这是在实例化父类还是子类?
请问,下面这句话是什么意思呢?
SuperA p = new SubB();
(其中,SubB是SuperA的子类)
1.等号定义成父类的类型,右边是子类的构造方法,那实例化出来的是子类还是父类啊?
2.这句话应该也是从右边执行到左边的吧,那它的实际内部执行过程是怎样的?比如分配内存空间什么的。
3.这句话执行的过程中会什么时候调用父类的构造函数啊,调用几次?
4.这与左右边都是子类的情况有什么不同吗?
[解决办法]
如果你要搞清楚这个问题首先你要搞清楚三个个问题:
第一、编译时与运行时的区别。
第二、深刻理解面向对象的原理与思想,也就是类与对象的联系与区别。
第三、理解什么引用什么是数据。
在你能够搞清楚这三个问题之前恐怕你不那么好理解上面那句多态的语句到底是干了什么。
不过我现在绕过那三个问题吧答案告诉,至于为什么你搞清楚那三个问题就都明白了:
1、实例化出来的是子类而不是父类。
2、赋值操作符都是从右往左执行,这句话代表想内存申请空间存放对象并执行构造函数。
3、执行构造函数的第一句话就是执行父类的构造函数(也就是立即执行父类构造函数),如果父类不是java.lang.Object对象,那么就继续往上执行父类构造函数,直到java.lang.Object。
4、如果左边是父类引用,那么只能调用对象在父类中声明的方法和属性,如果左边是本类引用,则可以调用所有的方法和属性。
[解决办法]
多态.. 父类引用指向子类对象. 这句话记住..都懂了.
[解决办法]
这么作的 会使子类变窄 就是 子类中有的方法而父类中没有的方法
在这个以父类引用变量作为引用的子类对象不能在调用其子类有而父类中没有的方法了
public class A {
public static void main(String[] args){
C c=new B();
c.abc();
c.abcd();//会报错找不到此方法
}
}
class B extends C{
void abc(){
System.out.println("d");
}
void abcd(){
System.out.println("dsfdsf");
}
}
class C{
void abc(){
System.out.println("SDFSDFSD");
}
}
[解决办法]
这就是面向对象的多态性之一。在C++中是父类的对象调用子类的方法,在java中等号左边实际上就相当于一个指针,其实是在栈中分配的一个名称,它储存对象的地址,储存拿过对象的地址呢?也就是储存new出来的对象,即等号右边的。只要是new出的东西,一定是在堆里分配的内存
[解决办法]
SuperA p = new SubB(); 是从右到左执行的。首先分析new SubB(),执行new SubB()是调用子类SubB的默认构造方法,即public SubB(){},事实上子类的
构造方法是这样的:public SubB(){
SubA() {};
}
子类构造方法里面父类的构造方法是编译器加上的,不需要自己写出来。所以调用子类构造方法时也会调用父类构造方法,且只调用一次,
调用完父类构造方法后再执行子类构造方法剩下的代码,这样就在内存中创建了一个子类对象,里面包含了一个父类对象;
然后用父类类型的引用p去持有这个创建出来的子类对象。通过引用p只能访问子类中从父类中继承的属性和方法,而子类中新增的属性和方法不能
通过引用p去访问,如果引用p是子类类型的,那么通过p可以访问所有子类中的属性和方法。
[解决办法]
是父类引用指向子类对象,会产生多态,其实就创建了一个对象,subperB的对象
父类引用(superA)指向了他。如果你等号两边都是子类类型,则不会产生多态,
当然,你创建的仍然是一个对象,都是在堆中创建的对象
[解决办法]
[解决办法]
3.这句话执行的过程中会什么时候调用父类的构造函数啊,调用几次?
个人觉得并没有调用父类的构造函数,而是子类的默认构造函数覆盖了父类的默认函数