在实例化(子)类时,您声明对象的“类型”是否有任何区别?
假设我有一个名为ParentClass
的类和一个名为ChildClass
的类
ParentClass
是抽象的, ChildClass
扩展了每个Java术语的ParentClass
。 此外, ParentClass
有一个构造函数,它将int
作为参数。 现在在另一个类中我想实例化ChildClass
。 我尝试了以下两种方式:
-
ChildClass obj1 = new ChildClass(5)
-
ParentClass obj2 = new ChildClass(5)
Java允许我使用上述两种方法中的任何一种。 我的问题是,实际上有什么区别吗? 如果我愿意,我可以互换使用吗?
两者都有效,并且都在内存中创建相同的对象。 但只有第一个允许您使用ChildClass其他特定的属性或ParentClass不知道的方法。
示例:
abstract class ParentClass{ ... } class ChildClass extends ParentClass { public void SomeChildMethod(){ ... } ... } ... ChildClass obj1 = new ChildClass(5); ParentClass obj2 = new ChildClass(5); obj1.SomeChildMethod(); // ok obj2.SomeChildMethod(); // compilation error ((ChildClass)obj2).SomeChildMethod(); // ok
因此,只有在您确定永远不需要特定的子方法或属性(如果有)时,才使用第二个实例化方法。
创建的对象实际上是相同的。
第一种方法允许您使用ChildClass
定义的方法而不是ParentClass
定义的方法。 所以
obj1.aMethodNotInParentClass();
编译时
obj2.aMethodNotInParentClass();
才不是。
或者,使用第二种forms允许您更容易地将内部类替换为其他实现。 如果要使用AnotherChildClass
而不是ChildClass
,
ParentClass obj2 = new AnotherChildClass(5);
是你需要做的所有改变(假设正确定义了类); 使用第一种方法可能需要在代码的其他位置进行一些更改。
根据经验,将变量定义为更通用的类,它定义(*)对象所需的所有方法。 因此,如果您使用未在ParentClass
定义的任何ChildClass
方法,请使用第一种方法,否则,使用第二种方法。
(*)请注意,我提到定义 ,而不是实现 。 如果覆盖ChildClass
的方法,则将使用该实现,因为创建的对象属于该类。
在内存中将使用完全相同的对象。 但是,您只能将变量obj2
用作包含ParentClass
对象的变量,而不会理所当然地认为您的ChildClass
类具有所有良好的function。 如果ChildClass
声明方法f()
,但ParentClass
没有,则调用obj2.f()
将不起作用 – 尽管内存中的对象可以完美地运行该方法。
- 如果他们有相同的方法只是孩子实现抽象方法,那么没有任何区别。
- 如果您添加了aditional方法,那么如果您将其声明为父级,则无法访问该子级。
第二种选择只允许使用ParentClass中声明的方法。 例如:
public class ParentClass { public void doX() {} } public class ChildClass { public void doY() {} public static void main() { ParentClass p = new ChildClass(); ChildClass c = new ChildClass(); p.doX(); //works c.doX(); //works p.doY(); //not allowed c.doY(); //works ((ChildClass) p).doY(); //this way you cast the object to ChilClass and can use its methods. } }
是,有一点不同。 第一种方法使用动态绑定将子实例作为父对象。 这仅为您提供父对象在子实例上的function。 第二种方法将为您提供子对象的实例作为子对象,允许您使用其所有方法及其父对象方法,而不是仅限于父类的方法。