Java中类可以从其他类中派生出来(be derived from),也就是继承机制
除了Object,每个类都有一个也只有一个直接父类,不指定就是默认Object的子类
子类将继承父类的所有成员,除了不让继承的
构造并不是类的成员,因此不能继承,但子类构造中可以用super(..)调用父类构造
内部类是可以访问外部类的private字段的,所以如果内部类被子类继承了的话,父类的private字段也被间接访问
MountainBike myBike = (MountainBike)obj;
这个显式转换实际上是在运行时才能检测出错误,编译时总是假设正确
如果提前加个
if (obj instanceof MountainBike) {
能让运行时不要报错
一个对象可以有很多类型,是通过接口来体现
如果声明一个变量为接口类型,那么赋值的可以是某个实现类的对象,他们的的确确是同一类型
类与接口的一个区别就是类中可以有字段,而接口只能有常量
如果类之间允许多重继承,都继承了同名的成员后将会引起混乱
类只能继承一个类,而可以实现多个接口
子类可以覆盖父类方法,这个意义在于,子类只需寻找类似的父类就行了,然后改改就能用,对父类的要求并不严格
覆盖的方法修饰符可以更宽
试图把父类的实例方法覆盖成static或反过来,会编译报错
实例方法跟父类实例方法同名,叫覆盖
static方法跟父类static方法同名,叫隐藏(hiding)
子类字段跟父类字段同名,也会隐藏 //不推荐这样
到底调用的是哪个方法要看声明的类名(类型)
接口中的abstract方法和default方法都是非static的,也就是实例方法,他们可以被子接口覆盖
接口的static方法是不会被继承的
super也可以用来调用实现的接口里的default方法,是最直接的上层
一个英文,polymorphism(多态)
如果父类和多个接口中有同样签名的方法?子类如何区分他们呢?这里有几个规则:
1.实例方法优先于接口的default方法
public class Horse { public String identifyMyself() { return "I am a horse."; } }
public interface Flyer { default public String identifyMyself() { return "I am able to fly."; } }
public interface Mythical { default public String identifyMyself() { return "I am a mythical creature."; } }
public class Pegasus extends Horse implements Flyer, Mythical { public static void main(String... args) { Pegasus myApp = new Pegasus(); System.out.println(myApp.identifyMyself()); } }
会显示I am a horse.
是继承来的实例方法
2.已经被覆盖过的方法会被忽略
public interface Animal { default public String identifyMyself() { return "I am an animal."; } }
public interface EggLayer extends Animal { default public String identifyMyself() { return "I am able to lay eggs."; } }
public interface FireBreather extends Animal { }
public class Dragon implements EggLayer, FireBreather { public static void main (String... args) { Dragon myApp = new Dragon(); System.out.println(myApp.identifyMyself()); } }
会显示I am able to lay eggs.
是新方法
3.子类继承来的方法,可以用来会实现接口的方法
public interface Mammal { String identifyMyself(); }
public class Horse { public String identifyMyself() { return "I am a horse."; } }
public class Mustang extends Horse implements Mammal { public static void main(String... args) { Mustang myApp = new Mustang(); System.out.println(myApp.identifyMyself()); } }
将显示I am a horse
4.无关的多个default方法重名,或跟某个abstract方法重名,会编译报错
Object的方法:
如果一个类或某个父类,实现了Cloneable
接口,就可以调用.clone()方法,生成一个拷贝的对象
默认的clone()实现只是复制了一个地址,所指向的依然是同一个对象,所以通常是需要覆盖的
而默认的equals()
也只是比较两个对象是否==,所以通常是需要覆盖的
public boolean equals(Object obj) { if (obj instanceof Book) return ISBN.equals((Book)obj.getISBN()); else return false; }//一个覆盖的例子,要手动比较内部成员
如果覆盖equals(),也必须覆盖hashCode(),默认返回对象内存地址的hex值
finalize()
默认什么都不做,要覆盖成一些收尾动作,当然不要指望那会执行
getClass()
方法是不能覆盖的,它返回一个java.lang.Class类的对象,可以得到很多信息
toString()
通常是需要覆盖的
构造方法里所调用的方法通常要定义为final,不让继承的子类修改,保证构造的确定性
一个类定义为final,是不能继承的
一个类定义为abstract,就是抽象类,可能有abstract方法,也可能没有
抽象类不能实例化,可以被继承
抽象方法没有方法体,包含抽象方法的类必须声明为abstract
抽象类当然可以有静态字段和静态方法
抽象类的子类也要实现父类的接口中的方法
抽象类使用情形:
1.想在多个有关联的类间共享一些东西
2.通过父类中声明,想让多个子类都拥有很多共同的字段和方法,或者非public的成员
3.想定义非static或非final的字段,可以声明某个方法改变他们
接口的使用情形:
1.想让多个无关联的类共享一些东西
2.想声明某个方法,却不关心怎么实现
3.想多重继承