一直以来我都不太明白为什么大家的代码中创建一个ArrayList对象都是用
List<A> temp = new ArrayList<A>();
所以今天来整理一下向上转型的。。实际效果!
首先看一段简单的代码:
public class test extends A {
public int a = 2;
public int getNum() {
return a;
}
public int getNew() {
return 3;
}
public static void main(String[] args) {
A temp = new test();
System.out.println(temp.a);
System.out.println(temp.getNum());
//System.out.println(temp.getNew());
}
}
class A{
public int a = 1;
public int getNum() {
return a;
}
}
输出结果为
1
2
结果很明显,调用相同名字的属性(变量)结果取决于引用类型,即A,当然由于封装的关系一般不会用到这一点。
而方法则要看引用的实际类型,即test。而如果把main中第四行的引用去掉,则会报错。我的理解是引用类型为父类时,只能调用父类中声明的方法,不过实际调用时会从引用变量的实际类型入手开始检查方法名,子类没有重写则检查父类直到找到方法为止,这就是Java特性中多态的方法多态。
那这有什么用呢?从上面的效果可以看出,因为正常情况下我们会对类进行封装,所以对属性的引用的特点我们无需管。所以使用场景多是运用方法多态。
abstract class A{
static int getNum(A temp) {
return temp.createNum();
}
protected abstract int createNum(){}
}
对于方法getNum(A temp),参数可以接收所有A的子类型去调用子类型中各自实现不同的的createNum()。
对上面的情况使用这一特性可以减少代码量,还有另外的使用场景是Java设计模式-装饰器模式和Java设计模式-策略模式,唔。。应该还有很多使用场景,后续看到会补充进来。
还有另外一种情况,当我们定义了
List<A> temp = new ArrayList<A>();
当我们不需要这个ArrayList而需要temp指向一个LinkedList时,可以直接
temp = new LinkedList<A>();
避免了再定义一个变量,节约了内存和分配空间的时间。
在上面的使用场景中向上转型增强了适应性,套路也大同小异;当然对于需要调用一些子类中特有的方法的场景,我们可以不使用向上转型或进行向下转型(强制类型转换)。