Skip to content

封装和继承

重复的代码不要重复编写,抽离出来,然后调用。

封装

封装:把属性私有,隐藏起来,然后把get和set方法公开,让其他类使用。

java
属性私有:将类中的属性都使用 private 修饰 表示此属性只能在本类中访问 其他类无法访问
方法公开:针对每个属性都编写一对公开的方法 分别用于属性的赋值setter 和 取值getter

方法书写格式

java
赋值的方法统一以set开头 加上属性名称 属性名首字母大写

取值的方法统一以get开头 加上属性名称 属性名首字母大写
java

封装思想的体现:

ts
开关盒子的例子,内部电线连接部分进行隐藏,只把插座和开关暴漏出来给客户使用。

1、便于使用者正确使用系统,防止错误修改属性
2、降低了构建大型系统的风险
3、提高程序的可重用性
4、降低程序之间的耦合度
java
高内聚: 本类中的属性和方法应该直接与本类对象,事物产生紧密关联,就是一类的都写在一起,不要把不相关写在一起。(类中main方法本身是一个测试方法,跟类本身没有关联,所以把main方法放在一个单独的测试类中运行。)

低耦合:耦合度表示紧密连接程度,降低耦合度:即表示降低紧密连接程度,提高程序的可扩展性,灵活性。

在类中属性前如果没有写修饰符,会存在一个默认的修饰符,这个修饰符的权限可以让在整个包中的其他类都能访问到。同时 在创建实例的时候默认使用的也是类中的无参构造方法,这个无参构造方法也是默认使用public修饰符,可以在任何地方都能访问到。

java
// com.object.pet/TestPet.java
package com.object.pet;

public class TestPet {
    public static void main(String[] args) {
        // 默认使用的无参构造方法,修饰符是public,在同一个包内可以访问到
        Pet cat = new Pet();
        cat.name = "月月";
        cat.sex = '女';
        cat.health = 100;
        //
        cat.info();
    }
}
java
// com.object.pet/Pet.java
package com.object.pet;

public class Pet {
    // 属性
    String name;
    char sex;
    int health;

    // 方法
    public void info(){
        System.out.println("我家猫猫是" + this.name + " " + this.sex + " " +this.health);
    }
}

这样做有很大的风险,对于Pet.java这个类来说,别人都可以访问自己的属性,并且随意的赋值。于是Pet.java对自己进行封装,通过向外部暴漏相应的方法,让外部调用这些方法来修改响应的值。

封装的示例:

java
// com.object.pet/Pet.java

package com.object.pet;

public class Pet {
    // 属性私有
    private String name;
    private char sex;
    private int health;


    // 方法公开
    public void setHealth(int health) {
        if(health < 0 || health > 100){
            // 设置默认值
            this.health = 60;
            System.out.println("参数设置有误,使用默认健康值:60");
        }else {
            this.health = health;
        }
    }

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

    public void setSex(char sex) {
        if(sex == '雌' || sex == '雄'){
            this.sex = sex;
        }else{
            System.out.println("参数设置有误,使用默认性别:雄");
            this.sex = '雄';
        }
    }

    public String getName() {
        return name;
    }

    public int getHealth() {
        return health;
    }

    public char getSex() {
        return sex;
    }
}
java
// com.object.Pet/TestPet.java

package com.object.pet;

public class TestPet {
    public static void main(String[] args) {
        // 默认使用的无参构造方法,修饰符是public,在同一个包内可以访问到
        Pet cat = new Pet();
        // 设置值
        cat.setHealth(10);
        cat.setName("九月");
        cat.setSex('雌');
        // 获取值
        System.out.println(cat.getName());
        System.out.println(cat.getHealth());
        System.out.println(cat.getSex());
    }
}

访问权限修饰符

image-20250627161343945

public修饰符

ts
在任何地方都可以访问到

private修饰符

ts
只能在本类中访问到

默认不写修饰符

ts
只能在同一个包内才可以访问到,包级别的访问权限。

不在同一个包,使用类中的属性或方法,需要导包。(一般会自动导包 import xxx )

类的访问修饰符

java
类的访问修饰符
	public修饰符:公有访问级别
	默认修饰符(不写):包级私有访问级别

类成员的访问修饰符

类的属性和方法,构造方法都叫做类成员。

类成员:类中的属性、方法、构造方法

类成员的访问权限修饰符:1、private 2、默认不写 3、protected 4、public

java
private 修饰的只允许在同一个类中可以访问到
默认不写 修饰的只允许在同一个包中可以访问到
protected 修饰的只允许在同一个包中可以访问到或在不同包中的子类中可以访问到
public 修饰的在导包后,在任何地方都可以访问到

image-20250628105008953

在一个方法中使用不同包的同名类该如何写

使用包名+类名,称之为:全限定名。

例如

java
package com.atguigu.test5;

// test3包中的D类
import com.object.test3.D;

public class TestD {
    public static void main(String[] args) {
        
        D d1 = new D();
        d1.m1(); // 这里的d1是由test3包中的D类实例化的对象

        // 包名 +  类名 称之为:全限定名
        com.object.test4.D d2 = new com.object.test4.D();
        d2.m1(); // 这里的d2是由test4包中的D类实例化的对象
    }
}

继承

只有符合子类属于父类的关系,才可以使用继承。表示只有子类属于父类这种关系,才可以使用继承设计。

例如:猫猫,狗狗都属于宠物,宠物类就是父类,猫猫狗狗属于子类。

子父类书写原则

java
父类中:书写各个子类共有的属性和方法
    
子类中:书写独有的属性和方法
    
子类可以调用父类中的方法,父类调用不了子类的方法。

Java中只支持单根继承,即一个子类只能有一个直接父类,间接父类没有限制。

继承是实现代码重用的重要手段之一。

使用 extend 关键字,让子类继承父类。

子类继承自父类的属性,可以使用super访问,也可以使用this访问,也可以直接访问。

如果子类中有跟父类重名的属性,this和直接访问,访问的是子类中的,super访问的是父类中的。

示例1:

宠物类(父类)和狗狗类(子类),猫猫类(子类)

java
// com.object.pet/PetTest.java
    
package com.object.pet;
/**
 *  使用此子类继承父类,调用继承自父类的print方法 存在如下两个小问题
 *  1. 宠物信息不完善,父类无法访问子类中的 属性:解决办法:使用子类在测试类中使用子类实例调用子类的方法。
 *  2. 宠物身份不明确,父类无法打印子类中的 name
 */
public class TestPet {
    public static void main(String[] args) {
        Dog dog1 = new Dog();
        dog1.setVariety("金毛");
        dog1.setHealth(99);
        dog1.setName("烈烈");
        dog1.setSex('雄');
        dog1.print();
        System.out.println("*******");

        Cat cat1 = new Cat();
        cat1.setWeight(206);
        cat1.setHealth(98);
        cat1.setName("九月");
        cat1.setSex('雌');
        cat1.print();
        System.out.println("*******");
    }
}
java
// com.object.pet/Pet.java

package com.object.pet;

public class Pet {
    // 属性私有
    private String name;
    private char sex;
    private int health;


    // 方法公开
    public void setHealth(int health) {
        if(health > 0 && health < 100){
            // 设置默认值
            this.health = health;
        }else {
            System.out.println("参数设置有误,使用默认健康值:60");
            this.health = 60;
        }
    }

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

    public void setSex(char sex) {
        if(sex == '雌' || sex == '雄'){
            this.sex = sex;
        }else{
            System.out.println("参数设置有误,使用默认性别:雄");
            this.sex = '雄';
        }
    }

    public String getName() {
        return name;
    }

    public int getHealth() {
        return health;
    }

    public char getSex() {
        return sex;
    }
    // 父类中无法访问子类中的成员
    public void print(){
        System.out.println("宠物名字是"+name);
        System.out.println("宠物健康值是"+health);
        System.out.println("宠物性别是"+sex);
    }
}
java
// com.object.pet/Dog.java

package com.object.pet;

public class Dog extends Pet{
    String variety;

    public String getVariety() {
        return variety;
    }

    public void setVariety(String variety) {
        this.variety = variety;
    }

    public Dog() {

    }
}
java
// com.object.pet/Cat.java

package com.object.pet;

public class Cat extends Pet{
    int weight;

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        if (weight < 0){
            System.out.println("重量输入有误,将使用默认值100g");
            this.weight = 100;
        }else{
            this.weight = weight;
        }
    }

    public Cat() {
    }
}

super关键字

super用于访问父类的信息(属性、方法、构造方法),前提是:必须在访问权限允许的情况下

java
访问父类的构造方法
    super();
	super(name);

访问父类属性
    super.name
访问父类方法
    super.print();

使用super关键字,super代表的是父类的

在子类构造方法中调用且必须是第一句

不可以访问父类中定位为 private的属性和方法

访问父类属性

属性:super.属性名

如果在同包中的父子类,那么属性如果需要被子类访问,属性的访问权限最起码是默认修饰符修饰的,如果是不再同包的父类,属性的访问权限最起码是protected修饰的。

访问父类方法

方法:super.方法名

继承自父类的方法,可以通过this加点访问,也可以通过super加点访问,也可以直接访问。

例如:this.print() 或 super.print() 或 print()

访问父类构造方法

构造方法: super() 无参构造 super(name,age,sex) 有参构造

必须在子类构造方法中的第一句

关于子类访问父类的构造方法:子类的每一个构造方法中,都默认访问(调用)父类的无参构造方法,除非在子类构造方法访问了父类的有参构造方法,则不再访问父类的无参构造。

总结:子类构造方法中必须访问父类的无参构造或者有参构造方法,其中是任意一种而且是必须2选1,不能选0,也不能选2。(因为要为子类的属性创建内存空间)

例子:

java
// 子类的每一个构造方法中,都默认访问(调用)父类的无参构造方法,除非在子类构造方法访问了父类的有参构造方法,则不再访问父类的无参构造
public Dog(){
    super() // 访问默认无参
}

public Dog(String name,char sex,int health,String variety) {
    // 调用父类中有参构造方法
    super(name,sex,health);
    this.variety = variety;
}

// 子类构造方法中必须访问父类的无参构造或者有参构造方法,其中是任意一种而且是必须2选1,不能选0,也不能选2。(因为要为子类的属性创建内存空间)

父类

java
package com.object.pet;

public class Pet {
    // 属性
    protected String name;
    protected char sex;
    public int health;
    // 父类中的无参构造方法
    public Pet(){}
    // 父类的有参构造方法
    public Pet(String name,char sex,int health){
        this.name = name;
        this.sex = sex;
        this.health = health;
    }
    // 父类中的有参构造
    public Pet(int health){
        this.health = health;
    }
    // getter和setter方法
    public void setHealth(int health) {
        if(health > 0 && health < 100){
            // 设置默认值
            this.health = health;
        }else {
            System.out.println("参数设置有误,使用默认健康值:60");
            this.health = 60;
        }
    }

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

    public void setSex(char sex) {
        if(sex == '雌' || sex == '雄'){
            this.sex = sex;
        }else{
            System.out.println("参数设置有误,使用默认性别:雄");
            this.sex = '雄';
        }
    }

    public String getName() {
        return name;
    }

    public int getHealth() {
        return health;
    }

    public char getSex() {
        return sex;
    }
    // 父类中print方法
    public void print(){
        System.out.println("名字:"+name);
        System.out.println("健康值:"+health);
        System.out.println("性别:"+sex);
    }
}

子类

java
package com.object.pet;
/**
 * 前提是:必须在访问权限允许的情况下访问
 * 子类访问父类的属性
 * super.属性
 *
 * 子类访问父类的方法
 * super.方法名()
 *
 * 子类访问父类的构造方法
 * super()或super(name,age,sex)
 */

public class Dog extends Pet{
    String variety;
    // 有参构造
    public Dog(String name,char sex,int health,String variety) {
        // 调用父类中有参构造方法
        super(name,sex,health);
        this.variety = variety;
    }
    // get和set方法
    public String getVariety() {
        return variety;
    }
    public void setVariety(String variety) {
        this.variety = variety;
    }
    // print方法
    public void print(){
        // 调用父类中的方法
        super.print();
        System.out.println("品种:"+this.variety);
    }
}

子类2

java
package com.object.pet;

public class Cat extends Pet{
    int weight;
    // setter 和 getter方法
    public int getWeight() {
        return weight;
    }
    public void setWeight(int weight) {
        if (weight < 0){
            System.out.println("重量输入有误,将使用默认值100g");
            this.weight = 100;
        }else{
            this.weight = weight;
        }
    }
    // 无参构造
    public Cat(String name,char sex,int health,int weight){
        // 调用父类中的构造方法,必须放在第一句
        super(health);
        // 调用父类中的属性
        super.name = name;
        // 调用父类中的方法
        super.setSex(sex);
        this.weight = weight;
    }
    // print 方法
    public void print(){
        // 调用父类中的方法
        super.print();
        System.out.println("体重:" + this.weight);
    }
}

测试类

java
package com.object.pet;

public class TestPet {
    public static void main(String[] args) {
        // 实例化对象
        Dog dog = new Dog("奈奈",'雌',100,"金毛");
        dog.print();

        Cat cat = new Cat("月月",'雌',99,205);
        cat.print();
    }
}

this和super区别

this表示当前对象;

super表示用于访问当前对象中父类的信息,是包含在this对象之内的。

问题

能不能同时在一个构造方法中使用this以及super访问本类以及父类的构造方法?

ts
不能同时访问本类以及父类的构造方法(因为this和super访问构造方法必须放在方法中的第一句,第一句只能有一个)
能够同时访问属性和方法是可以的

子类可以继承哪些内容

ts
可以继承 public 和 protected 修饰的属性和方法,不管子类和父类是否在同一个包里
可以继承 默认权限修饰符 修饰的属性和方法,但子类和父类必须在同一个包里

总结一句话:可以继承父类访问权限允许的属性和方法

子类不能继承哪些内容

ts
不能继承 private修饰的属性和方法
不能继承 子类与父类不在同包使用默认访问权限的成员

继承补充

1.私有的属性和方法以及子类无法访问的属性和方法是无法继承的。

2.创建子类对象并不会创建父类对象但是会执行父类的构造方法 :用于给父类中的属性在子类的对象内存中完成初始化。

3.创建对象必须执行构造方法,但是执行构造方法(调用)不一定要创建对象。