背景
并发编程学习中,对于局部变量是否是线程安全,进行分情况讨论的时候,涉及到了访问修饰符的影响范围,对于其中的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变量在序列化时不会被保存,反序列化时会恢复为默认值(如null、0等)。
- 变量:
- 示例:
class MyClass implements Serializable { private String name; private transient int age; // 不会被序列化 // 构造函数、getter 和 setter 方法 }
总结
理解这些修饰符的定义和区别有助于你更好地设计和实现Java程序,确保代码的安全性、可维护性和性能。选择合适的修饰符可以提高代码的质量,并使你的程序更加健壮和高效。