继承的好处:
1.提高了代码的复用性.(源代码级别的;) ------> 当发现两个类有大量相同代码时,可考虑向上提取,使用继承,增加代码复用; 1.1 功能的积累,其实也是一种代码的复用 ------>当发现新功能在原有功能基础上增强时,可考虑使用继承,增加代码复用;
2.让类与类之间产生了关系,给第三个特征多态提供了前提,没有继承就没有多态(暂不考虑接口时) ----->使用继承,进而使用多态时;
3.特点:子类继承了父类,在子类的每个对象中划分了两块内存区域,一块是放了父类的堆中成员(因为这个时候并没有产生父类对象,所以我们不说 父类对象的成员 ),一块是放了子类对象本身的堆中成员.
子类对象地址是:0x0045 在堆内存中子类对象被分成了两份空间:
Zi空间 (this持有引用),
Fi空间 (super持有引用),
堆内存:
_________________________________
0x0045 | new Zi() : |
| ____________ ____________ |
| | | | | |
| | | | | |
| | Zi空间 | | Fu空间 | |
| | | | | |
| | | | | |
| |____________| |___________ _| |
|____________________________ ____|
问题:
1,创建子类对象时,子类构造会默认调用父类空参构造,此时是否创建了父类对象(已知每一个子类对象继承的父类字段都是惟一的)?
答: 没有.
因为子类继承父类之后,在创建子类对象时,虽然在子类构造中会默认调用父类空参构造,但此时不会创建父类对象,只是会把父类成员打包一份放在子类对象所在内存区域,并用super做标记.这样子类就可以通过super访问父 类中非私有的成员,但其实这些成员封装在子类对象中,并没有单独创建父类对象.
从代码的抽取性这个意义上来说:
继承的抽取性是 :源代码级别的;
也就是说继承只是让我们在写源代码时减少了相同代码的书写,而在内存中可以说是并没有减少内存的占用,(甚至说相反可能会增加内存的占用),因为子类对象中本来该有的,都会通过从父类获取,最终保存在子类在堆内存所开辟的空间内;
static 的抽取性是 :内存级别的;
也就是说静态修饰,并没有改变我们源代码书写量,但是在内存上却将原来在堆内存中大量重复的部分,进行抽取,只保留一份放在方法区中的静态区,供所有对象共享,减少了内存空间不必要的消耗.
java中支持单继承,不直接支持多继承,但对c++中的多继承机制进行了改良.
问题:
1.java中不直接支持多继承的原因是什么?
答:举个例子来说:如果[ class C extends A,B ] 当A ,B 有声明完全一样的方法时,C中又没有重写
(覆盖)该方法,当C 的对象调用该方法时,它不知道到底应该调用 A类中的还是 B类中的方法,此时会产生调用的不确定性,所以java中为了避免这种不确定性,不直接支持多继承; ps:但是java对c++中的多继承机制进行了改良: 通过定义接口,而接口可以多实现,也可以多继承(变相做到了多继承),并且接口要求子类必须 重写(覆盖)其所有方法,所以在子类调用方法时,即便是父类接口中有声明完全一样的方法,子类调用时,实际调用的是子类中的方法,就不会出现调用的不确定性.
2.子类继承父类时,子类对象调用父类方法时,父类的方法都只局限于操作父类的数据;而我们随便定义一个类,创建子类对象调用了toString()方法时,这个方法返回了子类对象本身的地址值,也就是说父类(Object)的方法操作到了子类对象自身的数据,这个是如何做到的?
答:这个其实是错觉:我们首先看object中tostring:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
其实是toString()里边的以下两个方法在作怪:
public final native Class<?> getClass();
public native int hashCode();
它们都被native修饰,都是本地方法,调用了底层的一些方法,所以它可以获得所有东西也就不奇怪了.
1.提高了代码的复用性.(源代码级别的;) ------> 当发现两个类有大量相同代码时,可考虑向上提取,使用继承,增加代码复用; 1.1 功能的积累,其实也是一种代码的复用 ------>当发现新功能在原有功能基础上增强时,可考虑使用继承,增加代码复用;
2.让类与类之间产生了关系,给第三个特征多态提供了前提,没有继承就没有多态(暂不考虑接口时) ----->使用继承,进而使用多态时;
3.特点:子类继承了父类,在子类的每个对象中划分了两块内存区域,一块是放了父类的堆中成员(因为这个时候并没有产生父类对象,所以我们不说 父类对象的成员 ),一块是放了子类对象本身的堆中成员.
子类对象地址是:0x0045 在堆内存中子类对象被分成了两份空间:
Zi空间 (this持有引用),
Fi空间 (super持有引用),
堆内存:
_________________________________
0x0045 | new Zi() : |
| ____________ ____________ |
| | | | | |
| | | | | |
| | Zi空间 | | Fu空间 | |
| | | | | |
| | | | | |
| |____________| |___________ _| |
|____________________________ ____|
问题:
1,创建子类对象时,子类构造会默认调用父类空参构造,此时是否创建了父类对象(已知每一个子类对象继承的父类字段都是惟一的)?
答: 没有.
因为子类继承父类之后,在创建子类对象时,虽然在子类构造中会默认调用父类空参构造,但此时不会创建父类对象,只是会把父类成员打包一份放在子类对象所在内存区域,并用super做标记.这样子类就可以通过super访问父 类中非私有的成员,但其实这些成员封装在子类对象中,并没有单独创建父类对象.
从代码的抽取性这个意义上来说:
继承的抽取性是 :源代码级别的;
也就是说继承只是让我们在写源代码时减少了相同代码的书写,而在内存中可以说是并没有减少内存的占用,(甚至说相反可能会增加内存的占用),因为子类对象中本来该有的,都会通过从父类获取,最终保存在子类在堆内存所开辟的空间内;
static 的抽取性是 :内存级别的;
也就是说静态修饰,并没有改变我们源代码书写量,但是在内存上却将原来在堆内存中大量重复的部分,进行抽取,只保留一份放在方法区中的静态区,供所有对象共享,减少了内存空间不必要的消耗.
java中支持单继承,不直接支持多继承,但对c++中的多继承机制进行了改良.
问题:
1.java中不直接支持多继承的原因是什么?
答:举个例子来说:如果[ class C extends A,B ] 当A ,B 有声明完全一样的方法时,C中又没有重写
(覆盖)该方法,当C 的对象调用该方法时,它不知道到底应该调用 A类中的还是 B类中的方法,此时会产生调用的不确定性,所以java中为了避免这种不确定性,不直接支持多继承; ps:但是java对c++中的多继承机制进行了改良: 通过定义接口,而接口可以多实现,也可以多继承(变相做到了多继承),并且接口要求子类必须 重写(覆盖)其所有方法,所以在子类调用方法时,即便是父类接口中有声明完全一样的方法,子类调用时,实际调用的是子类中的方法,就不会出现调用的不确定性.
2.子类继承父类时,子类对象调用父类方法时,父类的方法都只局限于操作父类的数据;而我们随便定义一个类,创建子类对象调用了toString()方法时,这个方法返回了子类对象本身的地址值,也就是说父类(Object)的方法操作到了子类对象自身的数据,这个是如何做到的?
答:这个其实是错觉:我们首先看object中tostring:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
其实是toString()里边的以下两个方法在作怪:
public final native Class<?> getClass();
public native int hashCode();
它们都被native修饰,都是本地方法,调用了底层的一些方法,所以它可以获得所有东西也就不奇怪了.