zoukankan      html  css  js  c++  java
  • 第九天

    1.什么时候需要用到强制类型转换(引用数据类型)

    当把子类对象赋给父类引用变量时,这个父类引用变量只能调用父类拥有的方法,

    不能调用子类特有的方法,即使它实际引用的是子类对象。

    如果需要让这个父类引用变量调用它子类的特有的方法,就必须把它强制转换成子类类型。

    2.引用类型之间要强制转换成功需要有什么条件

    把父类实例转换成子类类型,则这个对象必须实际上是子类实例才行,否则将在运行时引发ClassCastException。

    3.让程序更健壮的写法:

    在强制转换前使用instanceof运算符判断是否可以成功转换。

    示例如下:

    public class Base {   
         public void say() {  //定义一个公共的say方法
             System.out.println("base的say方法");//输出
         }
    }
    public class Sub extends Base{
       //子类中 把父类的方法重写
        public void say() {
            System.out.println("sub的say方法");
        }
        public void read() {
            System.out.println("sub的read方法,子类特有的方法,父类中没有的方法");
        }
    }
    public class Test {
          public static void main(String[] args) {
                Base base = new Sub();
                base.say();
                //我们业务需要base变量调用子类中的特有的方法read,这个时候需要我们对base进行强制类型转换
               if(base instanceof Sub) {  //为了程序的健壮性,
                   //运算符是用来在运行时指出对象是否是特定类的一个实例
                   ((Sub)base).read();//强制类型转换  base转换为Sub,
                   //转换后可以调用Sub里的read方法
               }
           }
    }

    java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。

    用法: 

    result = object instanceof class 

    参数: 

    Result:布尔类型。 

    Object:必选项。任意对象表达式。 

    Class:必选项。任意已定义的对象类。 

    说明: 

    如果 object 是 class 的一个实例,则 instanceof 运算符返回 true。如果 object 不是指定类的一个实例,或者 object 是 null,则返回 false。

    但是instanceof在Java的编译状态和运行状态是有区别的:

    在编译状态中,class可以是object对象的父类,自身类,子类。在这三种情况下Java编译时不会报错。

    在运行转态中,class可以是object对象的父类,自身类,不能是子类。在前两种情况下result的结果为true,最后一种为false。但是class为子类时编译不会报错。运行结果为false。

    public class Person {    //定义一个Person类   
    }
    public class XiaoMing extends Person{
    }
    public class Abc {
    }
    public class Test {
          public static void main(String[] args) {
              Person person = new Person();
              XiaoMing x = new XiaoMing();
              System.out.println(x instanceof Person);// 父类编译可以              运行true
              System.out.println(x instanceof XiaoMing);//自身类编译可以         运行true
              System.out.println(person instanceof XiaoMing);//子类编译可以    运行false
              //System.out.println(x instanceof Abc);//无关系  编译报错
           }
    }

    继承

    继承是面向对象的三大特征之一,也是实现软件复用的重要手段,Java的继承具有单继承的特点,每个类只有一个直接父类,可以有多个间接父类。继承是一种"is-a"的关系。

        优点:

    • 代码复用
    • 子类可重写父类的方法
    • 创建子类对象时,无需创建父类的对象,子类自动拥有父类的成员变量和方法。
    • 子类在父类的基础上可根据自己的业务需求扩展,新增属性和方法

       缺点:

    • 破坏封装

    封装:通过公有化方法访问私有化属性,使得数据不容易被任意窜改,常用private修饰属性;

    继承:通过子类继承父类从而获得父类的属性和方法,正常情况下,用protected修饰属性,专门用于给子类继承的,权限一般在本包下和子类里;

    继承破坏了封装:是因为属性的访问修饰符被修改,使得属性在本包和子类里可以任意修改属性的数据,数据的安全性从而得不到保障。

    如下例子中父类Fruit中有成员变量weight。Apple继承了Fruit之后,Apple可直接操作Fruit类的成员变量,因此破坏了封装性!

    public class Fruit {
        //成员变量
        // private double weight;为了让子类继承,改为了:
        protected double weight;
        public void info(){   
        System.out.println("我是一个水果!重" + weight + "g!");
        }
    }
    public class Apple extends Fruit {   //继承
        public static void main(String[] args){ //程序入口
        Apple a = new Apple();  //实例化对象
        a.weight = 10;  //调用父类变量
        a.info();  //调用父类方法
        }
    }
    • 支持扩展,但往往以增加复杂度为代价
    • 不支持动态继承,在运行时,子类无法选择不同的父类
    • 紧耦合

    当子类继承了父类,需要修改父类接口名称时,修改了接口名称,子类都会报错,如果是同一个人维护,可能还可以修改,如果由多个人修改,后果不敢想象呀!

    组合

    什么是组合? 组合在代码中如何体现呢?如下:

    public class Animal {   
         public void breath() {
            //......实现功能 
             System.out.println("breath of Animal");
         }
    }
    public class Bird {
          //清楚我们现在的目标,想把Animal类里的breath方法,在这个类里复用
         //直接的办法是将Bird类做成Animal类的子类,从而可以实现复用Animal类里的breath方法里的代码
        //另一种办法  组合
        private Animal animal; //私有变量 Animal类型, 变量名animal
        public Bird() {    //空构造方法
        }
        public Bird(Animal animal) {  //有参构造
            this.animal = animal;
        }
        public void breath() {    
            animal.breath();  //就是我们实现另一种代码复用这个目标的另一种技术:组合
        }
        public void fly(){
            System.out.println("我在飞..");
            }
    }
    public class Test {
           public static void main(String[] args) {
            Animal animal = new Animal();   //实例化一个Animal,new一个Animal对象
            Bird   bird   = new Bird(animal);//实例化一个Bird对象,new一个有参构造,将animal对象传进去
            //bird里面包含了animal一个对象,实质是调用bird里面的animal对象里面的breath方法
            bird.breath();//通过brid调用Animal类的breath方法
            bird.fly();//调用bird本类的fly方法
            }
    }

    优点

    • 不破坏封装,松耦合
    • 具有可扩展性
    • 支持动态组合

     缺点

    • 整体类不能自动获得和局部类同样的接口

    组合对比继承

    • 继承结构,子类可以获得父类内部实现细节,破坏封装。组合结构:整体不能看到部分的内部实现细节,不会破坏封装
    • 继承模式是单继承,不支持动态继承,组合模式可以支持动态组合
    • 继承结构中,子类可以回溯父类,直到Object类,这样就可以根据业务实现多态(向上转型和向下转型)  ,组合中不可以实现多态
    • 在开发过程中,如果复用的部分不会改变,为了安全性和封装的本质,应该使用组合,当我们不仅需要复用,而且还可能要重写或扩展,则应该使用继承

    如何选择?

    • 两个类之间,明显的存在整体和部分的关系,则应该使用组合来实现复用,当我们需要对已有类做一番改造,从而得到新的符合需求的类,则应该使用继承
    • 当需要被复用的类一定不会改变时,应该使用组合,否则,应该使用继承

     今日回顾知识

     

    Animal animal=new Dog()和Animal animal=dog 一样吗?

    第一种写法是定义一个Dog类的对象,就是你说的父类引用指向子类对象,思想是多态。

    第二种写法是定义Animal类的对象,并且把dog赋值给它。这里有一个隐藏的类型转换。可以分解成两句话实现,

    Animal animal = new Animal();

    animal = dog;

     

     

  • 相关阅读:
    rm
    Linux下解包/打包,压缩/解压命令
    虚拟机安装---vm12+ubuntukylin16.04
    mysql-5.6.41-winx64安装
    tensorflow学习笔记一------下载安装,配置环境(基于ubuntu16.04 pycharm)
    大一上学期C语言学习心得总结
    常见HTTP状态码
    Java语言基础及java核心
    linux下安装JMeter(小白教程)
    Linux下安装JDK(小白教程)
  • 原文地址:https://www.cnblogs.com/jikebin/p/12431638.html
Copyright © 2011-2022 走看看