java中修饰符的定义,范围,区别,你能说清楚吗?

225 阅读6分钟

背景

并发编程学习中,对于局部变量是否是线程安全,进行分情况讨论的时候,涉及到了访问修饰符的影响范围,对于其中的protected和default的范围和区别,记不太清了,于是进行查询,在此记录

结果

修饰符作用域/行为示例场景
public允许任何类访问API接口、公共库
protected允许同包类和子类访问父类与子类之间的共享成员
默认(无修饰符)只允许同包类访问内部工具类、包内协作
private只允许定义它的类内部访问封装类的内部实现细节
final表示不可改变的状态(类、方法、变量)常量、防止继承或重写
static表示类级别的成员,所有实例共享工具类、配置信息、单例模式
abstract表示抽象类或抽象方法,需要子类实现定义模板方法、框架设计
synchronized确保线程安全,防止多个线程同时执行多线程编程中的同步控制
volatile确保多线程之间的可见性,每次读取都从主内存中读取线程间通信、状态标志
transient标记变量不应被序列化敏感信息、临时状态

Java中的修饰符分为两大类:访问控制修饰符(Access Modifiers)和非访问控制修饰符(Non-Access Modifiers)。每种修饰符都有其特定的用途,用于控制类、方法、变量和构造函数的访问级别和行为。以下是详细的分类和说明:

1. 访问控制修饰符(Access Modifiers)

访问控制修饰符用于定义类、方法、构造函数和变量的访问级别。它们决定了这些成员可以在多大范围内被访问。

1.1 public

  • 定义public是最高级别的访问控制,表示该成员可以被任何其他类访问。
  • 作用域
    • 类:可以被任何其他类访问。
    • 方法/变量:可以被同一包内的类或不同包中的类通过对象引用访问。
  • 示例
    public class MyClass {
        public void myMethod() {
            // 可以被任何地方访问
        }
    }
    

1.2 protected

  • 定义protected允许同包内的类以及子类(即使在不同包中)访问该成员。
  • 作用域
    • 类:不允许使用protected修饰类。
    • 方法/变量:可以被同一包内的类或不同包中的子类访问。
  • 示例
    protected int myVariable;
    protected void myMethod() {
        // 可以被同包内的类或子类访问
    }
    

1.3 默认(无修饰符)

  • 定义:当没有显式指定访问控制修饰符时,默认访问级别(也称为包级私有)适用。这意味着该成员只能在同一包内的类中访问。
  • 作用域
    • 类:可以被同一包内的类访问。
    • 方法/变量:可以被同一包内的类访问。
  • 示例
    class MyClass {
        int myVariable; // 默认访问级别
        void myMethod() {
            // 只能在同一包内访问
        }
    }
    

1.4 private

  • 定义private是最严格的访问控制,表示该成员只能在定义它的类内部访问。
  • 作用域
    • 类:不允许使用private修饰类。
    • 方法/变量:只能在定义它的类内部访问。
  • 示例
    private int myVariable;
    private void myMethod() {
        // 只能在同一个类内访问
    }
    

2. 非访问控制修饰符(Non-Access Modifiers)

非访问控制修饰符用于定义类、方法、变量和其他程序元素的行为,而不是控制它们的访问级别。

2.1 final

  • 定义final修饰符用于表示不可改变的状态。
  • 作用
    • final类不能被继承。
    • 方法final方法不能被子类重写。
    • 变量final变量一旦赋值就不能再改变(常量)。
  • 示例
    final class FinalClass {} // 不能被继承
    
    class MyClass {
        final void myMethod() {
            // 不能被子类重写
        }
    
        final int MY_CONSTANT = 10; // 常量
    }
    

2.2 static

  • 定义static修饰符用于表示类级别的成员,即它们属于类本身而不是类的实例。
  • 作用
    • 变量static变量是类级别的,所有实例共享同一个变量。
    • 方法static方法属于类本身,可以通过类名直接调用,而不需要创建实例。
    • 代码块static代码块在类加载时执行一次。
    • 内部类static内部类是静态嵌套类,不依赖于外部类的实例。
  • 示例
    class MyClass {
        static int sharedCounter = 0; // 类级别的变量
    
        static void myStaticMethod() {
            // 类级别的方法
        }
    
        static {
            // 静态代码块,在类加载时执行一次
        }
    }
    

2.3 abstract

  • 定义abstract修饰符用于表示抽象类或抽象方法。
  • 作用
    • abstract类不能被实例化,必须被继承。抽象类可以包含抽象方法和具体方法。
    • 方法abstract方法没有实现,必须在子类中实现。
  • 示例
    abstract class AbstractClass {
        abstract void myAbstractMethod(); // 没有实现
    
        void myConcreteMethod() {
            // 具体方法
        }
    }
    
    class ConcreteClass extends AbstractClass {
        @Override
        void myAbstractMethod() {
            // 实现抽象方法
        }
    }
    

2.4 synchronized

  • 定义synchronized修饰符用于确保多个线程不会同时执行某个方法或代码块,从而保证线程安全。
  • 作用
    • 方法synchronized方法在每次调用时会自动获取对象锁(实例方法)或类锁(静态方法),并在方法执行完毕后释放锁。
    • 代码块synchronized代码块可以指定一个具体的锁对象。
  • 示例
    class MyClass {
        synchronized void mySynchronizedMethod() {
            // 同步方法
        }
    
        void myMethod() {
            synchronized (this) {
                // 同步代码块
            }
        }
    }
    

2.5 volatile

  • 定义volatile修饰符用于确保多线程环境下的可见性。它告诉JVM,该变量可能会被多个线程并发修改,因此每次读取时都必须从主内存中读取,而不是从线程本地缓存中读取。
  • 作用
    • 变量volatile变量保证了多线程之间的可见性和有序性,但不提供原子性。
  • 示例
    class MyClass {
        volatile boolean flag = false;
    
        void setFlag(boolean value) {
            flag = value;
        }
    
        boolean getFlag() {
            return flag;
        }
    }
    

2.6 transient

  • 定义transient修饰符用于表示该变量不应被序列化。当对象被序列化时,transient变量的值不会被保存到文件中,而是会被忽略。
  • 作用
    • 变量transient变量在序列化时不会被保存,反序列化时会恢复为默认值(如null0等)。
  • 示例
    class MyClass implements Serializable {
        private String name;
        private transient int age; // 不会被序列化
    
        // 构造函数、getter 和 setter 方法
    }
    

总结

理解这些修饰符的定义和区别有助于你更好地设计和实现Java程序,确保代码的安全性、可维护性和性能。选择合适的修饰符可以提高代码的质量,并使你的程序更加健壮和高效。