封装和继承

目录

(1)什么封装:

(2)封装的好处: 

(3)private、public、protected的意义:

(4)什么是继承:

(5)什么时候用继承:

(6)继承的特点:

        1、单继承:       

        2、非私有成员变量和成员方法

        3、访问私有变量

(7)构造方法和成员方法的区别:

(8)继承中成员变量和成员方法以及构造方法的访问特点:

(9)方法的重写:


(1)什么封装:

        封装是面向对象编程中的一种重要概念,它是指将数据(属性)和操作数据的方法(行为)封装在一个单独的类中,同时对外部隐藏类的内部细节,只暴露出有限的接口供其他类进行交互。封装使得对象的使用者无需了解类的内部实现细节,只需要通过暴露的接口来使用对象,这样可以降低代码的复杂性,增加代码的可维护性和可复用性。

        在封装中,类将数据成员声明为私有(private),这意味着只有类的内部成员可以直接访问这些数据,而其他类无法直接访问。对外部类而言,私有数据成员是不可见的,只能通过公有的方法(公有接口)来访问和修改数据。

(2)封装的好处: 

  1. 隐藏实现细节:通过封装,类可以隐藏其内部实现细节,只暴露有限的接口给外部,这样可以防止外部类直接访问和修改类的私有数据,从而保护类的数据安全。

  2. 简化接口:封装可以将复杂的实现细节隐藏起来,对外部类提供简单的接口,使得类的使用更加简单和直观。

  3. 提高可维护性:封装可以将类的内部实现和外部接口分离,使得对类的修改不会影响外部类的使用,从而提高代码的可维护性。

  4. 增强代码的复用性:封装可以将类的实现细节封装起来,使得类可以在不同的应用场景中被复用,而不需要重新编写代码。

(3)private、public、protected的意义:

  • private表示私有成员,只能在类的内部访问,其他类无法直接访问。在Java中,可以使用 private 关键字来将类的成员声明为私有的。
public class MyClass {
    private int privateVar;  // 私有成员变量

    private void privateMethod() {  // 私有方法
        // 仅在类的内部可访问
    }
}
  •  public表示公共成员,可以在类的内部和外部直接访问。在Java中,类的成员默认是公共的,如果不想将成员设为公共的,就需要使用其他访问控制修饰符。
public class MyClass {
    public int publicVar;  // 公共成员变量

    public void publicMethod() {  // 公共方法
        // 在类的内部和外部都可以访问
    }
}
  •  protected表示受保护成员,可以在类的内部访问,以及派生类(子类)中访问。在Java中,使用 protected 关键字来将类的成员声明为受保护的。
public class MyClass {
    protected int protectedVar;  // 受保护成员变量

    protected void protectedMethod() {  // 受保护方法
        // 在类的内部和派生类中都可以访问
    }
}

总结:

  1. private:私有成员,只能在类的内部访问。
  2. public:公共成员,可以在类的内部和外部直接访问。
  3. protected:受保护成员,可以在类的内部访问,以及派生类中访问。

        举个例子,其实之前的文章也有!

        假设我们要创建一个简单的汽车类来表示汽车的基本信息,包括品牌、颜色和价格。我们可以使用封装来隐藏汽车类的内部细节,并通过公共接口来访问和修改汽车的属性。 

public class Car {
    private String brand;   // 品牌(私有属性)
    private String color;   // 颜色(私有属性)
    private double price;   // 价格(私有属性)

    // 构造方法
    public Car(String brand, String color, double price) {
        this.brand = brand;
        this.color = color;
        this.price = price;
    }

    // 获取品牌(公共方法)
    public String getBrand() {
        return brand;
    }

    // 获取颜色(公共方法)
    public String getColor() {
        return color;
    }

    // 获取价格(公共方法)
    public double getPrice() {
        return price;
    }

    // 设置价格(公共方法)
    public void setPrice(double price) {
        this.price = price;
    }
}

 (这些方法idea可以生成快捷方式alt+insert)。使用 private 关键字将汽车类的品牌、颜色和价格属性声明为私有的,这样外部的代码无法直接访问这些属性。然后,提供了公共的方法(getter 和 setter 方法)来访问和修改这些属性。

//创建对象这个直接调用构造方法进行赋值
Car car = new Car("Toyota", "Red", 25000.0);
//获取对象的信息调用方法
String brand = car.getBrand();
System.out.println("品牌:" + brand);  // 输出:品牌:Toyota

(4)什么是继承:

        继承是面向对象编程中的一种重要概念,它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法,从而可以在子类中重用父类的功能并添加自己的特定功能。继承是面向对象编程的三大特性之一,另外两个是封装和多态。

        在继承中,子类可以继承父类的所有非私有成员(属性和方法),包括数据成员和成员函数。子类可以直接使用继承自父类的属性和方法,也可以在子类中重写(覆盖)父类的方法以实现特定的行为。

        继承的主要目的是代码重用和层次化组织。通过继承,我们可以将共性的代码放在父类中,减少重复编写相似代码的工作量。同时,继承也使得代码的结构更加清晰,将不同的类组织成一个类的层次结构,提高了代码的可读性和可维护性。

        格式:

class 子类 extends 父类{

}

        举个例子打个比方!

        假设有一个动物园的模拟程序,我们需要在程序中创建各种动物,其中有不同种类的动物,例如狗、猫和鸟等。每种动物都有一些共同的属性和行为,比如它们都有名字和吃食物的行为,但同时也有一些独特的行为,比如狗会汪汪叫,猫会喵喵叫,鸟会飞。

        在这个例子中,我们可以创建一个基类 (也就是父类)Animal 表示所有动物,其中包含共同的属性和方法,然后再创建各个子类继承自 Animal 类,每个子类可以添加自己的特有属性和方法。

// 基类 Animal 表示所有动物
public class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println(name + " is eating.");
    }
}

// 子类 Dog 继承自 Animal
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    public void bark() {
        System.out.println("汪汪!汪汪!");
    }
}

// 子类 Cat 继承自 Animal
public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }

    public void meow() {
        System.out.println("喵喵!喵喵!");
    }
}

// 子类 Bird 继承自 Animal
public class Bird extends Animal {
    public Bird(String name) {
        super(name);
    }

    public void fly() {
        System.out.println(name + " is flying.");
    }
}

        然后我们创建小动物叭!

public class ZooSimulation {
    public static void main(String[] args) {
        Dog dog = new Dog("小黑");
        Cat cat = new Cat("小花");
        Bird bird = new Bird("小鸟");

        dog.eat(); // 小黑 is eating.
        dog.bark(); // 汪汪!汪汪!

        cat.eat(); // 小花 is eating.
        cat.meow(); // 喵喵!喵喵!

        bird.eat(); // 小鸟 is eating.
        bird.fly(); // 小鸟 is flying.
    }
}

        通过继承,我们可以将共同的属性和方法放在基类 Animal 中,减少了重复编写代码的工作量,同时每个子类也可以添加自己特有的行为。这样,我们可以更加方便地创建不同种类的动物,并且让程序更加简洁和易于扩展。

(5)什么时候用继承:

  1. 存在类之间的"是一种"关系:当一个类(子类)是另一个类(父类)的特殊化或具体化时,可以考虑使用继承。例如,狗类是动物类的一种,猫类是动物类的一种,这时候可以将动物类作为父类,而狗类和猫类作为子类,从而实现代码的重用和层次化组织。

  2. 存在共同的属性和方法:当多个类拥有相同的属性和方法时,可以将这些共同的部分抽象出来放在一个父类中,然后让子类继承这些共同的属性和方法。这样可以减少代码的重复,提高代码的可维护性和可读性。(加上一个限制,满足子类是父类的一种,最起码要有关系吧,就比方说一个小狗类,有名字name,有年龄age,一个老师类,也有名字name,有年龄age,要说你定义一个类里面属性有name和age两个属性,其实也没错但是就是觉得有一点怪怪的是叭)

(6)继承的特点:

        1、单继承:       

         java只能单继承,不支持多继承,但是可以多层继承(什么是多层继承,就是子类A继承父类B,而父类B又继承与父类(有点迷哈哈哈,那把它当成爷爷叭)C),画个图叭!

         这样蒋其实A也可继承到C的属性和方法(是这样滴应该)但是举个反例!假设有以下三个类:

好的,让我用一个简单的例子来解释为什么Java只能单继承,如果允许多继承会出现什么问题。

假设有以下三个类:

        1、Animal类:代表动物,具有一个eat()方法。

public class Animal {
    public void eat() {
        System.out.println("Animal is eating");
    }
}

        2、Bird类:代表鸟类,继承自Animal类,并且具有一个fly()方法

public class Bird extends Animal {
    public void fly() {
        System.out.println("Bird is flying");
    }
}

         3、Fish类:代表鱼类,继承自Animal类,并且具有一个swim()方法。

public class Fish extends Animal {
    public void swim() {
        System.out.println("Fish is swimming");
    }
}

        这些没有毛病吧,现在,假设我们希望创建一个新的类,既能够飞行又能够游泳(飞鱼!!!),我们可能会想让这个类同时继承自Bird类和Fish类,从而同时具有fly()方法和swim()方法。

public class FlyingFish extends Bird, Fish {
    // ...
}

        然而,这样的多重继承会带来一些问题:

        1、方法冲突:由于FlyingFish类同时继承自Bird类和Fish类,它可能会继承到两个父类中具有相同方法名的方法(例如fly()和swim()),这样就会产生冲突,不知道该调用哪个父类的方法。

        2、命名冲突:如果多个父类中存在相同名称的成员变量或常量,也会导致命名冲突。

        为了避免上述问题,Java采用了单继承的机制,一个类只能直接继承自一个父类。如果需要多重继承的功能,可以使用接口来实现,通过接口可以使一个类实现多个接口,从而在一定程度上解决了多重继承的问题。但是接口只能定义抽象方法和常量,不能包含成员变量和方法的具体实现,从而遵循了单继承的限制。

        继承体系:

        就单单看应该D来讲,他的父类是B,它可以直接使用B里面非私有成员变量和成员方法,当然D也可以间接的使用A的非私有成员变量和成员方法,这里讲一下虽然B和C的父亲一样,但是D不能用C里面的变量和方法(叔叔不是爸爸,怎么会疼你,是不是乖乖!)

        此外讲一下!如果一个类没有写他继承于谁,只是简简单单的一个独立的类,那么问题来了他有没有父类呐,就比方蒋这个Student类没有说他继承谁

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

        答案是有的!在Java里面,所以的类直接或者间接的继承于object类 

        2、非私有成员变量和成员方法

        当一个子类继承自一个父类时,它继承了父类的所有非私有成员方法和成员变量。子类可以通过继承来直接使用这些成员方法和成员变量,而无需重新定义它们。如下面的代码

//父类
class Parent {
    // 成员变量
    int num = 10;

    // 成员方法
    void display() {
        System.out.println("Parent class method");
    }
}
//子类
class Child extends Parent {
    // 子类可以直接调用父类的成员变量和成员方法
    void show() {
        System.out.println("Child class method");
        System.out.println("Parent class variable num: " + num);
        display();
    }
}

public class Main {
    public static void main(String[] args) {
        Child child = new Child();
        child.show();
    }
}

        Child类继承自Parent类。在Child类的show()方法中,直接调用了父类的成员变量num和成员方法display(),并且可以正常地输出父类的数据和调用父类的方法。那么一个问题来了,怎么可以访问私有变量呐

         3、访问私有变量

        如果父类B中的成员变量是public或protected的,子类A可以直接继承并访问这些成员变量。而且如果父类B中的成员变量是默认访问修饰符(包级私有,即没有明确修饰符)的,子类A可以继承并访问这些成员变量,前提是子类A和父类B在同一个包下。

        但是子类A无法直接继承父类B中的私有成员变量。私有成员变量只能在父类B中被访问和修改,子类A无法直接访问它们。但是子类A可以通过父类B提供的公有方法来间接访问和修改私有成员变量。   

        假设有两个类,一个是动物类(Animal),另一个是类(Dog)。类是动物类的子类,也就是说,类继承了动物类的属性和方法。在动物类中,有一个私有成员变量age表示动物的年龄,以及一个公有方法getAge()用于获取动物的年龄。

class Animal {
    private int age;

    public Animal(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

        在类中,我们可以直接使用继承自父类动物的公有方法getAge()来获取狗的年龄。

class Dog extends Animal {
    private String breed;

    public Dog(int age, String breed) {
        super(age);
        this.breed = breed;
    }

    public String getBreed() {
        return breed;
    }

    public static void main(String[] args) {
        Dog dog = new Dog(3, "金毛");
        System.out.println("狗的年龄:" + dog.getAge());
        System.out.println("狗的品种:" + dog.getBreed());
    }
}

        在上面的例子中,Dog类继承了Animal类,因此它可以直接使用父类Animal中的公有方法getAge()来获取动物的年龄。同时,Dog类也可以定义自己的私有成员变量和方法,比如在上面的例子中,我们定义了一个私有成员变量breed表示狗的品种,以及一个公有方法getBreed()用于获取狗的品种。

        总结:

        首先我们要明白一点父类里面有什么,构造方法和成员变量以及成员方法,然后子类到底可以继承父类的什么呐,是非私有的全部的内容嘛?是私有的就都不可以继承嘛?

        1、构造方法:私有和非私有,不管是什么修饰符,子类都不能继承。(因为构造方法要和类名一致,子类的名字总不能和父类的名字一样叭!)

        2、成员变量:私有和非私有,子类都可以继承下来,但是不可以直接调用(要明白继承和直接调用是不同的意思。上面有例子,是可以通过非私有的方法去进项调用)

        3、成员方法:私有和非私有,如果是私有的子类就不能继承下来,只能继承非私有的

(7)构造方法和成员方法的区别:

        1、构造方法 (Constructor)构造方法是一种特殊类型的方法,用于创建和初始化对象时自动调用的。它的主要目的是初始化对象的成员变量,为对象提供合理的初始状态。在Java中,构造方法的名称与类名相同,没有返回类型(包括void),且不能被直接调用,而是在创建对象时由new关键字隐式调用。每当创建一个新对象时,都会调用该对象的构造方法。如果在类中没有定义构造方法,编译器会默认提供一个无参构造方法。但是,如果在类中定义了自定义构造方法,那么默认的无参构造方法将不再自动生成,需要显式定义。

        2、成员方法 (Instance Method)成员方法是定义在类中的普通方法,用于执行特定的操作和功能。它们必须通过对象来调用,因为它们操作对象的状态或行为。成员方法可以访问对象的成员变量和其他成员方法,并且可以返回一个值(包括void)。成员方法是类的行为,用于操作类的数据和实现类的功能。在Java中,成员方法必须在对象上调用,通过使用点号语法来实现,例如:objectName.methodName()

        总结:

  1. 构造方法用于创建和初始化对象,没有返回类型,对象创建时自动调用,且名称与类名相同。
  2. 成员方法用于执行对象的操作和功能,必须通过对象调用,可以有返回类型,且需要显式调用。

(8)继承中成员变量和成员方法以及构造方法的访问特点:

        1、成员变量:就近原则:谁离我近我用谁

        父类

public class Fu {
    String name="fu";
    
}

        子类

public class Zi extends Fu {
    String name = "Zi";

    public void show() {
        String name = "zishow";
        System.out.println(name);
    }
}

        测试类 

public class test {
    public static void main(String[] args) {
        Zi zi=new Zi();
        zi.show();
    }
}

         调用show方法后会输出哪个name,就近原则:谁离我近我用谁,肯定是zishow,注释后是子类里面的zi,在注释是父类里面的Fu。

        我们修改一下子类:

public class Zi extends Fu {
    String name = "Zi";

    public void show() {
        String name = "zishow";
        //输出局部变量
        System.out.println(name);
        //输出成员变量----->this(方法的调用者)
        System.out.println(this.name);
        //输出父类的成员变量------>super
        System.out.println(super.name);
    }
}

        然后运行test类,下面是输出结果:

         2、成员方法:就近原则:谁离我近我用谁

        person类(父类)

public class person {
    public void eat(){
        System.out.println("吃东西!");
    }
    public void drank(){
        System.out.println("喝水!");
    }

}

      teacher类(子类)

public class teacher extends person {

    public void show(){
        //1
        eat();
        drank();
        //2
        this.eat();
        this.drank();
        //3
        super.eat();
        super.drank();
        /*首先讲一下1和2:其实1也有this,但是可以省略,他们两个是一样的首先在方法的调用者的类里面去找
        eat和drink这两个方法,但是结果里面没有,然后看到他有一个父类就在去他的父类里面找
        然后3呐,就是直接去方法调用者的父类里面找*/
    }

}

        测试类

public class test {
    public static void main(String[] args) {
        teacher t=new teacher();
        t.show();
    }
}

         输出:

         在teacher类里面解释了它如何运行的,这里没有什么区别是因为子类里面没有和父类重名的方法,我们修改一下子类从新测试就可以直观的感觉到。

        子类:

public class teacher extends person {

    public void show(){
        //1
        eat();
        drank();
        //2
        this.eat();
        this.drank();
        //3
        super.eat();
        super.drank();
        /*首先讲一下1和2:其实1也有this,但是可以省略,他们两个是一样的首先在方法的调用者的类里面去找
        eat和drink这两个方法,但是结果里面没有,然后看到他有一个父类就在去他的父类里面找
        然后3呐,就是直接去方法调用者的父类里面找*/
    }
    public void eat() {
        System.out.println("老师吃饭!");
    }
    public void drank(){
        System.out.println("老师喝水!");
    }

}

        测试结果: 

        3、构造方法的访问特点:

        还是那句话,父类的构造方法不会被子类继承,但是可以被调用,另外,子类的所有构造方法默认先访问父类的构造方法中的无参构造,然后才执行自己

        使用super调用父类的构造方法,当用子类的构造方法创建(初始化)一个子类的对象时,子类的构造方法总是先调用父类的某个构造方法,也就是说,如果子类的构造方法没有明显地指明使用父类的哪个构造方法,子类就调用父类的不带参数的构造方法。
        由于子类不继承父类的构造方法,因此,子类在其构造方法中需使用 super 来调用父类的构造方法,而且super必须是子类构造方法中的头一条语句,即如果在子类的构造方法中,没有明显地写出super关键字来调用父类的某个构造方法,那么默认地有:

super();//调用父类的空参构造

super(参数1,参数2,~);//手动调用父类的有参构造

        第一个是默认的,我们没有指明的话就是虚拟机会生成super(),并且在子类构造方法里面的第一行,放在其他位置就会报错,第二个是我们手动指明调用有参数的构造方法。

        嘿嘿嘿,发现一个问题,就是父类里面有的方法,然后子类里面也有,方法名是一样的,这种情况叫什么呐-------->方法的重写

(9)方法的重写:

        方法重写(Method Overriding)是面向对象编程中的一种特性,它允许子类重新定义父类中已经存在的方法,以便在子类中实现特定的功能,同时保留方法的名称和参数列表。 

        1、成员变量的隐藏:

        成员变量的隐藏(Variable Hiding)是指在继承关系中,子类定义了与父类同名的成员变量,从而隐藏了父类中的同名成员变量。当子类中定义了与父类同名的成员变量时,子类对象访问该成员变量时将优先使用子类中的成员变量,而不是父类中的成员变量。这种行为称为成员变量的隐藏。

class Animal {
    public int age = 5;
}

class Dog extends Animal {
    public int age = 3;
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Animal();
        Dog dog = new Dog();

        System.out.println(animal.age); // 输出:5,访问父类中的成员变量
        System.out.println(dog.age);    // 输出:3,访问子类中的成员变量
    }
}

         成员变量的隐藏可以使得子类可以定义自己的成员变量,从而实现对父类成员变量的个性化定制。但是需要注意的是,成员变量的隐藏并不会改变继承关系,子类仍然可以访问父类的成员变量和方法,只是在访问同名成员变量时优先使用自己定义的成员变量。

        2、重写的规则:

        这里就是乱七八糟的,就是用简单的话来讲,重写的方法要和父类的保持一致就啥事没有,一致是指访问权限、方法名字、参数个数,参数类型,返回值类型。

        子类通过方法方法的重写就可以隐藏继承父类的方法,通过重写可以父类的状态和行为转变成自己的状态和行为,举个例子!

        如果父类的方法f()可以被子类继承,子类就有权重写 f(),一旦子类重写了父类的方法 f(),就隐藏了继承的方法 fo),那么子类对象调用方法 f()一定调用的是重写方法f();如果子类没有重写,而是继承了父类的方法 f(),那么子类创建的对象当然可以调用 f()方法,只不过方法 f()产生的行为和父类的相同而已。
        重写方法既可以操作继承的成员变量、调用继承的方法,也可以操作子类新声明的成员变量、调用新定义的其他方法,但无法操作被子类隐藏的成员变量和方法。如果子类想使用被隐藏的方法或成员变量,必须使用关键字 super。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值