zoukankan      html  css  js  c++  java
  • java基础继承

     女神镇楼

    1、类的继承

     继承是面向对象中的一个非常重要的概念,是的整个程序具有一定的弹性,在程序中,复用一些已经定义的完善的类,不仅可以减少软件的开发周期,还可以提高软件的可维护性和可拓展性。

        继承的基本思想是基于某个父类的拓展,制造出一个新的子类,子类可继承父类的属性和方法,也可以增加原父类不具备的属性和方法,或者重写父类中的某个方法。比如平行四边形继承了四边形类,这个时候,平行四边形类将所有四边形类中的属性和方法保留下来,并拓展了新的属于自己的属性和方法。

    代码示例---父类:

    public class Test {
        public Test(){ //构造方法
            //SomeSentence
        }
        protected void doSomething(){
            // 成员方法
        }
        protected Test dolt(){
            // 方法返回值类型为Test类型
            return new Test();
        }
    }

    代码示例---子类:

    public class Test2 extends Test {
        public Test2(){
            //构造方法
            super(); // 调用父类的构造方法
            super.doSomething(); //调用父类的成员方法
        }
        public void doSomethingNeW(){
            //新增方法
        }
        public void doSomeThing(){
            //重写父类方法
        }
        protected Test2 dolt(){
            //重写父类方法,返回值类型为Test2类型
            return new Test2();
        }
    }

    实例说明:

        实例中,Test类是Test2类的父类,Test2类是Test类的子类,在子类中连同初始化父类的构造方法来完成子类的初始化操作,即可以在子类的构造方法中使用super()语句调用父类的构造方法,也可以在子类中通过super关键字调用父类的成员方法。但是在子类中没有权限调用父类中使用private修饰的方法,只可以调用父类中修饰为public或者protected的成员方法。

        继承不止可以拓展父类的功能,还可以对父类的方法进行重写,重写也可以成为覆盖,就是在子类中,将父类的成员方法的名称保留,重写成员方法实现的内容,可更改成员方法的储存权限,或者修改成员方法的返回值类型,还可以将权限修饰符修改为public。

        继承中还有一种特殊的重写方式,子类与父类的成员方法的返回值、方法名称、参数类型及个数完全相同,唯一不同的是方法实现内容,这种特殊的重写方式称为重构。 

    当重写父类方法时,修改方法的修饰权限只能从小的范围到大的范围改变,例如,父类中的
    doSomething0方法的修饰权限为protected, 继承后子类中的方法doSomething0的修饰权限只能修改
    为public,不能修改为private。

        在java中,一切都是一对象的形式进行处理,在继承机制中,创建一个子类对象,将包含一个父类子对象,这个对象与父类创建的对象是一样的,两者的区别就在于,后者来自于外部,而前者来自子类对象内部。当实例化子类对象时,父类对象也相应被实例化,也就是说,在实例化子类对象时,java编译器会在子类的构造方法中自动调用父类的无参构造方法。

     代码示例:

    public class Parent {
        Parent(){
            System.out.println("调用父类的Parent()方法");
        }
    }
    public class Subparent extends Parent { //继承Parent
        Subparent(){
            System.out.println("调用子类Subparent的构造方法");
        }
    }
    public class Subbroutine extends Subparent { // 继承 Subparent
        Subbroutine(){
            System.out.println("调用子类Subbroutine的方法。");
        }
    
        public static void main(String[] args) {
            Subbroutine s = new Subbroutine();
        }
    }

     运行结果:

     运行结果说明:

        子类Subroutine的主方法中只调用子类的构造方法实例化子类对象,并且在子类的构造方法中没有调用父类构造方法的任何语句,但是在实例化子类对象时,他会相应的调用父类的构造方法,调用构造方法的顺序是:顶级父类==上一级父类==子类,也就是实例化子类对象时首先实例化父类对象,再实例化子类对象。在子类的构造方法访问父类的构造方法之前,已经完成了父类的实例化操作。

        说明:

        在实例化子类对象时,父类无参构造方法将会被自动调用,但是有参构造方法不能被自动调用,只能借用super关键字显式的调用父类方法。

        如果使用finalize()方法对对象进行清理,需要确保子类的finalize()方法最后一个动作是调用父类的finalize()方法,用来保证垃圾回收对象所占用的内存时,对象所有部分都能被正常终止。

    极客时间视频课总结:

     1、继承的语法就是在类名后面使用extends 加 要继承的类名
     被继承的类叫做父类(Parent Class),比如本例中的MerchandiseV2。
     继承者叫做子类(Sub Class),比如本例中的PhoneExtendsMerchandise。
     Java中只允许一个类有一个直接的父类(Parent Class),即所谓的单继承
     没错,别的类也可以继承子类,比如可以有一个HuaweiPhone继承PhoneExtendsMerchandise
     这时候,HuaweiPhone就是PhoneExtendsMerchandise的子类了。
     子类继承了父类什么呢?所有的属性和方法。
     但是子类并不能访问父类的private的成员(包括方法和属性)。

    通过使用和父类方法签名一样,而且返回值也必须一样的方法,可以让子类覆盖(override)掉父类的方法
    子类并不是只能把父类的方法拿过来,而且可以通过覆盖来替换其中不适合子类的方法
    public class PhoneExtendsMerchandise extends MerchandiseV2 {
    	...
    }
    public class HuaweiPhone extends PhoneExtendsMerchandise {
    
        public HuaweiPhone(String name, String id, int count, double soldPrice, double purchasePrice, double screenSize, double cpuHZ, int memoryG, int storageG, String brand, String os) {
            super(name, id, count, soldPrice, purchasePrice, screenSize, cpuHZ, memoryG, storageG, brand, os);
        }
    }

    2、super与父类沟通的桥梁

    使用super可以调用父类的方法和属性(当然必须满足访问控制符的控制)
    public double buy(int count) {
            if (count > MAX_BUY_ONE_ORDER) {
                System.out.println("购买失败,手机一次最多只能买" + MAX_BUY_ONE_ORDER + "个");
                return -2;
            }
            return super.buy(count);
        }
    super是子类和父类交流的桥梁,但是并不是父类的引用
    使用super可以调用父类的public属性,但是super不是一个引用。
    super的用法就像是一个父类的引用。它是继承的一部分,像组合的那部分,但不是全部
    public void useSuper() {
            super.describe();
            super.buy(66);
            System.out.println("父类里的count属性:" + super.count);
        }
    可以认为,创建子类对象的时候,也就同时创建了一个隐藏的父类对象
     
      public Phone(
            String name, String id, int count, double soldPrice, double purchasePrice,
            double screenSize, double cpuHZ, int memoryG, int storageG, String brand, String os
        ) {
            // >> TODO 可以认为,创建子类对象的时候,也就同时创建了一个隐藏的父类对象
    
            this.screenSize = screenSize;
            this.cpuHZ = cpuHZ;
            this.memoryG = memoryG;
            this.storageG = storageG;
            this.brand = brand;
            this.os = os;
    
            // >> TODO 所以,才能够setName,对name属性进行操作。
            this.setName(name);
            this.setId(id);
            this.setCount(count);
            this.setSoldPrice(soldPrice);
            this.setPurchasePrice(purchasePrice);
        }
     3、调用父类的构造方法
    使用super调用父类的构造方法,必须是子类构造方法的第一个语句
    可以使用表达式
    super调用构造方法,不可以使用super访问父类的属性和方法,不可以使用子类成员变量和方法
    可以使用静态变量和方法
     
     public Phone(
                String name, String id, int count, double soldPrice, double purchasePrice,
                double screenSize, double cpuHZ, int memoryG, int storageG, String brand, String os
        ) {
            super(name, id, count, soldPrice * 1.2, purchasePrice);
            init(screenSize, cpuHZ, memoryG, storageG, brand, os);
        }
     4、父类和子类的引用赋值关系
    可以用子类的引用给父类的引用赋值,也就是说,父类的引用可以指向子类的对象
    MerchandiseV2 m = ph;
            MerchandiseV2 m2 = new Phone(
                "手机002", "Phone002", 100, 1999, 999,
                4.5, 3.5, 4, 128, "索尼", "安卓"
            );
    
    但是反之则不行,不能让子类的引用指向父类的对象。因为父类并没有子类的属性和方法
     
    Phone notDoable = new MerchandiseV2();

    因为子类继承了父类的方法和属性,所以父类的对象能做到的,子类的对象肯定能做到
    换句话说,我们可以在子类的对象上,执行父类的方法
    当父类的引用指向子类的实例(或者父类的实例),只能通过父类的引用,像父类一样操作子类的对象
    也就是说"名"的类型,决定了能执行哪些操作
    ph和m都指向同一个对象,通过ph可以调用getBrand方法

    Phone ph = new Phone(
                "手机001", "Phone001", 100, 1999, 999,
                4.5, 3.5, 4, 128, "索尼", "安卓"
            );
    
            MerchandiseV2 m = ph;

    因为ph的类型是Phone,Phone里定义了getBrand方法
    ph.getBrand();
    ph和m都指向同一个对象,但是通过m就不可以调用getBrand方法
    因为m的类型是MerchandiseV2,MerchandiseV2里没有你定义getBrand方法
    m.getBrand();

    如果确定一个父类的引用指向的对象,实际上就是一个子类的对象(或者子类的子类的对象),可以强制类型转换

    Phone aPhone = (Phone) m2;

    完整代码(父类):

    package com.geekbang.supermarket;
    
    public class MerchandiseV2 {
    
        public String name;
        public String id;
        public int count;
        public double soldPrice;
        public double purchasePrice;
    
    
        public MerchandiseV2(String name, String id, int count, double soldPrice, double purchasePrice) {
            this.name = name;
            this.id = id;
            this.count = count;
            this.soldPrice = soldPrice;
            this.purchasePrice = purchasePrice;
        }
    
        public MerchandiseV2(String name, String id, int count, double soldPrice) {
            // double purPrice = soldPrice * 0.8;
            // this(name, id, count, soldPrice, purchasePrice);
            this(name, id, count, soldPrice, soldPrice * 0.8);
            // double purPrice = soldPrice * 0.8;
        }
    
        public MerchandiseV2() {
            this("无名", "000", 0, 1, 1.1);
    
        }
    
        public void describe() {
            System.out.println("商品名字叫做" + name + ",id是" + id + "。 商品售价是" + soldPrice
                + "。商品进价是" + purchasePrice + "。商品库存量是" + count +
                "。销售一个的毛利润是" + calculateProfit());
        }
    
        public double calculateProfit() {
            double profit = soldPrice - purchasePrice;
    //        if(profit <= 0){
    //            return 0;
    //        }
            return profit;
        }
    
        public double buy(int count) {
            if (this.count < count) {
                System.out.println("购买失败,库存不够");
                return -1;
            }
            this.count -= count;
            double cost = count * soldPrice;
            System.out.println("购买成功,花费为" + cost);
            return cost;
        }
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public int getCount() {
            return count;
        }
    
        public void setCount(int count) {
            this.count = count;
        }
    
        public double getSoldPrice() {
            return soldPrice;
        }
    
        public void setSoldPrice(double soldPrice) {
            this.soldPrice = soldPrice;
        }
    
        public double getPurchasePrice() {
            return purchasePrice;
        }
    
        public void setPurchasePrice(double purchasePrice) {
            this.purchasePrice = purchasePrice;
        }
    }

     完整代码(phone子类):

    package com.geekbang.supermarket;
    
    public class Phone extends MerchandiseV2 {
    
        // 给Phone增加新的属性和方法
        private double screenSize;
        private double cpuHZ;
        private int memoryG;
        private int storageG;
        private String brand;
        private String os;
        private static int MAX_BUY_ONE_ORDER = 5;
    
        public Phone(
            String name, String id, int count, double soldPrice, double purchasePrice,
            double screenSize, double cpuHZ, int memoryG, int storageG, String brand, String os
        ) {
            super(name, id, count, soldPrice * 1.2, purchasePrice);
            this.screenSize = screenSize;
            this.cpuHZ = cpuHZ;
            this.memoryG = memoryG;
            this.storageG = storageG;
            this.brand = brand;
            this.os = os;
        }
    
        public double buy(int count) {
            if (count > MAX_BUY_ONE_ORDER) {
                System.out.println("购买失败,手机一次最多只能买" + MAX_BUY_ONE_ORDER + "个");
                return -2;
            }
            return super.buy(count);
        }
    
        public String getName() {
            return this.brand + ":" + this.os + ":" + super.getName();
        }
    
        public void describe() {
            System.out.println("此手机商品属性如下");
            super.describe();
            System.out.println("手机厂商为" + brand + ";系统为" + os + ";硬件配置如下:\n" +
                "屏幕:" + screenSize + "寸\n" +
                "cpu主频" + cpuHZ + " GHz\n" +
                "内存" + memoryG + "Gb\n" +
                "存储空间" + storageG + "Gb");
        }
    
        public boolean meetCondition() {
            return true;
        }
    
        public double getScreenSize() {
            return screenSize;
        }
    
        public void setScreenSize(double screenSize) {
            this.screenSize = screenSize;
        }
    
        public double getCpuHZ() {
            return cpuHZ;
        }
    
        public void setCpuHZ(double cpuHZ) {
            this.cpuHZ = cpuHZ;
        }
    
        public int getMemoryG() {
            return memoryG;
        }
    
        public void setMemoryG(int memoryG) {
            this.memoryG = memoryG;
        }
    
        public int getStorageG() {
            return storageG;
        }
    
        public void setStorageG(int storageG) {
            this.storageG = storageG;
        }
    
        public String getBrand() {
            return brand;
        }
    
        public void setBrand(String brand) {
            this.brand = brand;
        }
    
        public String getOs() {
            return os;
        }
    
        public void setOs(String os) {
            this.os = os;
        }
    }

    完整代码(ShellColorChangePhone孙子类):

    package com.geekbang.supermarket;
    
    public class ShellColorChangePhone extends Phone {
        private boolean enableShellColorChange;
    
        public ShellColorChangePhone(String name, String id, int count, double soldPrice, double purchasePrice,
                                     double screenSize, double cpuHZ, int memoryG, int storageG, String brand, String os) {
            super(name, id, count, soldPrice, purchasePrice, screenSize, cpuHZ, memoryG, storageG, brand, os);
            enableShellColorChange = false;
        }
    
        public boolean isEnableShellColorChange() {
            return enableShellColorChange;
        }
    
        public void setEnableShellColorChange(boolean enableShellColorChange) {
            this.enableShellColorChange = enableShellColorChange;
        }
    
        @Override
        public void describe() {
            super.describe();
            System.out.println("壳色随着屏幕色变的功能开启状态:" + enableShellColorChange);
        }
    
        @Override
        public double calculateProfit() {
            // TODO 厂家提供10个点的返点
            return super.calculateProfit() + super.getPurchasePrice() * 0.1;
        }
    }

    完整代码(使用类):

    package com.geekbang;
    
    import com.geekbang.supermarket.MerchandiseV2;
    import com.geekbang.supermarket.Phone;
    import com.geekbang.supermarket.ShellColorChangePhone;
    
    public class ReferenceAssign {
        public static void main(String[] args) {
            Phone ph = new Phone(
                "手机001", "Phone001", 100, 1999, 999,
                4.5, 3.5, 4, 128, "索尼", "安卓"
            );
    
            // >> TODO 可以用子类的引用给父类的引用赋值,也就是说,父类的引用可以指向子类的对象
    
            MerchandiseV2 m = ph;
            MerchandiseV2 m2 = new Phone(
                "手机002", "Phone002", 100, 1999, 999,
                4.5, 3.5, 4, 128, "索尼", "安卓"
            );
    
            // >> TODO 但是反之则不行,不能让子类的引用指向父类的对象。因为父类并没有子类的属性和方法呀
    
    //         Phone notDoable = new MerchandiseV2();
    
            // >> TODO                          重点
            // >> TODO 因为子类继承了父类的方法和属性,所以父类的对象能做到的,子类的对象肯定能做到
            //    TODO 换句话说,我们可以在子类的对象上,执行父类的方法
            // >> TODO 当父类的引用指向子类的实例(或者父类的实例),只能通过父类的引用,像父类一样操作子类的对象
            //    TODO 也就是说"名"的类型,决定了能执行哪些操作
    
    
            // >> TODO ph和m都指向同一个对象,通过ph可以调用getBrand方法
            //    TODO 因为ph的类型是Phone,Phone里定义了getBrand方法
            ph.getBrand();
            // >> TODO ph和m都指向同一个对象,但是通过m就不可以调用getBrand方法
            //    TODO 因为m的类型是MerchandiseV2,MerchandiseV2里没有你定义getBrand方法
            // m.getBrand();
    
            // TODO 如果确定一个父类的引用指向的对象,实际上就是一个子类的对象(或者子类的子类的对象),可以强制类型转换
            Phone aPhone = (Phone) m2;
    
            // MerchandiseV2是Phone的父类,Phone是shellColorChangePhone的父类
            ShellColorChangePhone shellColorChangePhone = new ShellColorChangePhone(
                "手机002", "Phone002", 100, 1999, 999,
                4.5, 3.5, 4, 128, "索尼", "安卓"
            );
    
            // TODO 父类的引用,可以指向子类的对象,即可以用子类(以及子类的子类)的引用给父类的引用赋值
            MerchandiseV2 ccm = shellColorChangePhone;
    
            // TODO 父类的引用,可以指向子类的对象。
            // TODO 确定MerchandiseV2的引用ccm是指向的是Phone或者Phone的子类对象,那么可以强制类型转换
            Phone ccp = (Phone) ccm;
    
            // TODO 确定MerchandiseV2的引用ccm是指向的是ShellColorChangePhone或者ShellColorChangePhone的子类对象
            // TODO 那么可以强制类型转换
            ShellColorChangePhone scp = (ShellColorChangePhone) ccm;
    
            // TODO 会出错,因为m2指向的是一个Phone类型的对象,不是ShellColorChangePhone的对象
            ShellColorChangePhone notCCP = (ShellColorChangePhone) m2;
    
    
        }
    }
    
  • 相关阅读:
    定时器应用(函数封装)
    js中的作用域
    js函数传参
    js数据类型转换
    jQuery总结
    少些招数,多些内力
    浏览器中的标签切换事件
    正则表达式之小有名气
    正则表达式之初入江湖
    详解apply
  • 原文地址:https://www.cnblogs.com/pangchunlei/p/15705260.html
Copyright © 2011-2022 走看看