Java多态的好处,定义、扩展都很方便。 比如下面的程序:interface A{ public void print(); }public class A1 implements A{ public void print(){ System.out.println("A1"); } }public class A2 implements A{ public void print(){ System.out.println("A2"); } }public class C{ public C(A a){//这里我需要用到print方法,那么就应该定义为父类类型,因为我只关系其共有属性,而不需要知道其子类的实现。} }
这是Effactive Java中说的,原因就是关注程序的扩展性。
能让你使用多态, 比如需要使用容器装东西,那我就可以使用 List l = new ArrayList();来声明一个容器, 但是项目里插入,删除操作比较多,那我可以不改其它代码 只需将声明语句改为List l = new LinkedList();就可以了
class Shape { public void draw() {} public void erase() {} public void show() { System.out.println("Shape.show()"); } }class Circle extends Shape { public void draw() { System.out.println("Circle.draw()"); } public void erase() { System.out.println("Circle.erase()"); } }class Square extends Shape { public void draw() { System.out.println("Square.draw()"); } public void erase() { System.out.println("Square.erase()"); } }class Triangle extends Shape { public void draw() { System.out.println("Triangle.draw()"); } public void erase() { System.out.println("Triangle.erase()"); } }class Shapes { public static void main(String[] args) { Shape[] s=new Shape[]{new Circle(),new Square(),new Triangle()}; for(int i=0;i<s.length;i++) s[i].erase(); for(Shape shp:s) shp.draw(); } }好处就是基类定义一个通用的接口,然后各生成类按各自的需求去扩展接口的内容。用基类指针引用可以实现统一管理,不用定义多个生成类子指指向各生成类。像例子中所有图形都有“清除”跟“绘图”功能,如果各个类各自定义再各自调用就比较麻烦,你只要定义一个基类包含这两个通用功能,各个类重载这两个方法,最后统一由基类指针调用就比较省事。
假设A类有很多子类A1,A2,A3... class Test{ public void test(){ A?a?=new A?(); //这里你需要用到一个A类的子类的对象,但是你不知道会用到哪个,而且要经常换,怎么办呢?你不能每次 //都要改一下这里吧,这时就可以考虑用父类的引用指想子类的对象,也就是向上转型的一种形式。
} }class Test{ public void test(Class xx){ A a=xx.newInstance();//这样你只需每次都传入一个A子类的Class对象就OK了,
} }class Test{ public static void test(A a){//也可以在这里直接接收一个A的对象
} public static void main(){ A? a=new A?(); test(a);//用的时候你可以传给它任意一个A的子类的对象它都可以识别,这样也是向上转型, }}
比如下面的程序:interface A{
public void print();
}public class A1 implements A{
public void print(){
System.out.println("A1");
}
}public class A2 implements A{
public void print(){
System.out.println("A2");
}
}public class C{
public C(A a){//这里我需要用到print方法,那么就应该定义为父类类型,因为我只关系其共有属性,而不需要知道其子类的实现。}
}
这是Effactive Java中说的,原因就是关注程序的扩展性。
比如需要使用容器装东西,那我就可以使用
List l = new ArrayList();来声明一个容器,
但是项目里插入,删除操作比较多,那我可以不改其它代码
只需将声明语句改为List l = new LinkedList();就可以了
class Shape {
public void draw() {}
public void erase() {}
public void show() {
System.out.println("Shape.show()");
}
}class Circle extends Shape {
public void draw() {
System.out.println("Circle.draw()");
}
public void erase() {
System.out.println("Circle.erase()");
}
}class Square extends Shape {
public void draw() {
System.out.println("Square.draw()");
}
public void erase() {
System.out.println("Square.erase()");
}
}class Triangle extends Shape {
public void draw() {
System.out.println("Triangle.draw()");
}
public void erase() {
System.out.println("Triangle.erase()");
}
}class Shapes {
public static void main(String[] args) {
Shape[] s=new Shape[]{new Circle(),new Square(),new Triangle()};
for(int i=0;i<s.length;i++)
s[i].erase();
for(Shape shp:s)
shp.draw();
}
}好处就是基类定义一个通用的接口,然后各生成类按各自的需求去扩展接口的内容。用基类指针引用可以实现统一管理,不用定义多个生成类子指指向各生成类。像例子中所有图形都有“清除”跟“绘图”功能,如果各个类各自定义再各自调用就比较麻烦,你只要定义一个基类包含这两个通用功能,各个类重载这两个方法,最后统一由基类指针调用就比较省事。
但是,这个工作具体应该如何做,则需要到更精确的类型才可以确定。比如“清洁工”是公司里的一个员工,他们的 doWork 方法就可以确定是打扫卫生;Sales 的 doWork 则是和客户谈生意等。
而在很多时候,我们要关注的是对象更加“泛”的类型,而不是更精确的类型。比如公司老板在招集员工开了一个短会之后,宣布散会,然后大家回去继续工作,也就是将用全体员工对象的 doWork 方法调用一次。在这里,老板在调用 doWork 方法时关注的是它的父类型,而不是子类类型,他没兴趣也没有必要去判断每个员工的子类型是什么。
这种思想在 jdk 的类库中多有体现。
比如 java.io.InputStream 类是一个抽象类,它的 read() 方法是一个抽象方法,它用于从输入流中读取一个字节的数据。
然而在 java 中,无论从网络还是从文件中读取数据都是用 Stream 类,显然文件和网络数据流的读取操作是不一样的。但是无论是网络还是文件,可以确定的是InputStream 一定会有一个 read() 方法用于从流中读取一个字节的操作。所以 InputStream 被定义成抽象类,read 方法被定义为抽象方法。read 方法是由它们的子类来完成的,文件的read方法由FileInputStream 类实现,网络输入流则是由 Socket.getInputStream 方法得到的 InputStream 的一个子类来对象来实现的。
class Test{ public void test(){
A?a?=new A?(); //这里你需要用到一个A类的子类的对象,但是你不知道会用到哪个,而且要经常换,怎么办呢?你不能每次
//都要改一下这里吧,这时就可以考虑用父类的引用指想子类的对象,也就是向上转型的一种形式。
}
}class Test{ public void test(Class xx){
A a=xx.newInstance();//这样你只需每次都传入一个A子类的Class对象就OK了,
}
}class Test{ public static void test(A a){//也可以在这里直接接收一个A的对象
}
public static void main(){
A? a=new A?();
test(a);//用的时候你可以传给它任意一个A的子类的对象它都可以识别,这样也是向上转型,
}}