对象类型声明

时间:2013-10-05 22:20:49

标签: java class inheritance

好的..所以, 当你有一个类的层次结构,如

public class A {...}

public class B extends A {...}

...创建对象时,有什么区别:

A object = new A();
A object = new B();
B object = new B();

感谢您的时间。

6 个答案:

答案 0 :(得分:2)

public class A
{
    public void methodA(){}
}
public class B extends A
{
    public void methodB(){}
}

我希望这能证明这一点。

A obj = new A();

a.methodA(); //works

A obj = new B();

obj.methodA(); //works
obj.methodB(); //doesn't work
((B)obj).methodB(); //works

B obj = new B();

obj.methodA(); //works
obj.methodB(); //works

答案 1 :(得分:2)

A object = new A();

您正在类型A的引用中创建A instance。您可以只访问方法/属性和父方法/属性。

A object = new B();

您正在A类型的引用中创建B instance。这样object可能会以多态方式运行,例如,如果您object.method()method是{在B中重写然后它将调用此覆盖方法。你必须注意不要破坏Liskov Substitution Principle。您可以只访问方法/属性和父方法/属性。当您只需要超类型合约时,这是首选方式。

B object = new B();

您正在B instance类型的引用变量中创建B。您可以只访问B方法/属性和父方法/属性。

答案 2 :(得分:1)

A object = new B();

这声明object将引用类A的对象或其任何子类(当它不是null时)。编译器会将其视为A类型的对象,因此您只能访问为A(或其中一个超类)声明的方法和字段。这也意味着您以后可以将它分配给类A或子类的任何其他对象:

A object1 = new B();
B object2 = new B();

// reassign later
object1 = new A();  // legal
object2 = new A();  // ILLEGAL

class C extends A { ... }
object1 = new C();  // legal
object2 = new C();  // ILLEGAL

因此,初始声明将object声明为类型A。但它的初始值是B类型的对象,这是正常的,因为BA的子类。

这应该解释你的第二个和第三个例子之间的区别。第一个和第二个之间的区别仅在于(在运行时)第一个创建类型为A的新对象,第二个创建类型为B的新对象。

答案 3 :(得分:1)

A object = new A();
类型为object

A(您可以访问A中的字段或方法)

A object = new B();
类型为object

A(您无法访问B中的字段或方法,仅来自A

B object = new B();
类型object

B(您可以访问AB中的字段或方法)

答案 4 :(得分:1)

A object1 = new A();
A object2 = new B();
B object3 = new B();

object1被声明为对A对象的引用。由于B类扩展了A类,因此可以将其设置为或(new A()new B()有效)。

object2被声明为对A对象的引用,但实际上是B对象。假设B类有一个名为eatFood()的方法。如果您尝试使用object2.eatFood()访问该方法,编译器将抛出错误,因为eatFood方法仅在B类中。尽管该对象实际上是一个B对象,但由于类型声明,编译器认为它是一个A对象。要访问eatFood方法,您必须对其进行类型转换:((B)object2).eatFood()

object3只是对B对象的引用,实际上是一个B对象。它可以访问A方法和B方法。

答案 5 :(得分:1)

这样的行
A var = new B();

是两个单独步骤的简写。

A var;         // (1) Make a variable of TYPE A.
var = new B(); // (2) Make an object of CLASS B, that from now on may be 
               // referred to by the variable var.

所以变量有一个TYPE,一个对象有一个CLASS。他们经常匹配。变量的类型实际上通常是一个类,尽管不一定。理解变量类型和变量引用的对象类之间的区别非常重要。

对象通常属于多个类。如果B类扩展了A类,那意味着B类的所有对象也是A类的对象。任何类的所有对象都是类Object的对象。换句话说,当我们说某个物体是B时,这比说它是A更具体。就像我们说Yogi是一样,这比说Yogi是一个< em> animal ,因为所有都是动物

因此,如果A是B扩展的类,则类型A的变量确实可以引用类B的对象。但是如果你有一个A类型的变量,就不能用它来做特定于B类对象的事情。例如,假设类A有一个名为display()的方法,而类B有一个名为explain()的方法。编译器允许您对类型A的变量调用display(),但不允许您调用explain()。如果确实如此,那么尝试在一个实际上不是B的对象上调用explain()会有失败的风险。

因此,只要有B类定义的方法,您就需要一个B类变量才能调用它们。当然,你也可以使用同一个变量来调用类A中定义的方法。从某种意义上说,如果类B扩展了类A,那么类型B的变量比类型A的变量更强大 - 你可以做更多的东西。

所以问题出现了 - 我为什么要写

A var = new B();

在此示例中,类型B的变量比var更强大吗?

简短的回答是它与查看代码的人进行通信。它说,“是的,我知道这个变量指的是B,但我实际上只打算使用A类提供的方法。这对于试图理解你的代码或维护它的人来说实际上是有帮助的。

在某些情况下,它可以对涉及该变量的方法调用产生真正的影响。假设还有另一个C类,它有两个名称相同但签名略有不同的方法,如下所示。

public class C {
    public void process(A arg){
        // Do some stuff
    }

    public void process(B arg){
        // Do some other stuff
    }
}

在这种特殊情况下,被调用的process版本取决于变量的类型,而不是对象的类。所以,如果你写

C processor = new C();
A var = new B();
processor.process(var);

这将调用process的第一个版本 - 签名中带有A的版本。因为变量的类型。但是如果你写的话

C processor = new C();
B var = new B();
processor.process(var);

这将调用process的第二个版本 - 签名中带有B的那个版本。