Java三大特性---封装、继承、多态

Java三大特性—封装、继承、多态

一、封装

学完之前的内容,我们一般不会在意属性的修饰符对吧。顶多写个public 修饰一下,但绝大多数都是默认的。但是不推荐大家这么做,为什么?我们来看下面
Dog dog = new Dog();
dog.health =-99999;
在这里插入图片描述
考虑到安全和权限的问题,属性不能让你随意赋值和更改。所以,引入封装。
封装的概念:
在这里插入图片描述
举个例子:就是生活中的快递包装盒,为了保护隐私安全。
具体步骤:
在这里插入图片描述
代码实现

public class Pet {					//创建Pet类,下面全都改为private 修饰的属性
    private String name;
    private String petType;
    private int healthValue;
    private String gender;
    private int intimacy;

    public void introduce(){
        System.out.println("我的名字叫"+this.getName()+",健康值为:"+this.getHealthValue()+",和主人的亲密度为"+this.getIntimacy()+",我的性别是"+this.getGender());
    }

    public String getName() {				//这些就是getter方法
        return name;
    }

    public void setName(String name) {		//这些就是setter方法,快捷键【Alt+Insert】
        this.name = name;
    }

    public String getPetType() {
        return petType;
    }

    public void setPetType(String petType) {
        this.petType = petType;
    }

    public int getHealthValue() {
        return healthValue;
    }

    public void setHealthValue(int healthValue) {				//定义规范
        if(healthValue<0||healthValue>100){
            System.out.println("输入不合法");
            this.healthValue = 60;
        }else {
            this.healthValue = healthValue;
        }
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        if(null==gender ||"公".equals(gender)){
            this.gender = "公";
        }else {
            this.gender = gender;
        }
    }

    public int getIntimacy() {
        return intimacy;
    }

    public void setIntimacy(int intimacy) {
        if(intimacy<0||intimacy>100){
            System.out.println("输入不合法");
            intimacy = 20;
        }
        this.intimacy = intimacy;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Pet pet = new Pet();
        System.out.println("请输入宠物的名字:");
        String name =sc.next();
        pet.setName(name);
        System.out.println("请选择宠物的类型:(1.狗狗 2.企鹅)");         //写在setter外面的
        int type =sc.nextInt();
        if(type==1){
            pet.setPetType("狗狗");
        }else {
            pet.setPetType("企鹅");
        }
        System.out.println("请选择"+pet.petType+"的性别:1.Q仔2.Q妹");
        int genderChoice = sc.nextInt();
        if(genderChoice==1){
            pet.setGender("Q仔");
        }else {
            pet.setGender("Q妹");
        }
        System.out.println("请输入"+pet.getPetType()+"的健康值");      //写在setter里面的
        pet.setHealthValue(sc.nextInt());

        System.out.println("请输入"+pet.getPetType()+"的亲密度");
        pet.setIntimacy(sc.nextInt());

        pet.introduce();
    }
}

代码虽然看上去有点多,其实很简单,就是几个属性,加一堆getter,setter方法。

然后就是包,注意package 包名; 全部小写,要写在代码的第一行
在这里插入图片描述
为什么要引入包这个概念,注意看前一章,修饰符的权限。
当然要引入包的话,要用关键字import 包名.类名或者import 包名.*,这个写在package下面
这个之前写Scanner的时候也有注意到吗

二、继承

在Java中,我们使用extends关键字来表示继承关系
形如:
class A{
属性
方法…
}
class B extends A{
属性
方法…
}
我们称A为B的父类,B为A的子类。
那我们为什么要使用继承呢
在这里插入图片描述
把一些公共的代码提取出来,形成父类,特有的作为子类,这样方便代码的修改和重复代码的创建。
这里注意一下一个类只能继承一个父类,但是一个父类可以有多个子类,这个很好理解吧。
在这里插入图片描述
这里要注意两点:
1:super和之前讲的this差不多一个是指父类,一个是指本类(当前对象)。
2:继承就是子类拥有父类的所有东西,至于被private修饰的属性不能被访问,其实只是隐藏了,后面讲反射可以进行访问,还有就是static(静态变量:类变量),它是属于这个类本身的,不属于单个对象,所以也不可以被访问。
继承条件下的构造方法
在这里插入图片描述
这里可以看一看前面转载的一片构造器,静态方法,执行顺序那篇文章。

最后我们通过一个例子来讲一下继承

/**
 * @Author shall潇
 * @Date 2021/1/19
 * @Description
 */
 //Car类
class Car {
    private int site = 4;  //座位数
    Car(){
        System.out.println ("载客量是"+site+"人");
    }
    public void setSite(int site){
        this.site = site;
    }
    void print(){
        System.out.print("载客量是"+site+"人");
    }

    public static void main(String[] args) {
        Bus bus = new Bus(20);
        bus.print();
    }
}
//Bus类继承Car类
class Bus extends Car{
    Bus(int site){
        setSite(site);
    }
}

结果显示
在这里插入图片描述
第一个4人是先调用了父类的构造器,但是并没有用到参数20,而是使用了父类本身的默认值
第二个20人是调用了父类的print的方法,这个时候用到参数20

三、多态

多态核心其实就是重载(override)和重写(overload)
多态的四种表现形式:重载,重写,抽象类,接口

1.重载

在一个类中(其实这个不是必要的,当没有子类时就必须要这个条件),相同的方法名,参数列表不同。和其他东西无关。它是根据传入的参数类型,个数自动进行匹配不同的方法。
【特殊的:在子类中,也可以实现父类的方法重载】

【我们来举个特殊的例子,正规的我就不举例子了,大家可以自己试一下】
父类:Pet,父类中方法:getPet方法
在这里插入图片描述
子类:Cat
在这里插入图片描述
注意看子类中这两个方法前面的标志,第一个没有重写标志,但是没有报错,说明它就是重载,第二个则有。
和父类方法名相同,参数列表不同,但是尽管方法在不同的类中,它也是重载。

2.重写

要在不同的类中,一般在子类中重新改写父类方法。方法名不变,参数列表没变,只是方法内部改变了。

【重载规则】

方法名相同
参数列表相同
返回值类型相同或者是其子类
访问权限不能严于父类
父类的静态方法不能被子类覆盖为非静态方法,父类的非静态方法不能被子类覆盖为静态方法
子类可以定义与父类同名的静态方法,以便在子类中隐藏父类的静态方法(注:静态方法中无法使用super)
父类的私有方法不能被子类覆盖
不能抛出比父类方法更多的异常

【举个例子】
父类,父类方法:show

public class Pet {
    private String name;
    private int health;
    private int love;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHealth() {
        return health;
    }

    public void setHealth(int health) {
        this.health = health;
    }

    public int getLove() {
        return love;
    }

    public void setLove(int love) {
        this.love = love;
    }

    public String show(){		//这里要被重写
        return "我叫:"+this.name+"我的健康值:"+this.health+"爱心值为:"+this.love;
    }
    
    public Pet getPet(){
        return new Pet();//返回一个Pet对象
    }
}

子类,子类方法:show

public class Cat extends Pet{
    private String strain; 		//多了一个 品种属性

    public String getStrain() {
        return strain;
    }

    public void setStrain(String strain) {
        this.strain = strain;
    }

    public String show(){    	   //方法重写
        String s = super.show();	//先调用父类 的show方法
        return s+"品种为"+this.strain;//再加入自己的属性
    }

    public Pet getPet(String name){
        return null;
    }

    public Pet getPet(){
        return new Pet();
    }
}

测试类

public static void main(String[] args) {
        Cat cat = new Cat();
        cat.setName("葡萄");
        cat.setHealth(76);
        cat.setLove(67);
        cat.setStrain("暹罗猫");

        System.out.println(cat.show());

结果显示
在这里插入图片描述
既然我们可以重写自己定义的方法,那么可不可以重写Java的方法?
当然是可以的,例如:object类(它是所有类的父类)里面的toString、equals、getClass、hashcode等方法。
接下来,我们就拿重写equals方法来举例,定义自己的比较标准。
【这里我们定义两个猫如果品种相同就是相同】
子类:Cat
在这里插入图片描述
测试类

Cat cat = new Cat();
cat.setName("葡萄");
cat.setHealth(76);
cat.setLove(67);
cat.setStrain("暹罗猫");

Cat cat1 = new Cat();
cat1.setName("豆豆");
cat1.setHealth(26);
cat1.setLove(37);
cat1.setStrain("暹罗猫");

System.out.println(cat.equals(cat1));

输出结果
在这里插入图片描述
重写完之后,我们正式进入多态
开始之前,我先抛个砖:大盒子能装小东西,小盒子能装大东西吗?用大盒子装舒服还是小盒子舒服?
现在我们要定义一个主人类:Master,主人类中只有带宠物看病这个方法。注意,我们这里写的是宠物,而不是确定的。
Master类

public class Master {
    public void cure(Pet p){		//注意看参数类型
        p.toHospital();				//之前的Pet类中没有这个方法,我们添加一下
    }
}

Pet类

public void toHospital(){
        System.out.println("父类去医院");//当然,子类在重写后,会覆盖掉
}

Cat类

@Override							//重写父类的看病方法
public void toHospital() {
    if(this.getHealth()<50){
        System.out.println("猫咪生病了,建议给猫咪看病");
        setHealth(60);
    }else {
        System.out.println("您的猫咪很健康");
    }
}

测试类

Cat cat1 = new Cat();
cat1.setName("豆豆");
cat1.setHealth(26);
cat1.setLove(37);
cat1.setStrain("暹罗猫");

Master master = new Master();
master.cure(cat1);

结果显示
在这里插入图片描述
看,对于Master来说,不管你是什么猫啊,狗啊,只要继承Pet类,都可以往我这进,只要进来我就带你去看病。

那多态就是这些吗?当然不是
多态:子类对象引用父类类型 Pet p = new Cat();
形如这样的才是真正地运用了多态特性。为什么要这样写呢?我们接着往下看:
其实上面这句话意思是:创建Pet类型的Cat对象,可能大家又要懵了,其实就是上面讲到的拿大箱子装小东西,我们来举个例子
Cat类

public void catchMouse(){
        System.out.println("抓老鼠");		//加了一个子类独有的方法
    }

测试类

Pet p2 = new Cat();
p2.setName("fofo");
p2.setHealth(78);
p2.setLove(56);
((Cat) p2).setStrain("加拿大无毛猫");	//调用子类特有的属性
 ((Cat) p2).catchMouse();			//调用子类特有的方法

输出就是抓老鼠。
我们可以注意到。当我们创建Pet类型的Cat对象时,想要调用Cat类里面独有的方法时,需要强制类型转换。可能大家有疑惑,为什么不直接创建Cat类型的对象,当然是为了思考更直接。我只需要Pet类型,不需要什么猫啊,狗啊,全部都是Pet类型,等到我需要你的特有的方法时,再转换一下类型。

当然如果不是继承关系怎么办?
那么我们通过instanceof关键字来判断是否为继承关系
例如:

if(p2 instanceof Cat)
    ((Cat) p2).catchMouse();

猜你喜欢

转载自blog.csdn.net/qq_43288259/article/details/112799914