Java(16)java转型问题

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();//此步成功运行
    }
}
上一篇:Vue组件


下一篇:flex九宫格一点小思考