抽象类"DocumentBuilderFactory"为什么可以实例化新实例?

5

最近,我一直在使用XML解析器。这只是我的开始,我已经理解如何在Java中使用DOM解析器类,即DocumentBuilderFactoryDocumentBuilder来解析XML文档。

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();  
DocumentBuilder db = dbf.newDocumentBuilder();            

我在思考的问题是,为什么像DocumentBuilderFactoryDocumentBuilder 这样的抽象类可以实例化新对象?另一个例子中,我看到:
Calendar calendar = Calendar.getInstance();  
System.out.println(calendar.get(Calendar.DATE)); 
  1. 据我所知,您不能为抽象和接口类实例化(换句话说,创建对象)。我正确吗?
  2. getInstance()newInstancce() 方法是否会创建上述抽象类的实例?

使用抽象类及其新对象方面是否有什么遗漏?

4个回答

9
那个方法是一个抽象工厂方法, 它返回DocumentBuilder子类, 这是一个(具体的)实现。
对象的确切类别并不重要,你只需要知道它是一个DocumentBuilder。该方法可以在运行时决定实例,也可以根据需要预先确定。
如果你好奇想知道,你可以像这样打印出实际的类:
 System.out.println(dbf.getClass());

请注意,方法newInstance()Class的同名方法不要混淆,即这两个方法是不同的:
 // a static method of this class
 DocumentBuilderFactory.newInstance(); 

// an instance method of Class
 DocumentBuilderFactory.class.newInstance();

一个不幸的名称选择,必定会引起混淆。

我在我的问题中添加了一点额外的内容。 - MKod
@Bohemian 只是好奇.. DocumentBuilderFactory类可以被视为抽象工厂,因为它公开了像newDocumentBuilder这样的方法来返回其他对象实例。但是DocumentBuilderFactory.newInstance()更多地是一个静态工厂方法。 - Dev Blanked
@DevBlanked,DocumentBuilderFactory.newInstance()不是一个抽象工厂方法,因为返回的类型DocumentBuilderFactory是一个抽象类。根据定义,如果返回的类型是接口或抽象类,则工厂方法是抽象的,这基本上意味着返回的实例必须是声明的返回类型的子类。 - Bohemian
@Bohemain,你能不能检查一下我的答案,它在底部。如果你完全不明白,请原谅我。我希望我把正确的概念记到了脑子里。 - MKod

3

这是一个静态的抽象工厂方法,它将返回DocumentBuilderFactory的子类型而不是DocumentBuilderFactory实例本身。它并不像我之前想象的那样,你明白吗:

DocumentBuilderFactory dbf = new DocumentBuilderFactory();

DocumentBuilderFactory#newInstance() , 获取一个新的 DocumentBuilderFactory 实例。这个静态方法会创建一个新的工厂实例。该方法使用以下有序查找过程来确定要加载的 DocumentBuilderFactory 实现类。

newInstance() 会返回一个实现了 DocumentBuilderFactory 的子类型的实例,并将该对象的引用赋值给 DocumentBuilderFactory 引用变量。


我理解您的意思是:假设代码为:DocumentBuilderFactory dbf = new DocumentBuilderFactory(); 当您说“它会返回一个子类型”时,我想知道子类型的类是什么。抱歉,我差不多到达目标了,但是细微之处超出了我的思考能力。 - MKod
我懂了,我已经查看了源代码。谢谢你的帮助。 - MKod
你能帮我检查一下我的答案吗?它在底部。如果你完全不明白,对不起。我希望我已经正确理解了概念。 - MKod

1
感谢大家,尝试了下面的代码后,我的疑惑得到了解决。

Calendar cls = Calendar.getInstance();
Date dt = new Date();
System.out.println(cls.getClass()); //<------ 1
DocumentBuilderFactory dbls = DocumentBuilderFactory.newInstance(); System.out.println(dbls.getClass()); //<------2
DocumentBuilder db = dbls.newDocumentBuilder();
System.out.println(db.getClass()); //<--------3

并且我看到了以下输出:
 ********Output******
   class java.util.GregorianCalendar
   class com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
   class com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl

a) 静态方法"DocumentBuilderFactory.newInstance()"返回名为"DocumentBuilderFactoryImpl"的子类型类实例。

b) "DocumentBuilderFactoryImpl"是抽象类"DocumentBuilderFacotory"的子类,因此如果我给出:

DocumentBuilderFacotryImpl dbls = DocumentBuilderFactory.newInstance();
//-----而不是给出DocumentBuilderFactory dbls = DocumentBuilderFactory.newInstance();

同样适用于DocumentBuilderImpl db = dbls.newDocumentBuilder();
//----而不是DocumentBuilder db = dbls.bewDocumentBuilder();

结论:newInstance(),newDocumentBuilder(),getInstance()返回子类对象。虽然抽象类不能创建新对象,但我们可以将子类对象分配给抽象类(即父类)引用变量。例如:

抽象类A{ }
class B extends A{ }

我们可以说:

 A a = new B();   

但不是

 A a = new A();

是的,我认为你已经想通了。 - Bohemian

1

这是一个静态方法。您可以在没有实例引用的情况下调用抽象类(或任何类)的静态方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接