• 面向对象的三大特性、方法重写、super关键字以及装箱拆箱(JAVA基础四)


    一、引言

    面向对象三大特性:封装、继承、多态。

    二、封装【重点】

    2.1 封装的必要性

    • 在对象的外部,为对象的属性赋值,可能存在非法数据的录入。
    • 就目前的技术而言,并没有办法对属性的赋值加以控制。

    2.2 什么是封装

    概念:尽可能隐藏对象的内部实现细节,控制对象的修改及访问的权限。

    访问修饰符:private (可将属性修饰为私有,仅本类可见)

    2.3 公共访问方法

    以访问方法的形式,进而完成赋值与取值操作。
    问题:依旧没有解决到非法数据录入!

    • 提供公共访问方法,以保证数据的正常录入。
    • 命名规范:
      • 赋值:setXXX() //使用方法参数实现赋值
      • 取值:getXXX() //使用方法返回值实现取值

    2.4 过滤有效数据

    在公共的访问方法内部,添加逻辑判断,进而过滤掉非法数据,以保证数据安全。

        // equipId的  setXXX 赋值方法
        public void setEquipId(int equipId) {
            
            //对传过来的值 进行 具体业务需求的操作和修改
            if(equipId >100)
            {
                this.equipId = 100;
            }
            
            this.equipId = equipId;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.5 总结

    在这里插入图片描述

    get/set方法是外界访问对象私有属性的唯一通道,方法内部可对数据进行检测和过滤。

    案例

    package com.qfedu;
    
    public class Equip {
        //装备id
        private int equipId;
        //装备名
        private String equipName;
        //别名
        private String equipAsname;
        //属性id
        private int attrId;
        //属性名称
        private String attrName;
        //售价
        private int sellingPrice;
        //买价
        private int buyingPrice;
        //详情
        private String detail;
        //被动效果
        private String uniquePassive;
        //装备图片
        private String imageUrl;
    
        // equipId的  setXXX 赋值方法
        public void setEquipId(int equipId) {
            this.equipId = equipId;
        }
        // equipId的 取值方法
        public int getEquipId() {
            return equipId;
        }
    
        // equipName  setXXX 赋值方法
        public void setEquipName(String equipName) {
            this.equipName = equipName;
        }
        // equipName的 取值方法
        public String getEquipName() {
            return equipName;
        }
    
        // equipAsname  setXXX 赋值方法
        public void setEquipAsname(String equipAsname) {
            this.equipAsname = equipAsname;
        }
        // equipAsname 取值方法
        public String getEquipAsname() {
            return equipAsname;
        }
    
        public void setAttrId(int attrId) {
            this.attrId = attrId;
        }
        public int getAttrId() {
            return attrId;
        }
        
        public String getAttrName() {
            return attrName;
        }
    
        public void setAttrName(String attrName) {
            this.attrName = attrName;
        }
    
        public int getSellingPrice() {
            return sellingPrice;
        }
    
        public void setSellingPrice(int sellingPrice) {
            this.sellingPrice = sellingPrice;
        }
    
        public int getBuyingPrice() {
            return buyingPrice;
        }
    
        public void setBuyingPrice(int buyingPrice) {
            this.buyingPrice = buyingPrice;
        }
    
        public String getDetail() {
            return detail;
        }
    
        public void setDetail(String detail) {
            this.detail = detail;
        }
    
        public String getUniquePassive() {
            return uniquePassive;
        }
    
        public void setUniquePassive(String uniquePassive) {
            this.uniquePassive = uniquePassive;
        }
    
        public String getImageUrl() {
            return imageUrl;
        }
    
        public void setImageUrl(String imageUrl) {
            this.imageUrl = imageUrl;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    package com.qfedu;
    
    public class EquipTest {
    
        public static void main(String[] args) {
            Equip equip = new Equip();
            //setXXX 赋值
            equip.setEquipId(1112);
            equip.setEquipName("匕首");
            //......
            System.out.println("equipId="+equip.getEquipId()+"equipName="+equip.getEquipName() +".......");
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    三、继承【重点】

    3.1 生活中的继承

    • 生活中的“继承”是施方的一种赠与,受方的一种获得。
    • 将一方所拥有的东西给予另一方。

    在这里插入图片描述

    3.2 程序中的继承

    • 程序中的继承,是类与类之间特征和行为的一种赠与或获得。
    • 两个类之间的继承关系,必须满足“is a”的关系。

    在这里插入图片描述

    3.4 父类的抽象

    实战:可根据程序需要使用到的多个具体类,进行共性抽取,进而定义父类。

    在一组相同或类似的类中,抽取出共性的特征和行为,定义在父类中,实现重用。

    3.5 继承

    语法: class 子类 extends 父类{ } //定义子类时,显示继承父类

    应用:产生继承关系之后,子类可以使用父类中的属性和方法,也可定义子类独有的属性和方法。

    好处:既提高代码的复用性,又提高代码的可扩展性。

    package com.qfedu.extendsTest;
    
    public class Animal {
    
        //品种
        String breed;
        //年龄
        int age;
        //性别
        String sex;
    
        public   void eat() {
            System.out.println("动物吃的方法。。。。");
        }
    
        public  void sleep() {
            System.out.println("动物在睡大觉....");
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    package com.qfedu.extendsTest;
    
    //狗和动物是 is a 的关系
    //所以可以存在  继承关系
    //  子类  extends  父类
    
    public class Dog extends Animal {
    
        String furColoer;
    
        public  void run() {
            System.out.println("狗在溜达。。。。。");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    package com.qfedu.extendsTest;
    
    public class Bread extends  Animal {
        String furColoer;
    
        public  void fly() {
            System.out.println("自由的飞......");
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    package com.qfedu.extendsTest;
    
    public class Test {
    
        public static void main(String[] args) {
            Dog dog = new Dog();
    
            dog.furColoer = "白白";
            dog.breed = "哈士奇";
            dog.age =12;
            dog.sex="母";
    
            System.out.println(dog.sex);
    
            dog.eat();
            dog.sleep();
            dog.run();
    
            Bread bread = new Bread();
            bread.age=300;
            bread.breed="雕";
            bread.furColoer="黑不溜秋";
            bread.fly();
            System.out.println(bread.furColoer);
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    3.6 特点

    在这里插入图片描述

    Java为单继承,一个类只能有一个直接父类,但可以多级继承,属性和方法逐级叠加。

    在这里插入图片描述

    3.7 不可继承

    构造方法: 类中的构造方法,只负责创建本类对象,不可继承。

    private修饰的属性和方法:访问修饰符的一种,仅本类可见。(详见下图)

    父子类不在同一个package中时,default修饰的属性和方法:访问修饰符的一种,仅同包可见。(详见下图)

    在这里插入图片描述

    四、访问修饰符

    4.1 访问修饰符

    在这里插入图片描述

    五、方法重写

    5.1 方法的重写/覆盖

    思考:子类中是否可以定义和父类相同的方法?

    思考:为什么需要在子类中定义和父类相同的方法?

    分析:当父类提供的方法无法满足子类需求时,可在子类中定义和父类相同的方法进行重写(Override)。

    方法重写原则:

    • 方法名称、参数列表、返回值类型必须与父类相同。
    • 访问修饰符可与父类相同或是比父类更宽泛。

    方法重写的执行:

    • 子类重写父类方法后,调用时优先执行子类重写后的方法。
    package com.qfedu.extendsTest;
    
    //狗和动物是 is a 的关系
    //所以可以存在  继承关系
    //  子类  extends  父类
    //单继承
    
    public class Dog extends Animal {
    
        String furColoer;
    
        public  void run() {
            System.out.println("狗在溜达。。。。。");
        }
    
        //重写 eat  和  sleep方法
        // 1.返回值 方法名(参数列表) 要父类完全相同
        // 2. 重写方法修饰符  >=  父类的修饰符  权限
        // 3. 调用子类的,--》 如果子类没有,再调用父类 的
        @Override  // 重写的注解标记
        public  void eat() {
            System.out.println("狗爱吃骨头.......");
        }
    
        public  void sleep() {
            System.out.println("狗在睡大觉。。。。");
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    六、super关键字

    6.1 super关键字

    在子类中,可直接访问从父类继承到的属性和方法,但如果父子类的属性或方法存在重名(属性遮蔽、方法重写)时,需要加以区分,才可专项访问。

    6.2 super访问方法

    super关键字可在子类中访问父类的方法。

    • 使用”super.”的形式访问父类的方法,进而完成在子类中的复用;
    • 再叠加额外的功能代码,组成新的功能。

    6.3 super访问属性

    父子类的同名属性不存在重写关系,两块空间同时存在(子类遮蔽父类属性),需使用不同前缀进行访问。

    package com.qfedu.extendsTest;
    
    public class Fish  extends  Animal{
    
        //年龄
        int age = 10;
    
        public  void swim() {
            System.out.println("小鱼游来游去");
        }
    
        public  int getAge() {
            //1. 要的是本类里的age
            //2 用super来获取 父类 属性
            return  super.age;
        }
    
        @Override
        public void eat() {
            //1.调用原来的方法
            super.eat();
            //2.增加自己的逻辑
            System.out.println("虾米");
    
        }
    
        @Override
        public void sleep() {
            //1.调用父类 的方法
            super.sleep();
            //2.增加自己的逻辑
            System.out.println("睡7秒");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    //super关键字
    //1. super 访问父类 的方法和属性
    //2. super访问属性  如果子类与父类 的属性有重复, 用super来表示父类 的属性
    System.out.println("--------------------------------------");
    Fish fish = new Fish();
    fish.eat();
    fish.sleep();
    System.out.println(fish.getAge());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    6.4 继承中的对象创建

    在具有继承关系的对象创建中,构建子类对象会先构建父类对象。

    由父类的共性内容,叠加子类的独有内容,组合成完整的子类对象。

    在这里插入图片描述

    6.5 继承后的对象构建过程

    在这里插入图片描述

    在这里插入图片描述

    构建子类对象时,先构建父类对象。

    6.6 super调用父类无参构造

    在这里插入图片描述

    运行结果:

    A()
    B()
    C()

    super():表示调用父类无参构造方法。如果没有显示书写,隐式存在于子类构造方法的首行。

    6.7 super调用父类有参构造

    在这里插入图片描述

    super():表示调用父类无参构造方法。

    super(实参):表示调用父类有参构造方法。

    public class TestArgsConstructor {
    	public static void main(String[] args) {
    		
    		new Son();
    		
    		System.out.println("-------------");
    		
    		Son son = new Son(10);
    		
    		System.out.println("-------------");
    		
    		new Son(3.5);
    		
    		System.out.println(son.field);
    	}
    }
    
    class Father{
    	
    	int field;//父类提供的属性
    	
    	public Father() {
    		System.out.println("Father() - 无参构造被执行");
    	}
    	
    	public Father(int a) {
    		this.field = a;
    		System.out.println("Father(int a) - 一参构造被执行");
    	}
    	
    }
    
    class Son extends Father{
    	
    	public Son() {
    		//super();
    		System.out.println("Son() - 无参构造被执行");
    	}
    	
    	public Son(int b) {
    		super(b);
    		System.out.println("Son(int b) - 一参构造被执行");
    	}
    	
    	public Son(double c) {
    		super(1);
    		System.out.println("Son(double c) - 一参构造被执行");
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    6.8 this与super

    在这里插入图片描述

    运行结果:

    ​ A-无参构造
    ​ B-无参构造
    ​ B-有参构造

    this或super使用在构造方法中时,都要求在首行。
    当子类构造中使用了this()或this(实参),即不可再同时书写super()或super(实参),会由this()指向z构造方法完成super()调用。

    package com.qfedu.extendsTest;
    
    //调用父类的构造方法
    //1. 创建子类对象时 默认调用父类 的无参构造器,除非 调用有参的super
    
    public class Pig  extends  Animal{
    
        String weight;
    
        //无参构造器
        public Pig() {
            super();//默认有
            System.out.println("pig的无参构造器。。。。。");
        }
    
        public  Pig(int age,String sex,String weight) {
            //super(age,sex); //调用 父类 的有参,如果不写。默认是super();
            this();
            this.weight = weight;
        }
    
        public static void main(String[] args) {
            //Pig pig = new Pig();
            Pig pig1 = new Pig(1,"公","300斤");
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    七、多态【重点】

    7.1 生活中的人物视角

    生活中,不同人物角色看待同一个对象的视角不同,关注点也不相同。

    在这里插入图片描述

    7.2 生活中的多态

    在这里插入图片描述

    生活中的多态是指“客观事物在人脑中的主观反应”。

    主观意识上的类别与客观存在的对象具有“is a”关系时,即形成多态。

    7.3 程序中的多态

    概念: 父类引用指向子类对象,从而产生多种形态。

    在这里插入图片描述

    二者具有直接或间接的继承关系时,父类引用可指向子类对象,即形成多态。

    父类引用仅可调用父类所声明的属性和方法,不可调用子类独有的属性和方法。

    7.4 多态中的方法重写

    思考:如果子类中重写了父类中的方法,以父类类型引用调用此方法时,优先执行父类中的方法还是子类中的方法?

    实际运行过程中,依旧遵循重写原则,如果子类重写了父类中的方法,执行子类中重写后的方法,否则执行父类中的方法。

    7.5 多态的应用

    方法重载可以解决接收不同对象参数的问题,但其缺点也比较明显。

    • 首先,随着子类的增加,Master类需要继续提供大量的方法重载,多次修改并重新编译源文件。
    • 其次,每一个feed方法与某一种具体类型形成了密不可分的关系,耦合太高。

    场景一: 使方法参数的类型更为宽泛。

    场景二:使用父类作为方法返回值实现多态,使方法可以返回不同子类对象。

    package com.qfedu.extendsTest;
    
    import java.io.DataOutput;
    import java.io.File;
    import java.lang.reflect.AnnotatedArrayType;
    
    //1  写一个方法,传入 子类的对象    输出 各个子类的品种
    
    public class Test1 {
    
        public static void main(String[] args) {
    
            //1 创建一个实例
            Test1 test1 = new Test1();
    
            //2. 子类 dog
            //Dog dog = new Dog();
            //1定义体现: 父类类型   对象名  = new 子类();
            Animal animal1 = new Dog();
            animal1.breed="狗";
            test1.printBreed(animal1);
            animal1.eat();
    
            //2. 子类 dog
            //Cat cat = new Cat();
            Animal animal2 = new Cat();
            animal2.breed="猫";
            test1.printBreed(animal2);
            animal2.eat();
            //......
    
            //测试多态做为返回值
            Animal animal = test1.getAnimal();
            Dog dog = (Dog)animal;
            //Cat cat = (Cat)animal;  //转换错误 里边放的是Dog
    
            System.out.println(animal.breed);
    
            //
            System.out.println((dog instanceof Animal));
            System.out.println((animal2 instanceof  Animal));
            //System.out.println((test1 instanceof  Animal));
    
        }
    
        public  void printBreed(Animal animal) {
            System.out.println(animal.breed);
        }
    
        public  Animal getAnimal() {
            Animal animal = new Dog();
    
            return  animal;
    
        }
    
      /*  //1 Dog
        public  void printBreed(Dog dog) {
            System.out.println(dog.breed);
        }
        //2. Cat
        public  void printBreed(Cat cat) {
            System.out.println(cat.breed);
        }
        //3.Bread
        public  void printBreed(Bread bread) {
            System.out.println(bread.breed);
        }
        //4.Fish
        public  void printBreed(Fish fish) {
            System.out.println(fish.breed);
        }
        //5.Pig
        public  void printBreed(Pig pig) {
            System.out.println(pig.breed);
        }
    */
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    八、装箱、拆箱

    8.1 向上转型(装箱)

    在这里插入图片描述

    父类引用中保存真实子类对象,称为向上转型(即多态核心概念)

    注意: 仅可调用Animal中所声明的属性和方法。

    8.2 向下转型(拆箱)

    在这里插入图片描述

    将父类引用中的真实子类对象,强转回子类本身类型,称为向下转型

    注意:只有转换回子类真实类型,才可调用子类独有的属性和方法。

    8.3 类型转换异常

    在这里插入图片描述

    向下转型时,如果父类引用中的子类对象类型和目标类型不匹配,则会发生类型转换异常。

    8.4 instance of关键字

    向下转型前,应判断引用中的对象真实类型,保证类型转换的正确性。

    语法: 父类引用 instance of 类型 //返回boolean类型结果

    在这里插入图片描述

  • 相关阅读:
    python自动解析301、302重定向链接
    leetcode每日一题复盘(11.6~11.12)
    分支结构相关
    20多年前微软曾计划收购,任天堂嘲讽道:“笑死我了”
    eax和ax、ah、al的区别简介
    .NET 7 RC1 正式发布
    RHCE---作业3
    微服务 - Redis缓存 · 数据结构 · 持久化 · 分布式 · 高并发
    spring boot +Scheduled 动态定时任务配置
    【业务功能109】微服务-springcloud-springboot-Skywalking-链路追踪-监控
  • 原文地址:https://blog.csdn.net/LCHONSEONE/article/details/127585203