面向对象的三大特性、方法重写、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;
    }

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;
    }
}
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() +".......");

    }
}

三、继承【重点】

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("动物在睡大觉....");
    }

}

package com.qfedu.extendsTest;

//狗和动物是 is a 的关系
//所以可以存在  继承关系
//  子类  extends  父类

public class Dog extends Animal {

    String furColoer;

    public  void run() {
        System.out.println("狗在溜达。。。。。");
    }

}
package com.qfedu.extendsTest;

public class Bread extends  Animal {
    String furColoer;

    public  void fly() {
        System.out.println("自由的飞......");
    }

}

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);

    }
}

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("狗在睡大觉。。。。");
    }

}

六、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秒");
    }
}

//super关键字
//1. super 访问父类 的方法和属性
//2. super访问属性  如果子类与父类 的属性有重复, 用super来表示父类 的属性
System.out.println("--------------------------------------");
Fish fish = new Fish();
fish.eat();
fish.sleep();
System.out.println(fish.getAge());

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) - 一参构造被执行");
	}
}

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斤");

    }
}

七、多态【重点】

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);
    }
*/
}

八、装箱、拆箱

8.1 向上转型(装箱)

在这里插入图片描述

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

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

8.2 向下转型(拆箱)

在这里插入图片描述

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

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

8.3 类型转换异常

在这里插入图片描述

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

8.4 instance of关键字

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

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

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java.L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值