本人瞬间记忆综合症实在过于严重,经常头一天看懂记住的东西第二天就忘记,忘记后又重复头一天的学习过程,着实浪费时间。比如Java子类父类这种简单的东西,我已经记住、忘记、记住、忘记的循环了不知几个轮回了,为了节省时间,我觉得还是总结一下,加以记录比较好,去掉那些混淆我记忆的汤汤水水,只留干货。
继承的概念就不啰嗦了,直接说应用。
1、如果父类拥有自定义constructor,但并没有定义不带参constructor,那么子类也一定要自定义constructor,否则子类会报 Implicit super constructor SuperClass() is undefined for default constructor. Must define an explicit constructor(因为子类会自动调用父类的无参构造函数,但此函数又不存在,所以报错)。自定义构造函数的参数可与父类不同。
2、子类自定义构造函数的首行要显式的调用父类的某一构造函数进行初始化,如果不显式的调用,那么子类构造函数就会调用父类默认构造函数(即无参构造函数),此时如果父类没有无参构造函数,那么就会报 Implicit super constructor SuperClass() is undefined. Must explicitly invoke another constructor。
3、子类不能直接使用和读取父类的private数据,要通过父类提供的public access方法,即getter和setter。
4、如果子类重写了父类的某个method,那么此时子类要调用父类的方法就需要用super.someMethod()的形式调用,否则系统会报运行时错误 java.lang.StackOverflowError(因为系统反复调用的都是子类的重写方法,造成死循环)。
5、重写的意思是:返回值类型,方法名,参数类型和个数都要相同(返回值类型在SE5.0时也可以不同)。
6、子类重写父类的方法,子类方法不可降低父类方法的作用域,如:父类某方法的作用域是protected,那复写方法不可以是friendly和private,只能是protected或public。
7、可以将子类对象赋给父类型变量,即 SuperClass e = new SubClass(), 反之不可; 但编译器仍只认为e属于SuperClass类型,因此不能调用SubClass的特有成员和方法(即新增的方法,而不是重写的方法),但可以调用被重写了的方法,并且由于动态绑定,e所调用的方法将按照子类中的方法逻辑执行。
8、子类无法覆写父类的private方法,虽然编译可通过,但实际上覆写并未成功,而只是产生了一个新方法而已。见下面的代码:
class BaseClass {
private void g() {
System.out.println("BaseClass.g()");
}
}
class DeriveClass extends BaseClass {
public void g() {
System.out.println("DeriveClass.g()");
}
}
public class Test {
public static void main(String[] args) {
BaseClass p = new DeriveClass();
//p.g(); you can't call the method, because g() is not overriden but new added method.
}
}
9、如果想禁止某类被继承,那么可以将此类定义为final class,此时类中所有的方法都被自动置为final型;如果仅要禁止某方法被重写,可以只将方法定义为final。我们平时用到烂的String类就是final型的,所以为我们无法继承该类。
10、Java编程中,某类型的对象可以转化为另一种类型,这个转化过程叫转型(Casting)。这种转型可以发生在primitive型数据中,也可发生在对象中,当发生在对象上时就有一定的要求了:首先,互相转型的对象应该要有继承关系。因此像如下这种转型在编译时就是错误的:
Employee e = new Employee(); // Employee与Date没有任何关系
Date c = (Date) e;
转型有两种:向上转型和向下转型。
向上转型(Upcasting):先看下面的代码
class Instrument {
public void play() {}
public static void tune(Instrument i) {
i.play();
}
}
class Wind extends Instrument {
public static void main(String[] args) {
Wind flute = new Wind();
Instrument.tune(flute); //upcasting
}
}
这段代码中,Instrument类中的tune方法本来接受一个Instrument类型的引用,但是Wind.main()函数调用tune时,传入的却是Wind类型引用,编译器依旧可以接受,这中间显然发生了一种转换,即“将子类引用转换为父类引用”的转换,这种转换就叫“向上转型”。因为当我们在做向上转型时,是将一种特殊型别转换为通用型别,对class接口产生的唯一效应是“减少”而不是“新增”方法,因此我们认为“向上转型”是安全的,无需特殊声明就可进行。举个例子,一个富豪想自愿变成一个普通人显然“安全”,但反之,一个普通人想一下子拥有富豪的特权,那没那么容易,要经过资格审核了……。
上面那个需要审核的就是“向下转型”(downcasting),即父类到子类的转换。还是先看代码:
Instrument gitar = new Instrument();
Instrument flute = new Wind();
Instrument i = flute; // compiling error, Type mismatch: cannot convert from SuperClass to SubClass
Instrument i = (Wind)flute; // pass
Instrument i = (Wind)gitar ; // runtime error, ClassCastException
由上面这个例子,我们可以看出,Java编译器和虚拟机对于“向下转型”的审核还是很严格的,不光要增加"(SubClassName)"的标记,还要保证被转型的父类引用确实“有资格”转型。也就是说只有被指定指向了子类的父类引用才可以被转型成子类,像上例中的flute引用,而gitar引用显然不符合。也可以用"instanceof"来判断一个对象引用是否克被转型成目标类型。
我们在实际项目应用中,“向上转型”和“向下转型”应用都很广泛,以Collection到List的转型居多。
11、抽象类不能实例化,但可以用来定义一个变量,但是变量要指向继承它的一个非抽象子类实例。