• Java向上下转型中的陷阱{详细}


    1: 多态

      多态时继承下面的产物,之所以存在向上向下转型的目的,就是解决参数传递的不变形,体现面向接口编程的重要性,

    1.1 方法的多态性

      ①. 方法的重载:同一个方法名称可以根据参数的类型或个数不同调用不同的方法体。
      ②. 方法的覆写:同一个父类的方法,可能根据实例化子类的不同也有不同的表现形式。

    1.2. 对象的向上转型

      出现了父类指向了子类那么出现 向上转型  对象的向上转型:父类 父类对象 = 子类实例

    class Person{
        public void say() {
            System.out.println("我是Person");
        }
    }
    
    public class Student extends Person {
        
        public void say() {
            System.out.println("我是Student");
        }
        public void gotoSchool() {
            System.out.println("我的职责是上学");
        }
        public static void main(String[] args) {
            // 向上转型 父类实例对象指向子类实例 只保留父类子类同名的方法,且子类变量覆盖父类变量
            Person p=new Student();
            p.say();
        }
    }

    输出: 我是Student

    目的: 用于参数统一化,假设父类有n个子类,方法要接受子类的实例,如果没有向上转型,就需要定义n个方法接收不同的对象

    1.3 对象的向下转型

     对象的向下转型:子类 子类对象 = (子类)父类实例

    class Person{
        public void say() {
            System.out.println("我是Person");
        }
    }
    
    public class Student extends Person {
        
        public void say() {
            System.out.println("我是Student");
        }
        public void gotoSchool() {
            System.out.println("我的职责是上学");
        }
        public static void main(String[] args) {
            // 向上转型 父类实例对象指向子类实例 只保留父类子类同名的方法,且子类变量覆盖父类变量
            Person p=new Student();
            p.say();
            // 向下转型 子类实例指向父类 可以拥有子类自己的方法,
            Student s=(Student) p;
            s.say();
            s.gotoSchool();
        }
    }

    注意:  向下转型之前一定要进行向上转型!!(让父类先指向子类)
    否则在转型时会出现ClassCastException(类型转换异常–运行时异常)

    问题: 如果向下转型存在安全隐患,那么如何转型才靠谱

    class Person{
        public void print()
        {
            System.out.println("我是人");
        }
        public void p()
        {
            System.out.println("伤心的一天");
        }
    }
    class Student extends Person{
        public void print()
        {
            System.out.println("我是学生");
        }
        public void fun()
        {
            System.out.println("开心的一天!");
        }
    }
    public class Test{
        public static void main(String[] args)
        {
            Person per = new Student();
            //per是否能表示Person实例
            System.out.println(per instanceof Person);
            //per是否能表示Student实例
            System.out.println(per instanceof Student);
            if(per instanceof Student)
            {
                Student stu = (Student)per;
                stu.fun();
            }
        }
    }

    注意: 虽然增强了 程序的健壮性 但是,仅仅是这样,你还是需要 在这之前 进行 父类指向子类实例的过程  父类 父类对象 = 子类实例

     1,4 扩展调用的例子

    class Person{
        public void print()
        {
            System.out.println("我是人");
        }
    }
    class Student extends Person{
        public void print()
        {
            System.out.println("我是学生");
        }
    }
    class Worker extends Person{
         public void print()
        {
            System.out.println("我是工人");
        }
    }
    public class Test{
        public static void main(String[] args)
        {
            whoAreYou(new Student());
            whoAreYou(new Worker());
        }
        public static void whoAreYou(Person per)
        {
            per.print();
        }
    }

    2: 存在公共变量的分析过程

     先类看一个代码:

    class BB{
        public String S="B";
        public String getS() {
            return this.S;
        }
        public void setS(String s) {
            this.S = s;
        }
    }
    
    public class AA extends BB{
        public String S="A";
        public String getS() {
            return this.S;
        }
        public void setS(String s) {
            this.S = s;
        }
        
        public static void main(String[] args) {
                AA aa = new AA();
                BB bb = new BB();
                System.out.println(aa.S);
                System.out.println(bb.S);
                aa.setS("AA");
                bb.setS("BB");
                System.out.println(bb.S);
                bb=aa;
                aa=(AA) bb;
                System.out.println(bb instanceof BB);
                System.out.println(bb instanceof AA);
                System.out.println(aa.S);
                System.out.println(bb.S);
                System.out.println(aa.getS());
                System.out.println(bb.getS());
                System.out.println(bb.S);
        }
    }

    一般我们认为输出

    1:A
    2:B
    3:BB
    4:true
    5:true
    6:AA
    7:BB
    8:AA
    9:AA
    10:BB

    上面输出 前6个没有问题,第七个由于前面执行了B.setS 所以我们认为应该为BB 

    正确输出结果为:

    1:A
    2:B
    3:BB
    4:true
    5:true
    6:AA
    7:B
    8:AA
    9:AA
    10:B

     那么为什么我们 第 7 10输出结果为 B呢, 我们打上断点看一下:

    1: aa实例 由于继承了bb 所以域中存在S='B'

    当执行了 设置BB的时候, 值按照我们的意思改变了

     当执行了向上转型的时候,AA指向父类的实例,所以发生改变

    所以第 System.out.println(bb.S); 能够输出 B,

    而 System.out.println(bb.getS());为什么输出AA 因为当前指向指向子类 aa aa中的getS方法与父类同名,那么执行子类的方法,注意:如果这里为不同名称的方法,那么执行父类的方法,

    我给出这个代码:

    package LL;
    
    class BB2{
        public int SB=1;
        public int getSB() {
            return SB;
        }
        public void setSB(int sB) {
            SB = sB;
        }
    }
    
    public class PP extends BB2{
        public int SA=2;
        public int getSA() {
            return SA;
        }
        public void setSA(int sA) {
            SA = sA;
        }
        public static void main(String[] args) {
                PP aa = new PP();
                BB2 bb = new BB2();
                System.out.println(aa.SA);//2
                System.out.println(bb.SB);//1
                aa.setSA(22);
                bb.setSB(11);
                System.out.println(bb.SB);//11
                bb=aa;
                System.out.println(bb instanceof BB2);
                System.out.println(bb instanceof PP);
                System.out.println(aa.SA);//22
                System.out.println(bb.SB);//1
                System.out.println(aa.getSA());//22
                System.out.println(bb.getSB());//22
                System.out.println(bb.SB);//1
        }
    }

    3:总结

    • 最好将变量private 私有化 ,以免阅读程序麻烦
    • 存在public变量时候,继承的子类 执行的时候 回拷贝一份父类的变量,(表示 父类修改变量不会影响子类拷贝这个变量的值)
    • 当发生向上转型的时候,父类指向子类实例,那么父类实例拥有与子类实例一样的参数变量,
    • 转型的时候 子类只会保留与父类中同名的方法,其他放弃
    • 最后: 向下转型的时候 ,一定必须让父类实例指向子类
  • 相关阅读:
    C# Func的同步、异步调用
    C#以管理员身份运行程序
    C# 代码编程规范
    C# DES加密解密
    C# MD5加密
    EntityFramework查询--联合查询(Join,GroupJoin)
    C# 图片和Base64之间的转换
    php 验证身份证号
    Vue环境搭建
    PHP 3种方法实现采集网站数据
  • 原文地址:https://www.cnblogs.com/dgwblog/p/11863174.html
Copyright © 2020-2023  润新知