我怀疑这么久,所以最后在这里问。我举个例子。
class A{
void run(){
System.out.println("hi");
}
}
class B extends A{
void jump(){
}
}
public class test{
public static void main(String[] args){
A a = new A(); //statement 1
A a1= new B(); //statement 2
B b= (B) new A(); // statement 3
a.run();
b.run();
b.jump();
}};
现在我的基本疑问是statement1,2,3之间的区别是什么?请有人解释我。
答案 0 :(得分:9)
现在我的基本疑问是声明1,2,3之间的区别是什么?
A a = new A(); //statement 1
=
右侧的位创建了类A
的对象;左边的位定义了存储它的变量,在本例中是A
类型的变量; =
是一项任务。因此,这会创建一个类A
的对象,并将其引用保存在A
类型的变量中。
A a1= new B(); //statement 2
=
右侧的位创建了类B
的对象;左边的位定义了存储它的变量,在本例中是A
类型的变量; =
是一项任务。因此,这会创建类B
的对象,并将对它的引用保存在A
类型的变量中。这意味着当通过该变量访问对象时,您只能访问A
定义的内容,即使该对象是B
。例如,即使B
具有jump
方法,您也无法执行此操作:
a1.jump(); // Compile-time error
B b= (B) new A(); // statement 3
在运行时使用ClassCastException
会失败,因为您试图将A
存储在B
类型的变量中。您无法将A
个实例分配给B
个变量。如果实例与赋值兼容,则只能将实例分配给变量,这实际上意味着:
答案 1 :(得分:1)
TJ的答案非常好且冗长,只是为了补充你原来的问题。 '='的左侧是对右侧实际物体的引用。
这样想,左侧是“房子”的地址,而右侧是实际的“房子”。
在第三个声明中,你很确定房子'A' is a house 'B'
,然后试图施放它。编译器会信任你,但运行时控制可能会失败,如果你的假设不正确(这里,它看起来像在运行时,它将抛出ClassCastEsception)
另外,另一个区别是代码中的地址驻留在堆栈上,而右侧则驻留在内存的堆区域上。
答案 2 :(得分:1)
这里有两个问题混淆,变量或表达式的类型以及对象的类。
每个对象都有一个通过“new”或clone()创建的类。该类在对象的生命周期内是固定的。
引用变量或表达式为null或指向某个对象的指针。引用变量的类型由类或接口的名称指示。如果对象的类直接或间接地匹配或扩展该类,或者实现该接口,则它只能引用对象。实际上,变量的类型保证了对象具有相应的成员。
A a = new A(); //statement 1
声明一个带有类型A的变量“a”,这意味着它只能是null或指向A的指针,或者是一个类扩展为A的对象。将它初始化为指向新创建的A类对象的指针。
A a1= new B(); //statement 2
声明一个带有类型A的变量“a1”,这意味着它只能是null或指向A的指针,或者是一个类扩展为A的对象。用指向新创建的B的指针初始化它。由于B扩展了A,允许将B类表达式转换为A类。
B b= (B) new A(); // statement 3
这里的区别在于A不扩展B.当且仅当它是null或指向类B的对象的指针或扩展B的类时,类型A引用可以转换为类型B. A类不会扩展B.编译器会接受这个,因为强制转换声称“new A()”为null或引用了B类对象,或者是扩展B的类的对象。它将在运行时获得ClassCastException时间,因为这个说法是假的。
引用变量或表达式的类型在编译时确定。在程序运行过程中,它可能为null或引用几个不同类的对象,但只适用于其声明类型的类。
答案 3 :(得分:0)
我认为你需要更多地了解多态性,这是一个对象采用多种形式的能力。 看到: Java polymorphism creating a subclass object using its superclass variable 要么: http://en.wikipedia.org/wiki/Polymorphism_(computer_science)