Java数组类型转换
2016-06-23 21:57
656 查看
在做项目的过程中,遇到一个很奇怪的问题。为了说明清楚,先举个栗子:
咋一看,会觉得上面的代码没有问题。实际情况是代码(1)处是没有问题的,而(2)处会发生ClassCastException;list明明泛型中指定了里面参数的类型,为何还是会发生类型转换的错误?我们知道Java泛型只是编译器有效,运行期泛型是要被擦除的。
其实这个问题解释起来也不复杂,我们知道Java一切皆对象,那么数组也必然为数组对象了。我们加些打印语句:
看看运行效果
看见没有a2与list.toArray()根本不是一种类型。运行时list.toArray()对象也不是Integer[]类型的实例。为了验证该说话继续添加代码:
现在在设计一个小实验,我们修改类型转化之后的数组:
我们知道BigDecimal和Integer类已经没有半毛钱的关系了,(3)运行成功,(4)抛出异常。说明list.toArray()之后,该数组可以存放任何对象均是合法的,所以将这样的数组对象转型为Integer[]合法的话那Java类型转化就乱套了。
现在想想为何list.toArray(T[])为何能运行成功?
看下ArrayList.java源码:
Debug运行看下效果:
换了角度理解我们知道,list.toArray(T[])参数带有泛型,就算我们自己可以轻易实现列表向数组转换。我们在看看list.toArray()在Debug模式下运行效果:
虽然这里的泛型类型已经丢了,数组中存储的对象类型没有问题,但是返回的数组泛型已经丢了。
数组对象继续思考:
1.Integer[] 类型的数组对象是否也是Object[]的实例?
2. 声明Object[]类型的数组对象,运行期间一定为Object[]类型吗?若声明之后直接全部实例化为StringBuilder对象呢?
如:
从中我们可以得出下面的结论:
1.数组类型也存在子父类(或接口)之间关系
2.变量声明并不能决定其最终类型。
3.数组初始化{}本身不具备类型。
public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(2); Integer[] a1 = list.toArray(new Integer[list.size()]);//(1) Integer[] a2 = (Integer[]) list.toArray();//(2) }
咋一看,会觉得上面的代码没有问题。实际情况是代码(1)处是没有问题的,而(2)处会发生ClassCastException;list明明泛型中指定了里面参数的类型,为何还是会发生类型转换的错误?我们知道Java泛型只是编译器有效,运行期泛型是要被擦除的。
其实这个问题解释起来也不复杂,我们知道Java一切皆对象,那么数组也必然为数组对象了。我们加些打印语句:
public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(2); Integer[] a1 = new Integer[1];//(1) Integer[] a2 = new Integer[1]; System.out.println("a1对象类型: " + a1.getClass()); System.out.println("a2对象类型: " + a2.getClass()); System.out.println("list.toArray(new Integer[list.size()])对象类型: " + list.toArray(new Integer[list.size()]).getClass()); System.out.println("list.toArray()对象类型: " + list.toArray().getClass()); a1 = list.toArray(new Integer[list.size()]); a2 = (Integer[]) list.toArray();//(2) }
看看运行效果
看见没有a2与list.toArray()根本不是一种类型。运行时list.toArray()对象也不是Integer[]类型的实例。为了验证该说话继续添加代码:
System.out.println(list.toArray() instanceof Integer[]);输出结果为false.
现在在设计一个小实验,我们修改类型转化之后的数组:
public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(1); Object[] a1 = list.toArray();//(1) Object[] a2 = list.toArray(new Integer[list.size()]);//(2) System.out.println("a1对象类型" + a1.getClass()); System.out.println("a2对象类型" + a2.getClass()); //修改元素 a1[0] = new BigDecimal(5);//(3) a2[0] = new BigDecimal(5);//(4) }运行结果
我们知道BigDecimal和Integer类已经没有半毛钱的关系了,(3)运行成功,(4)抛出异常。说明list.toArray()之后,该数组可以存放任何对象均是合法的,所以将这样的数组对象转型为Integer[]合法的话那Java类型转化就乱套了。
现在想想为何list.toArray(T[])为何能运行成功?
看下ArrayList.java源码:
@SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; }起作用的为 System.arraycopy(elementData, 0, a, 0, size),这里直接返回的数组对象a是带有泛型的;这其实为native方法,和 Java无关了!
Debug运行看下效果:
换了角度理解我们知道,list.toArray(T[])参数带有泛型,就算我们自己可以轻易实现列表向数组转换。我们在看看list.toArray()在Debug模式下运行效果:
虽然这里的泛型类型已经丢了,数组中存储的对象类型没有问题,但是返回的数组泛型已经丢了。
数组对象继续思考:
1.Integer[] 类型的数组对象是否也是Object[]的实例?
2. 声明Object[]类型的数组对象,运行期间一定为Object[]类型吗?若声明之后直接全部实例化为StringBuilder对象呢?
如:
public static void main(String[] args) { Integer[] a1 = new Integer[1]; System.out.println("a1 instanceof Integer[]:\t" + (a1 instanceof Integer[])); System.out.println("a1 instanceof Object[]:\t"+ (a1 instanceof Object[])); Object[] a2 = {new StringBuilder("abc"),new StringBuilder("bcd")};//只是实例化,并不返回类型 //System.out.println({new StringBuilder("abc"),new StringBuilder("bcd")});//语法错误 System.out.println(a2.getClass()); Object[] a3 = a1; System.out.println(a3.getClass()); Class c1 = Integer[].class; Class c2 = Object[].class; System.out.println("Integer[]是否为Object[]子类型:" + c2.isAssignableFrom(c1)); }运行结果为:
从中我们可以得出下面的结论:
1.数组类型也存在子父类(或接口)之间关系
2.变量声明并不能决定其最终类型。
3.数组初始化{}本身不具备类型。
相关文章推荐
- 关于最近使用imageMagick的Jmagick和im4java
- 答疑java集合问题
- 我的SPARK调试java代码
- 深入探讨 Java 类加载器
- struts2环境搭建
- java.io.FileNotFoundException: F:\jstorm (拒绝访问.)
- Java中的Exception异常 自定义异常
- Spring入门第3天--JDBC Template开发入门
- ElasticSearch Java Api -检索索引库
- Java注解
- windows下java环境变量配置
- 接口添加默认方法以及静态方法
- 50. Spring Boot日志升级篇—log4j【从零开始学Spring Boot】
- Spring 编码过滤 -- 解析Filter实现原理
- Java:按值传递还是按引用传递详细解说
- Spring 之 AOP
- 毕向东Java视频学习笔记【Day09 继承+接口+抽象类】
- 设计模式-简单工场模式
- Hibernate框架常用映射
- Spring注解@Component、@Repository、@Service、@Controller区别