当前位置: 代码迷 >> J2SE >> 为什么是强制类型转换?解决方法
  详细解决方案

为什么是强制类型转换?解决方法

热度:420   发布时间:2016-04-24 02:25:39.0
为什么是强制类型转换?
有如下代码:
class T1{}
class T2 extends T1{}
class T3 extends T2{}
class Test{
  public static void main(String [] args){
  T1 t1=new T3();
  T2 t2=(T2)t1;//合法,发生强制类型转换。*1

  t1=new T1();
  t2=(T2)t1;//非法,因为t1指向的对象是T1类型的。*2
  }
}

这是我从书上抄来的,只是在*1、*2两处不明白。谁能给解释一下?
我觉得,*1处,应该是由T3向T2转换,是提升的,应该是自动转换啊?
*2处,是T1向T3转换,是孙子类向下继承,应该是强制转换啊?

------解决方案--------------------
Java是自动转换的。 T3 -> T1

t1 现在是一个 T1对象, 向孙子类强制转换,使不可行的。

我们可以用内存原理来解释:
*1处: T3对象创建时,它包括了T1和T2的内存数据。 t1是指向T3中的T1部分。
*2处: T1对象创建, 它没包括T2和T3的内存数据。那么我们就不能孙子类强制转换。
------解决方案--------------------
这两个都是像下转型。
那么为什么前一句向下转型代码可以,而后一句代码却出错?
这是因为刚开始的时候,t1指向一个子类T3的对象,所以子类T2的实例对象t2当然也可以指向t1,因为T3是T2的子类,这里是多态啊,父类引用指向子类对象。
而下面的时候t1是一个父类对象,子类引用t2不能指向父类对象t1。那么如何避免这种在执行向下转型时发生运行时ClassCastException异常?用instanceof就可以了。我们修改一下的代码: 
class T1{}
class T2 extends T1{}
class T3 extends T2{}
class Test{
public static void main(String [] args){
T1 t1=new T3();
T2 t2=(T2)t1;//合法,发生强制类型转换。*1

t1=new T1();
if(t1 instanceof T2){//显然t1不是T2啊,就想不能说鸟是麻雀一样
t2=(T2)t1;
}
}
}
------解决方案--------------------
我觉得有一个比喻很贴切,男人是人,但人不是男人!所以第一处把男人转换为人,肯定成立啊!但是把人转换为男人,就有问题了!楼主想想,是不是这个道理!
------解决方案--------------------
子类可以转为父类
但父类不可转为子类。
------解决方案--------------------
就像说某人长的很像他爸 是正确的
但是当说他爸长的像他就有点说不通了
同理 子类向父类转换的时候不用强调就可以自动实现
但是父类向子类转换的时候就有条件了 首先必须先由子类实现向父类转型 以此来说明他们是父子关系 然后父类才有可能像子类转型 转型的时候必须在前面加上强制转换类型
------解决方案--------------------
强制转换这个概念其实容易误解,强制转换本来只能用来描述基本类型的转换,
比如:float a = 5.0f; int d = (int) a;

之所以需要强制转换,是因为这种变量在内存中的布局是不同的,比如 int 是按一般说的二进制分布的,而 Float 则是按 IEEE 浮点数的二进制表示分布在内存的(某几位是指数,某几位是尾数,某个位是+/-号位等),这需要编译器生成转换的指令去将它的不同的位转换成对应的值。

而面向对象里面的 cast 在 Java 中,case 仅仅是临时改变可见性,也就是说:
Parent p = new Child();
Child c = (Child) p;
这两句,第一句,我们创建了 Child对象,赋值给 Parent 之后,我们就可以只能看到 Parent 类的属性和方法。在 Child 中新增的 Parent 中没有,就不能使用,这由编译器来检查。而当我们再赋值给 Child 时,用 cast 仅仅是请求编译器再检查一下它是不是合适的,如果合适就再把它的可见性还原。其它你要调用一个对象的某个方法,编译器最后生成的指令其实都是用虚函数调用的方式,也就是相当于动态地调用而不像 C语言那样去链接生成静态二进制代码,类型只是 VM 来确保它是有效的,编译的过程本身”并不那么需要知道类型“。否则的话,我们要用 Java 的反射的话,那岂不是很麻烦?背后的原理就是抽象类型的对象本身从 new 之后就永远不会改变类型(Java 中如此,其它语言不清楚)。

上面基本类型和抽象类型的 Cast 的意思是不同的,基本类型会改变内存中数据的分布,而抽象类型的都仅改变可见性,对象本身的状态没有任何变化。



------解决方案--------------------
探讨
1.父类引用指向子类对象为什么是向下转型?由子类对象类型转向父类引用类型应该是向上转型啊?
2.子类引用t2指向父类对象t1应该可以啊?
  相关解决方案