第12篇:Java 的访问修饰符(public、protected、private)、封装、继承

简介: 🍀public: 在所有类中都是可见的🍀protected: 仅在自己的包中、自己的子类中可见🍀package-private(没有修饰符): 仅在自己的包中可见🍀private: 仅在自己的类中可见

一、访问控制修饰符

🍀 Access level modifiers determine whether other classes can use a particular field or invoke a particular method.
访问级别修饰符决定其他类是否可以使用特定成员变量或调用特定成员方法方法。

Java 中有 4 个级别的访问控制:
🍀public: 在所有类中都是可见的
🍀protected: 仅在自己的中、自己的子类中可见
🍀package-private(没有修饰符): 仅在自己的中可见
🍀private: 仅在自己的中可见

修饰符 Class Package Subclass World
public 🌼 🌼 🌼 🌼
protected 🌼 🌼 🌼
package-private 🌼 🌼
private 🌼

---
🍀 这四个访问控制修饰符可以修饰类的成员【eg:成员变量、成员方法、嵌套类(Nested Class)】
🍀 只有 publicpackage-private(没有修饰符)可以修饰顶级类(Top-level Class)【顶级类可以有多个,但被 public 修饰的顶级类只能有一个】

public class Person {
   public class Fahter {
       class Son {
           protected class Grandson {
               private class Dog {

               }
           }
       }
   }
}
上面代码中的 Person 就是顶级类,Person 类(顶级类)只能被 public 修饰、或没有访问修饰符

🍀 访问修饰符不能修饰局部类(Local Class)、局部变量

二、封装(Encapsulation)

🌻 类中的成员变量私有化(private
🌻 提供公共的(public)方法【Getter 和 Setter】让外界操纵成员变量

public class Person {
    // 成员变量私有化
    private String name;
    private int age;

    /* 提供公共的(public)方法(Getter 和 Setter)让外界操纵私有的属性 */
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

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

    public void setAge(int age) {
        this.age = age;
    }
}
public class Main {
    public static void main(String[] args) {
        Person p = new Person();

        /* 通过公共的 Getter/Setter 方法操作成员变量 */

        p.setName("张浩男");
        p.setAge(11);

        System.out.println(p.getName());
        System.out.println(p.getAge());
    }
}

🌻 封装避免外界直接修改属性(而是通过 Setter 方法修改属性),把实现细节封装起来;Setter 可对数据进行验证,保证数据安全合理

三、继承(Inheritance)

(1) 引出继承

学生类:👨‍🎓

public class Student {
    private String name;
    private int age;
    private double score;
    private String gender;
}

员工类:👨‍💻

public class Employee {
    private String name;
    private int age;
    private String gender;
    private double salary;
}
🌻 上面代码中的员工类和学生类都有 name、age 和 gender 属性,员工类和学生类唯一不同的属性是 salary 💴 和 score 💯
🌻 可以把 name、age 和 gender 等三个属性也抽取在一个类( Person)中,把 name、age 和 gender 作为 Person 类的属性。然后学生类和员工类 继承 Person 类。这样学生类和员工类也拥有了 Person 类的 name、age 和 gender 等三个属性,而学生类和员工类中可编写它们独有的属性。

人类【包含 name、age 和 gender 三个属性(这三个属性是员工类和学生类也共有的)】👶

public class Person {
    private String name;
    private int age;
    private String gender;
}

学生类【独有的属性只有 score】👨‍🎓

public class Student {
    private double score;
}

员工类【独有的属性只有 salary】👨‍✈️

public class Student {
    private double salary;
}
💚 Person 类拥有 Student 类和 Employee 类共有的属性(name、age、gender)
💚 可使用 extends 关键字把 Person 类和 Student 类、把 Person 类和 Employee 类产生关联(让 Student 类和 Employee 类中也拥有 Person 类中所拥有的属性)

(2) 继承介绍

💮 The idea of inheritance(继承) is simple but powerful: When you want to create a new class and there is already a class that includes some of the code that you want, you can derive(产生、获得) your new class from the existing class. In doing this, you can reuse the fields and methods of the existing class without having to write them yourself.
💮 继承思想简单,却强大:当你想要创建一个新的类的时候。如果有一个已存在的类,该类中包含你的新类中所需要的代码。你可以从已存在的类中产生你的新类。这样做的话,你就可以重复使用已存在的类中的成员变量和成员方法,而无需自己重新写。

🌷 A subclass(子类) inherits all the members (fields, methods, and nested classes) from its superclass(父类、超类). Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass.
🌷 子类继承了父类(或超类)中的所有成员(成员变量、成员方法和嵌套类)。构造方法不是成员,所以构造方法不会被子类继承,但父类(或超类)的构造方法可以被子类调用。


继承可实现代码的复用。当多个类中存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法。然后所有的子类不需要重新定义这些属性和方法,只需要通过 extends 关键字来继承父类即可。
在这里插入图片描述

public class Person {
    private String name;
    private int age;
    private String gender;
}
// Student 类继承 Person 类
public class Student extends Person {
    private double score;
}
// Employee 类继承 Person 类
public class Employee extends Person {
    private double salary;
}
🌺 Person 可叫做超类、父类、基类
🌺 Student 和 Employee 可叫做子类或派生类

(3) 继承细节

🌾 ① 子类继承了父类的成员变量和成员方法后,非私有的(publicprotectedpackage-private)属性和方法可以在子类直接访问。私有的属性和方法子类不能够直接访问,可通过非私有的方法间接访问。
父类 Father:

/**
 * 父类
 */
public class Father {
    public String name = "父类 name";
    protected String age = "父类 age";
    String money = "父类 money";
    // 被 private 修饰的属性无法被子类直接访问到
    private String hobby = "父类 hobby";

    public String getHobbyByPublic() {
        return hobby + "_ByPublic";
    }

    protected String getHobbyByProtected() {
        return hobby + "_ByProtected";
    }

    String getHobbyByPackagePrivate() {
        return hobby + "_ByPackagePrivate";
    }
}

子类 Son 继承 Father:

/**
 * 子类
 */
public class Son extends Father {
    public static void main(String[] args) {
        Son son = new Son();
        son.printFatherClassFields();
    }

    private void printFatherClassFields() {
        // output: 父类 name
        System.out.println(name);
        // output: 父类 age
        System.out.println(age);
        // output: 父类 money
        System.out.println(money);

        // 无法访问到父类被 private 关键字修饰的属性
        // System.out.println(hobby); // ERROR

        // 可通过父类的非私有的方法间接访问到父类被 private 关键字修饰的属性
        // output: 父类 hobby_ByPublic
        System.out.println(getHobbyByPublic());
        // output: 父类 hobby_ByProtected
        System.out.println(getHobbyByProtected());
        // output: 父类 hobby_ByPackagePrivate
        System.out.println(getHobbyByPackagePrivate());
    }
}

在这里插入图片描述

🌾 ② 实例化子类的时候,先调用父类的构造器完成父类的初始化,后调用子类的构造器完成子类的初始化 【“父子”,“父子”,先初始化“父”,后初始化“子”】

/**
 * 父类
 */
public class Father {
    public Father() { // 父类构造器
        System.out.println("1.public Father() 构造器");
    }
}
/**
 * 子类
 */
public class Son extends Father {
    public Son() { // 子类构造器
        System.out.println("2.public Son() 构造器");
    }

    public static void main(String[] args) {
        new Son();
        /*
            output:
                1.public Father() 构造器
                2.public Son() 构造器
         */
    }
}

🌾 ③ 创建子类对象的时候,不管使用子类的哪个构造器,默认情况下都会先去调用父类的无参构造器。如果父类没有提供无参构造器,则子类的构造器中必须用 super 关键字去指定使用父类的哪个构造器。否则,编译无法通过。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

🌾 ④ 子类可通过 super(参数列表) 显示调用父类的某个构造器

🌾 ⑤ super 使用的时候必须放在构造器第一行,且 super 只能在构造器中使用
在这里插入图片描述

🌾 ⑥ super() this() 都只能放在构造器的第一行,所以这两个方法不能在一个构造器中同时存在

🌾 ⑦ Java 中所有的类都有一个共同的父类 Object;Java 中所有的类都是 Object 类的子类;Object类是所有类的基类】

public class Father {
    
    public static void main(String[] args) {
        // output: class java.lang.Object
        // Father 类继承 Object 类
        System.out.println(Father.class.getSuperclass());
    }
    
}

🌾 ⑧ 父类构造器的调用不仅限于直接父类,将会一直往上追溯,直到 Object 类

public class Grandpa {

    public Grandpa() {
        System.out.println("1. class Grandpa - 构造器");
    }

}
public class Father  extends Grandpa{

    public Father() {
        System.out.println("2. class Father  extends Grandpa - 构造器");
    }

}
public class Son extends Father {

    public Son() {
        System.out.println("3. class Son extends Father - 构造器");
    }

}
public class Grandson extends Son {

    public Grandson() {
        System.out.println("4. class Grandson extends Father - 构造器");
    }

    public static void main(String[] args) {
        new Grandson();
    }

}
output:
        1. class Grandpa - 构造器
        2. class Father  extends Grandpa - 构造器
        3. class Son extends Father - 构造器
        4. class Grandson extends Father - 构造器

在这里插入图片描述

🌾 ⑨ Java 中是单继承机制(子类最多只能继承一个直接父类)
在这里插入图片描述

思考:如何让 A 类继承 B 类和 C 类 ?

A extends B;B extends C
public class C {
   public String candy = "candy";
}
public class B extends C {
    public String boy = "boy";
}
public class A extends B {
    public static void main(String[] args) {
        A a = new A();
        a.test();
    }

    private void test() {
        // boy
        System.out.println(boy);
        // candy
        System.out.println(candy);
    }
}

在这里插入图片描述

bye-bye! 下篇文章分析类之间产生继承关系后的内存布局...

若文章中发现错误,请不吝赐教

相关文章
|
2天前
|
运维 NoSQL Java
Serverless 应用引擎产品使用之在函数计算上部署Java服务并访问阿里云MongoDB如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
9 0
|
6天前
|
安全 Java
Java基础&面向对象&继承&抽象类
Java基础&面向对象&继承&抽象类
|
6天前
|
Java
【Java基础】详解面向对象特性(诸如继承、重载、重写等等)
【Java基础】详解面向对象特性(诸如继承、重载、重写等等)
10 0
|
12天前
|
安全 Java API
java借助代理ip,解决访问api频繁导致ip被禁的问题
java借助代理ip,解决访问api频繁导致ip被禁的问题
|
14天前
|
存储 NoSQL Java
探索Java分布式锁:在高并发环境下的同步访问实现与优化
【4月更文挑战第17天】Java分布式锁是解决高并发下数据一致性问题的关键技术,通过Redis、ZooKeeper、数据库等方式实现。它确保多节点共享资源时的同步访问,防止数据不一致。优化策略包括锁超时重试、续期、公平性和性能优化。合理设计分布式锁对支撑大规模分布式系统至关重要。
|
15天前
|
SQL 缓存 Java
Java数据库连接池:优化数据库访问性能
【4月更文挑战第16天】本文探讨了Java数据库连接池的重要性和优势,它能减少延迟、提高效率并增强系统的可伸缩性和稳定性。通过选择如Apache DBCP、C3P0或HikariCP等连接池技术,并进行正确配置和集成,开发者可以优化数据库访问性能。此外,批处理、缓存、索引优化和SQL调整也是提升性能的有效手段。掌握数据库连接池的使用是优化Java企业级应用的关键。
Java中访问修饰符public、private、protect、default范围
Java中访问修饰符public、private、protect、default范围
|
4天前
|
设计模式 安全 Java
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
|
1天前
|
消息中间件 监控 安全
【JAVAEE学习】探究Java中多线程的使用和重点及考点
【JAVAEE学习】探究Java中多线程的使用和重点及考点
|
1天前
|
安全 Java 开发者
构建高效微服务架构:后端开发的新范式Java中的多线程并发编程实践
【4月更文挑战第29天】在数字化转型的浪潮中,微服务架构已成为软件开发的一大趋势。它通过解耦复杂系统、提升可伸缩性和促进敏捷开发来满足现代企业不断变化的业务需求。本文将深入探讨微服务的核心概念、设计原则以及如何利用最新的后端技术栈构建和部署高效的微服务架构。我们将分析微服务带来的挑战,包括服务治理、数据一致性和网络延迟问题,并讨论相应的解决方案。通过实际案例分析和最佳实践的分享,旨在为后端开发者提供一套实施微服务的全面指导。 【4月更文挑战第29天】在现代软件开发中,多线程技术是提高程序性能和响应能力的重要手段。本文通过介绍Java语言的多线程机制,探讨了如何有效地实现线程同步和通信,以及如