一文搞定Java访问控制符public、private、protected、默认的区别

 更新时间:2026年07月13日 11:02:43   作者:Seal^_^  
在Java编程语言中有四种权限访问控制符,这四种访问权限的控制符能够控制类中成员的可见性,这篇文章主要介绍了Java访问控制符public、private、protected、默认区别的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

在 Java 中,访问控制符(Access Modifiers)是面向对象封装特性的核心体现。很多初学者甚至工作一段时间的开发者,对这四个级别的权限区分仍然模糊。本文将通过表格、流程图、代码示例,帮你彻底理清 publicprivateprotected 和默认(包级私有)的区别。

1. 先看结论(速记版)

访问修饰符同类同包子类(不同包)任何位置
private
默认(无修饰符)
protected
public

一句话总结:
private < 默认 < protected < public
权限依次放宽,private 最严,public 最宽

2. 流程图:访问权限判断规则

3. 四种访问权限详解

3.1 private:类的私密空间

只能在当前类内部访问,这是封装性最强的级别。

public class Person {
    private int age;          // 私有成员
    
    private void secret() {   // 私有方法
        System.out.println("这是秘密");
    }
    
    public void show() {
        System.out.println(age);  // ✅ 同类中可访问
        secret();                  // ✅ 同类中可访问
    }
}

public class Test {
    public static void main(String[] args) {
        Person p = new Person();
        // p.age = 10;     ❌ 编译错误
        // p.secret();     ❌ 编译错误
    }
}

使用场景:隐藏内部实现细节,如成员变量、工具方法。

3.2 默认(package-private):包级私有

不加任何修饰符,只能在同一个包内访问。

// 文件:com/example/Person.java
package com.example;

class Person {              // 默认修饰符
    String name;            // 默认修饰符
    
    void sayHello() {       // 默认修饰符
        System.out.println("Hello");
    }
}
// 文件:com/example/TestSamePackage.java
package com.example;

public class TestSamePackage {
    public static void main(String[] args) {
        Person p = new Person();   // ✅ 同包可访问
        p.name = "Alice";           // ✅ 同包可访问
        p.sayHello();               // ✅ 同包可访问
    }
}
// 文件:com/other/TestDifferentPackage.java
package com.other;
import com.example.Person;

public class TestDifferentPackage {
    public static void main(String[] args) {
        Person p = new Person();   // ❌ 编译错误(类不可见)
    }
}

使用场景:包内部协作的工具类或辅助类。

3.3 protected:继承的桥梁

同包可访问 + 不同包的子类可访问(注意:不同包的非子类不能访问)。

// 文件:com/example/Animal.java
package com.example;

public class Animal {
    protected String name;
    
    protected void eat() {
        System.out.println("吃东西");
    }
}
// 文件:com/example/TestSamePackage.java
package com.example;

public class TestSamePackage {
    public static void main(String[] args) {
        Animal a = new Animal();
        a.name = "Tom";    // ✅ 同包可访问
        a.eat();            // ✅ 同包可访问
    }
}
// 文件:com/other/Dog.java(不同包,但继承 Animal)
package com.other;
import com.example.Animal;

public class Dog extends Animal {
    public void test() {
        name = "旺财";   // ✅ 子类可访问 protected 成员
        eat();            // ✅ 子类可访问 protected 方法
    }
}
// 文件:com/other/TestNotSubclass.java
package com.other;
import com.example.Animal;

public class TestNotSubclass {
    public static void main(String[] args) {
        Animal a = new Animal();
        // a.name = "Jerry";   ❌ 不同包且非子类,不可访问
        // a.eat();            ❌ 编译错误
    }
}

关键点protected 允许不同包的子类访问继承来的 protected 成员,但不能通过父类实例直接访问。

// 不同包子类中的特殊规则
package com.other;
import com.example.Animal;

public class Cat extends Animal {
    public void test() {
        name = "Kitty";        // ✅ 自己的继承成员
        eat();                  // ✅ 自己的继承成员
        
        Animal a = new Animal();
        // a.name = "Test";    ❌ 不能通过父类对象访问
    }
}

使用场景:父类允许子类重写或使用的核心方法/属性。

3.4 public:完全公开

任何地方都可以访问

public class Utils {
    public static final double PI = 3.14159;
    
    public void printMessage() {
        System.out.println("公开方法");
    }
}

// 任何包、任何类中都可以访问

使用场景:对外暴露的 API、常量、工具方法。

4. 横向对比:同一个类中能否访问?

public class Demo {
    private   int a = 1;
              int b = 2;   // 默认
    protected int c = 3;
    public    int d = 4;
    
    public void test() {
        System.out.println(a); // ✅ private 可访问
        System.out.println(b); // ✅ 默认可访问
        System.out.println(c); // ✅ protected 可访问
        System.out.println(d); // ✅ public 可访问
    }
}

5. 类级别的访问限制

注意顶层类(非内部类)只能用 public 或默认修饰符,不能用 privateprotected

public class PublicClass {}     // ✅ 正确
class DefaultClass {}           // ✅ 正确
// private class PrivateClass {}   ❌ 编译错误
// protected class ProtectedClass {} ❌ 编译错误

内部类则可以使用所有四种修饰符。

6. 继承与方法重写时的规则

子类重写父类方法时,访问权限不能比父类更严格

class Father {
    protected void method1() {}
    public void method2() {}
}

class Son extends Father {
    @Override
    public void method1() {}   // ✅ protected → public 放宽权限
    
    @Override
    // protected void method2() {}   ❌ public → protected 收窄权限,编译错误
}

原则:只能放大,不能缩小(父类 public → 子类 public;父类 protected → 子类 publicprotected

7. 总结对比表(包含继承关系)

修饰符同类同包子类(同包)子类(不同包)全局
private
默认
protected
public

注意:默认权限下,同包的子类可以访问,但不同包的子类不能访问。

8. 记忆口诀

私有一个类,默认一个包
保护包加子,公开全世界
继承重写要注意,权限只能放不能缩

9. 思考题(检验是否真的懂了)

package packageA;
public class A {
    private   void m1() {}
              void m2() {}
    protected void m3() {}
    public    void m4() {}
}

package packageA;
public class B extends A {
    // 问:B 中可以访问 A 的哪些方法?
}

package packageB;
import packageA.A;
public class C extends A {
    // 问:C 中可以访问 A 的哪些方法?
}

package packageB;
public class D {
    A a = new A();
    // 问:D 中可以访问 A 的哪些方法?
}

答案

  • B(同包继承):m2、m3、m4
  • C(不同包继承):m3、m4(注意不能通过 superthis 访问 m2)
  • D(不同包非继承):只有 m4

总结

到此这篇关于Java访问控制符public、private、protected、默认的区别的文章就介绍到这了,更多相关Java访问控制符public、private、protected内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot配置log4j输出日志的案例讲解

    SpringBoot配置log4j输出日志的案例讲解

    这篇文章主要介绍了SpringBoot配置log4j输出日志的案例讲解,springboot框架中默认使用logback进行日志输出,当然它也可以配置其它的日志框架,需要的朋友可以参考下
    2022-11-11
  • JavaSE反射与动态代理详细代码示例

    JavaSE反射与动态代理详细代码示例

    Java反射和动态代理是Java中两个强大的特性,它们允许程序在运行时动态地获取和操作类、方法、字段等信息,以及创建代理对象来实现AOP等功能,这篇文章主要介绍了JavaSE反射与动态代理的相关资料,需要的朋友可以参考下
    2026-04-04
  • Java中ThreadLocal共享变量的使用

    Java中ThreadLocal共享变量的使用

    java.lang.ThreadLocal该类提供了线程局部变量,用于在当前线程中共享数据,本文主要介绍了Java中ThreadLocal共享变量的使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • java 中数据库连接的JDBC和驱动程序的深入分析

    java 中数据库连接的JDBC和驱动程序的深入分析

    这篇文章主要介绍了java 中数据库连接的JDBC和驱动程序的深入分析的相关资料,需要的朋友可以参考下
    2017-04-04
  • AQS加锁机制Synchronized相似点详解

    AQS加锁机制Synchronized相似点详解

    这篇文章主要为大家介绍了AQS加锁机制Synchronized相似点详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • 基于python locust库实现性能测试

    基于python locust库实现性能测试

    这篇文章主要介绍了基于python locust库实现性能测试,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • Java基础语法之对象的比较方式

    Java基础语法之对象的比较方式

    文章介绍了Java中自定义类类型的比较大小的三种方式:覆写基类的equals方法、基于Comparable接口的比较、基于Comparator接口自定义比较器的比较,每种方式都有其适用场景和局限性
    2026-02-02
  • Java 阻塞队列BlockingQueue详解

    Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下
    2022-06-06
  • Java map.getOrDefault()方法的用法详解

    Java map.getOrDefault()方法的用法详解

    这篇文章主要介绍了Java map.getOrDefault()方法的用法详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Java Clone深拷贝与浅拷贝的两种实现方法

    Java Clone深拷贝与浅拷贝的两种实现方法

    今天小编就为大家分享一篇关于Java Clone深拷贝与浅拷贝的两种实现方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10

最新评论