转型
转型依据数据类型分为两种,一种是基本数据类型上的转型,一种是引用数据类型的转型
1 基本数据类型依据
byte/char ——> int ——> long ——> float ——> double
的顺序可以自动向上转型,反之向下强制转型(由于窄化转型仅仅是丢弃最低位N个字节的内容,可能会发生精度丢失)
2 引用数据类型:数组 和 对象
其中 数组具有协变性数组的协变性
我们这里主要面向引用类型。。。。
向上转型
引用类型向上转型到父类(extends)以及实现的接口(implements)
向上转型是安全的,不需要强制转换
因为符合子类的对象一定符合父类
String[] s1 = new String[]{"111"};
Object[] obj1 = s1;//不需要强转
Object[] s1 = new String[]{"123"};//向上转型定义,父类引用指向子类对象
引用类型向上转型到父类(extends)以及实现的接口(implements),其中优先级父类大于接口,当没有父类时可以转换成接口,在接口之间优先级相同(如果出现他实现的多个接口,引用类型会因为向上转型模糊而拒绝编译),故在不能出现参数列表仅仅是两个同等级的接口不同的重载方法
以重载为例
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
//ArrayList实现List、Serializable接口
public class Test {
private static void println(int a, AbstractList obj){
System.out.println("AbstractList");
}
private static void println(int a,List list){
System.out.println("List");
}
private static void println(int a, Serializable serializable){
System.out.println("serializable");
}
public static void main(String[] args) {
println(1,new ArrayList());
}
}
//此时编译不通过,编译器提示两个方法都匹配不能指定
//注意这里,即便优先级应该是给父类,但是方法中只要是有两个接口,他就没有办法排列优先级,就无法编译
当然向上转型还可以转换成父类的父类,父类的接口等等。。当然优先级就会减弱
向下转型
向下转型是不安全的,因为不能保证存放在父类中的都是要转换的子类
除了要求强制转换
还有:
1 定义声明时要指向父类引用指向的是子类的实例对象(以保证转换时类型安全),也就是说在向下转型前必须先向上转型
2 只能转换成要转换的子类(自己的实际类型),不能转成其他的,也就是说Object声明时引用的是String实例就不能向下转型成Integer(这点十分重要,所以向下转型只能转成自己的实际类型,转型的范围是固定的)
Object[] obj2 = new Object[]{"123"};
String[] s2 = (String[])obj2;
//报异常 [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
//正确用法
Object[] obj3 = new String[]{"1223"};//先向上转型
String[] s3 = (String[]) obj3;//再强制向下转型
那么转型带给我们有什么优势嘞
向上转型
上下转型中要注意到一点:
向上转型中会忘记对象类型
也就说子类中单独定义而父类中没有的方法将无法访问,子类重写的方法也无法调用,可以调用的只有父类自己的方法
使用场景:
例如目前有父类Object 子类String Integer
现在有一个方法function,要求传入参数Object的子类们
在普通情况下我们需要定义两个方法,一个传String 一个传Integer
public void function(String s){}
public void function(Integer i){}
我们访问时也是
function(new String());
function(new Integer());
如果使用向上转型,我们在定义这个方法的时候使用父类作为参数类型
public void function(Object o);
访问时,因为向上转型是自动非强制的,我们都不需要做其他的操作,直接调用就可
向上转型在Java中运用超级多,源码中Object o方法一大堆
向上转型可以节省大量代码
function(new String());
function(new Integer());
向下转型
上面说过了,向下转型之前必须先要向上转型,那这样的话为什么还要向下转型
向下转型重点在于调用子类自己的方法
使用场景:
既然我们说向下转型前必须先向上转型,那就是说向下转型是为了能更好地服务向上转型的,不会有单独只为了使用向下转型而使用的情况(要不我为啥不用自己的实例)
So,在使用向上转型的时候,子类丧失了自己的类型,然而我们还需要调用子类中自己的方法,怎么办呢,yeah 向下转型
这里就不举例子了,还蛮好理解的