Java中有多少个非访问修饰符?

Java中有多少个非访问修饰符?

在 Java 中,非访问修饰符是指除了 public、private 和 protected 以外的修饰符。Java 中共有多少个非访问修饰符呢?我们来一一看看。

1. static

static 表示静态的。它可以修饰变量、方法和内部类。

修饰变量时,该变量变成了类变量,即不属于任何一个对象,而是属于类的本身。被该变量赋值后,就可以在任何地方通过类名直接调用。

public class Example {

static int count = 0; // 类变量

int id; // 实例变量

Example() {

count++;

id = count;

}

}

public class Test {

public static void main(String[] args) {

Example e1 = new Example();

System.out.println(e1.id); // 1

Example e2 = new Example();

System.out.println(e2.id); // 2

System.out.println(Example.count); // 2

}

}

修饰方法时,该方法变成了类方法,即不属于任何一个对象,而是属于类的本身。被该方法调用时,不需要先创建对象,在调用时直接使用类名即可。

public class Example {

static void sayHello() {

System.out.println("Hello");

}

}

public class Test {

public static void main(String[] args) {

Example.sayHello(); // Hello

}

}

修饰内部类时,该内部类变成了静态内部类,即不属于任何一个外部类的对象,而是属于外部类本身。

public class Example {

static class Inner {

void sayHello() {

System.out.println("Hello");

}

}

}

public class Test {

public static void main(String[] args) {

Example.Inner i = new Example.Inner();

i.sayHello(); // Hello

}

}

2. final

final 表示最终的、不可变的。

修饰变量时,该变量成为了常量,一经赋值后就不可再修改。

public class Example {

final int id = 1; // 常量

}

public class Test {

public static void main(String[] args) {

Example e = new Example();

System.out.println(e.id); // 1

e.id = 2; // 编译错误

}

}

修饰方法时,该方法表示不能被重写。

public class Example {

final void sayHello() {

System.out.println("Hello");

}

}

public class Test extends Example {

void sayHello() { // 编译错误

System.out.println("Hi");

}

}

修饰类时,该类表示不能被继承。

final public class Example {

// ...

}

public class Test extends Example { // 编译错误

// ...

}

3. abstract

abstract 表示抽象的。它可以修饰类、方法。

修饰类时,该类表示抽象类,即不能被实例化的类,只能被继承,其子类必须实现抽象类中的抽象方法。

abstract public class Example {

abstract void sayHello();

}

public class Test extends Example {

void sayHello() {

System.out.println("Hello");

}

}

修饰方法时,该方法表示抽象方法,即没有方法体的方法,只有声明,子类必须实现该方法。

public class Example {

abstract void sayHello();

}

public class Test extends Example {

void sayHello() {

System.out.println("Hello");

}

}

4. synchronized

synchronized 表示同步的。它可以修饰方法和代码块。

修饰方法时,该方法表示同步方法,即在一个线程访问该方法时,其他线程必须等待,直到该方法执行完毕后才能访问。

public class Example {

synchronized void sayHello() {

System.out.println("Hello");

}

}

public class Test {

public static void main(String[] args) {

Example e = new Example();

new Thread(() -> e.sayHello()).start();

new Thread(() -> e.sayHello()).start();

new Thread(() -> e.sayHello()).start();

}

}

修饰代码块时,该代码块表示同步代码块,在该代码块内的同步部分只能由一个线程访问,其他线程必须等待。

public class Example {

void method() {

synchronized (this) {

// ...

}

}

}

public class Test {

public static void main(String[] args) {

Example e = new Example();

new Thread(() -> e.method()).start();

new Thread(() -> e.method()).start();

new Thread(() -> e.method()).start();

}

}

5. volatile

volatile 表示易失的。它可以修饰变量。

修饰变量时,该变量表示易失变量,即多线程并发模型下可以保证其内存可见性。

public class Example {

volatile int count = 0;

}

public class Test {

public static void main(String[] args) {

Example e = new Example();

new Thread(() -> {

for (int i = 0; i < 1000000; i++) {

e.count++;

}

}).start();

new Thread(() -> {

for (int i = 0; i < 1000000; i++) {

e.count++;

}

}).start();

try {

Thread.sleep(1000);

} catch (InterruptedException ex) {}

System.out.println(e.count); // 可能是 2000000,也可能小于 2000000

}

}

在上面的代码中,如果 count 变量没有被 volatile 修饰,那么可能会出现 e.count 小于 2000000 的情况。

6. transient

transient 表示短暂的。它可以修饰变量。

修饰变量时,该变量表示短暂变量,即在对象序列化时不会存储该变量的值。

import java.io.*;

public class Example implements Serializable {

transient int id = 1;

}

public class Test {

public static void main(String[] args) {

Example e = new Example();

try {

ObjectOutputStream out = new ObjectOutputStream(

new FileOutputStream("test.txt")

);

out.writeObject(e);

out.close();

ObjectInputStream in = new ObjectInputStream(

new FileInputStream("test.txt")

);

Example e2 = (Example) in.readObject();

System.out.println(e2.id); // 0

in.close();

} catch (Exception ex) {

ex.printStackTrace();

}

}

}

在上面的代码中,变量 id 被 transient 修饰后,在对象序列化后,id 的值变为 0。

7. native

native 表示本地的。它可以修饰方法。

修饰方法时,该方法表示本地方法,即用 C 或 C++ 写的方法,可以通过 Java Native Interface(JNI)在 Java 中调用。

public class Example {

native void sayHello();

}

public class Test {

static {

System.loadLibrary("example");

}

public static void main(String[] args) {

Example e = new Example();

e.sayHello();

}

}

在上面的代码中,通过 Example 类的 native 方法 sayHello(),在 Java 中调用了 C 代码实现的方法。

总结

到这里,我们就看完了 Java 中的 7 个非访问修饰符,包括:

static

final

abstract

synchronized

volatile

transient

native

它们各自有不同的特点和用途,在实际开发中需要根据实际需求选择合适的修饰符。

后端开发标签