Head First Java学习:第八章-接口和抽象类
第八章:接口和抽象类
深入多态
1、抽象类:有些类不应该被初始化
在类声明前面加上抽象类的关键字,abstract。
- 防止类被初始化,即不能被“new”创建该类的实例(要求)
- 还是可以用这种抽象的类型作为引用类型,给多态使用(目的)
abstract class Canine extends Animal{
public void roam(){}
}
2、编译器不会让你初始化抽象类
编译的时候就会报错。抽象类除了被继承之外,是没有用途,没有值,没有目的。
3、抽象的方法
- 抽象的方法没有实体:
public abstract void eat();
- 如果申明一个抽象的方法,必须将类也标记为抽象。不能在非抽象类中拥有抽象方法
为什么要有抽象的方法?
将可以继承的方法体放到父类中。但有时就是没有办法作出给任何子类有意义的共同程序代码。抽象方法的意义就算无法实现出方法的内容,但还是可以定义出一组子型共同的协议。
抽象的方法有什么好处?
答:可以使用多态!你想达成的目标是要使用父型作为方法的参数、返回类型或数组的类型。通过这个机制,你可以加入新的子型到程序中,却不必重写或修改处理这些类型的程序。
- 必须实现所有抽象的方法
实现抽象的方法就如同覆盖过方法一样。
抽象的方法没有内容,它只是为了标记出多态而存在。这表示在继承树结构下的第一个具体类,必须要实现出所有的抽象方法。
可以通过抽象机制将实现的负担转给下层。
4、多态的使用
自行描写维护list的类,以保存Dog对象。
如果要写出给Cat 用的:
5、所有的类都继承自:Object类
Object类的常用方法:
- equals(Object o) 比较两个对象是否“相等”
- hashCode() 列出词对象的哈希代码,可以想像成唯一id
- getClass() 告诉你此对象是从哪里被初始化的
- toString() 列出类的名称和对象在堆中存放的地址
数字是对象在堆中存放的地址。
6、使用Object类型的多态引用是会付出代价的
任何从 ArrayList<Object> 取出来的东西都会被当作 Object类型的引用,而不管原来放进去是什么。
编译器是根据引用类型来判断有哪些method 可以调用。
o.hashCode();
o 被声明为Object的引用,所以只能通过o调用Object类中的方法。
7、探索内部Object
对象会带有从父类继承下来的所有东西。这代表每个对象,不论实际类型,也会是个Object的实例。所以java中的每个对象除了真正的类型外,也可以当作是Object 来处理。当你执行new Snowboard() 命令时,除了在堆上会有一个Snowboard对象外,此对象也包含了一个Object在里面。
- 把对象装进 ArrayList<Object> 时,不管它原来是什么,只能把它当作 Object
- 从ArrayList<Object> 取引用,引用的类型只会是object。
8、如何转换回原来的类型:强制转换
Object o = al.get(index);
Dog d = (Dog) o;
d.roam();
检查是否是 Dog类型,使用:instanceof
如果类型错误,执行期间会报 ClassCastException。
9、多重继承的问题
导致“致命方块”问题。
10、接口:interface
所以的接口方法都是抽象的
接口的定义:public interface Pet {…}
接口的实现:public class Dog extends Canine implements Pet {…}
设计和实现Pet接口:
public interface Pet {
// 接口的方法一定是抽象的,所以必须以分号结束
public abstract void beFriendly();
public abstract void play();
}
public class DogNew extends Animal implements Pet{
public void beFriendly(){
// 必须实现出Pet的方法
}
public void play(){
// 必须实现出Pet的方法}
}
}
使用接口你就可以继承超过一个以上的来源。
类可以 extend 过某个父类,并且实现其他接口,同时其他的类也可以实现同一个接口。
如果使用接口来编写程序,你就会说,不管你来自哪里,别人就会知道你一定会履行这个合约。
11、不同继承树的类也可以实现相同的接口
对于这棵继承树,定义为 Canine 类型的参数可以接受 Wolf和Dog,但是无法忍受 Cat 或 Hippo。
但当你用接口来作为多态类型时,对象就可以来自任何地方了,唯一的条件就是该对象必须是来自有实现此接口的类。
类可以实现多个接口。
12、在子类中调用父类的方法:super
可以做在父类中设计出所有子类都使用的功能实现,让子类可以不用完全覆盖掉父类的功能,只是再加上额外的行为,可以通过 super这个关键字取用父类。
abstract class Report {
// 父类的方法,子类可以运行
void runReport(){
// 设置报告
}
void printReport(){
// 输出
}
}
public class BuzzwordsReport extends Report{
void runReport(){
// 调用父类的方法
super.runReport();
buzzwordCompliance();
printReport();
}
void buzzwordCompliance(){
//...
}
}
执行super.runReport();
对子类的对象调用会去执行子类覆盖过的方法,但在子类中可以去调用父类的方法。
12、总结
- 不想让某个类被初始化:abstract标记为抽象的
- 抽象类 = 抽象方法+非抽象方法+实例变量
- 抽象方法没有内容,它的声明是以分号结束
- 抽象的方法必须在具体的类中运用
- Java所有的类都是 Object(lang.Object)直接或间接的子类
- 方法可以申明Object的参数或返回类型。
- 不管实际上所引用的对象时什么类型,只有在引用变量的类型就是带有某方法的类型时才能调用该方法。
- Object引用变量在没有类型转换的情况下不能赋值给其他的类型,若堆上的对象类型与所要转换的类型不兼容,则此转换回在执行期间产生异常。
- 从ArrayList<Object> 取出的对象只能被Object 引用,不然就要用类型转换来改变。
- java不允许多重继承,因为那样会有致命方块的问题。
- 接口就是 100% 纯天然抽象类。
- 以interface 这个关键字取代class 来声明接口。
- 实现接口时要使用 implements 这个关键词
- class 可以实现多个接口
- 实现某接口的类必须实现它所有的方法,因为这些方法都是 public 与 abstract的。
- 要从子类调用父类的方法,可以用 super这个关键词来引用。