java转型问题
-
基本数据类型的casting:
-
自动类型转换:小的数据类型可以自动转换为大的数据类型,如:
long a=20; double b=12.0f;
-
强制类型转换:可以把大的数据类型转换成小的数据类型,如:
int c=(int)1200L;
-
-
对JAVA对象的类型转换(造型)
需要记住一句话:允许父类引用指向子类对象,不允许子类引用指向父类对象,因为子类功能比父类多,多的功能不能凭空变出来。从子类到父类的类型转换可以自动进行,但是从父类到子类的类型转换必须通过(强制类型转换)实现,无继承关系的引用类型的转换是非法的。
package test;
public class Father {
public void run() {
System.out.println("RunSlow");
}
}
class Son extends Father {
@Override
public void run() {
System.out.println("RunFast");
}
public void play() {
System.out.println("play");
}
}
class RunClass {
public static void main(String[] args) {
//下面演示向上转型,父类引用可以指向子类对象
Son a = new Son();
Father b = a; //会自动将new Son()对象的引用类型转型为Father类型
b.run();
/*程序在执行时分两个阶段:编译阶段 、运行阶段
程序在编译阶段只知道b是Father类型,在运行时候才知道堆中的实际对象是Son类型。*/
//-------------------------------------------
//下面演示向下转型
// Father c=new Father();
// Son d =c; 此步会编译报错,因为子类引用不可以指向父类对象
// Father c=new Father();
// Son d =(Son)c; //编译时不会报错,但是运行时会报错,java.lang.ClassCastException: test.Father cannot be cast to test.Son,下面才是正确的做法:
Father c = new Son();
Son d = (Son) c; //强制将new Son()对象的引用类型转换为Son类型
d.run();
}
}
/*运行结果为
RunFast
RunFast*/
向上转型
对象向上转型后,对象会丢失除了与父类共有的属性和方法,因为属性和方法是在编译时确定的,编译时为父类类型。
package test;
public class Animal {
public void eat() {
System.out.println("eat");
}
}
class dog extends Animal {
public void run() {
System.out.println("run");
}
}
class RunClass {
public static void doEat(Animal x) {
x.eat();
}
public static void main(String[] args) {
Animal a = new dog();
a.eat();
a.run(); //此步会报错,run()方法已经丢失
Animal b = new Animal();
dog c = new dog();
RunClass.doEat(b);
RunClass.doEat(c);//此步存在向上转型,因为doEat()需要的是Animal类的实例对象
}
}
从上面案例可以知道,向上转型的其中一个作用就是用在方法的参数传递上,doEat()
方法以父类为参数,调用时即使传来不同的子类,也不需要创建多个不同的方法,可以对其进行向上转型,使得代码变得简洁。
静态绑定与动态绑定
package test;
public class Human {
public void sing(){
System.out.println("我唱歌不怎么好听");
}
}
class Singer extends Human{
@Override
public void sing() {
System.out.println("我唱歌超级好听");
}
}
class RunT{
public static void main(String[] args) {
Singer a= new Singer();
Human b=a;
b.sing();
/*
在编译阶段,b绑定的是Human类型中定义的sing()方法(静态绑定,也叫做编译器绑定)
在运行阶段,堆中的对象实际上是Singer类型,而Sing类型已经重写了sing()方法。
所以程序在运行阶段,对象绑定的方法是Singer类型中的sing()方法(动态绑定,也叫做运行期绑定)
--这种现象只是针对方法来说,属性没有这种现象,即使子类里定义了与父类完全相同的实例变量,
这个实例变量依然不能覆盖父类中定义的实例变量--
*/
}
}
/*运行结果为:
我唱歌超级好听*/
向下转型
向上转型时会遗失除与父类对象共有的其他方法;可以用向下转型在重新转回,这个和向上转型的作用要结合理解。
package test;
public class Father {
public void run() {
System.out.println("RunSlow");
}
}
class Son extends Father {
@Override
public void run() {
System.out.println("RunFast");
}
public void play() {
System.out.println("play");
}
}
class RunClass {
public static void main(String[] args) {
Father c = new Son();
// c.play(); 此步编译阶段即报错
Son d = (Son) c;
d.play();//此步成功运行
}
}