Java 修饰符
Java 语言提供了很多修饰符,其主要的作用就是为所修饰的代码提供额外的特性, 主要分为以下两类:
- 访问修饰符
- 非访问修饰符
访问修饰符
访问修饰符决定了其他类是否可以使用特定字段或调用特定方法. 它有两个级别的访问控制:
- 在顶层 - 分为 public(公开) 或 package-private(包私有, 无显式修饰符的情况)
- 在成员层 - 分为 public (公开), protected(受保护), private(私有) 或 package-private (包私有, 无显式修饰符的情况)
在顶层(类级别), 如果使用了 public 修饰了一个类, 那么这个类对所有类都是可见的, 如果使用了默认情况(即无修饰符的情况), 那么该类仅能被同一个包下的其他类所访问到.
在成员层(属性, 方法级别), public 与 无修饰符的可见性与顶层意义相同. 但是额外增加 protected 和 private 两种访问修饰符. 其中, protected 控制了成员可以被同一个包下的其他类访问(这点与无修饰符类似) 或者被不同包下的子类(subclass)所访问. 而 private 控制了成员只能被类自身所访问.
由此可见访问修饰符可以有四种情况:
- 无修饰符的 (默认的, 包私有的)
- public (公开的)
- protected (受保护的)
- private (私有的)
其中 protected 和 private 仅用于类成员的访问控制.
下面一表, 用于快速记忆各个修饰符对于成员访问的限制:
修饰符 | 类自身 | 同名包 | 子类 | 全局 |
---|---|---|---|---|
public | 是 | 是 | 是 | 是 |
protected | 是 | 是 | 是 | 否 |
无修饰符 | 是 | 是 | 否 | 否 |
private | 是 | 否 | 否 | 否 |
示例代码:
我们分别创建以下几个类:
//包 modifier //文件: com/yi21/modifier/A.java package com.yi21.modifier; public class A { protected static String name = "Class A"; protected static void hello() { System.out.println("Hello, I'm A."); } } //文件: com/yi21/modifier/B.java package com.yi21.modifier; public class B { private static String name = "Class B"; public static void helloA() { A.hello(); System.out.println(A.name); System.out.println("Hello, I'm " + name); } } //新的包 modifier2 //文件: com/yi21/modifier2/C.java package com.yi21.modifier2; import com.yi21.modifier.*; public class C { public static void helloB() { B.helloA(); System.out.println(A.class); // System.out.println(A.name); } } //文件: com/yi21/modifier2/A2.java package com.yi21.modifier2; import com.yi21.modifier.A; public class A2 extends A { public static void helloPapa() { System.out.println("My Father is " + A.name); } } //入口文件 Yi21Runner.java import com.yi21.modifier2.*; public class Yi21Runner { public static void main(String[] args) { C.helloB(); System.out.println("------- 21yi.com -------"); A2.helloPapa(); } }
最终我们建立了 5 个文件来展示访问修饰符对成员的访问控制.
讲解如下:
- 在包 modifier 下定义了 A 类, A 类为公开否则包 modifier2 下的 A2 无法访问到 A, 也就无法继承 A, A 只提供了两个 proteced 的成员 类变量 name 和静态方法 hello
- 在包 modifier 下定义了 B 类, B 类同样为公开, B 定义了 private 成员 类变量 name, 只能在 B 内部访问, 以及 proteced 的成员 静态方法 helloA, 在 helloA 中调用了同包下的 A 的 protected 的两个成员: 方法 hello 和类变量 name, 并输出了自己的 private 成员, 类变量 name
- 在包 modifier2 下定义了 C 类, C 类调用了 B 类的 helloA 方法, 同时因为 A 类的可访问性, 可以输出 A.class.
- 在包 modifier2 下定义了 A2 类, A2 类继承了 A 类, 因此 A2 类可以在自己的方法里调用 A 类的 protected 属性 name.
- 最后, 通过默认包下, 输出 C.helloB() 和 A2.HelloPapa() .
执行结果如下:
Hello, I'm A. Class A Hello, I'm Class B class com.yi21.modifier.A ------- 21yi.com ------- My Father is Class A
非访问修饰符
非访问修饰符, 言下之意就是不进行访问控制, 对其他方面进修修饰的修饰符, 常见的有以下几种:
static
static 的意思是静态的, 所谓静态就是指类不用初始化成一个对象, 即可调用. static 用于修饰类的各种成员, 包括类的内部类(一种定义在类的内部的类).
用法示例如下:
package com.yi21.modifier; public class StaticDemo { static class Duck { public void hello() { System.out.println("Quak!Quak!Quak!"); } } class Fox { public void hello() { System.out.println("What the fox say?"); } } public static String name = "Class StaticDemo"; public static void hello() { System.out.println("Hello I'm " + name); Duck duck = new Duck(); duck.hello(); StaticDemo demo = new StaticDemo(); Fox fox = demo.new Fox(); fox.hello(); } }
上述代码, 定义了三个 static 成员, 一个静态内部类 Duck, 一个类变量 name, 一个静态方法 hello, 以及定义了一个非静态成员, 类 Fox .
其中在静态方法 hello 中, 调用静态类 Duck 时就不需要初始化类再调用, 而调用非静态类 Fox 时则需要初始化 StaticDemo, 然后通过初始化的实例来使用类 Fox.
执行结果如下:
Hello I'm Class StaticDemo Hello I'm Class StaticDemo Quak!Quak!Quak! What the fox say?
final
final 的意思是最终的, 最终就意味这不可变化, 不可继承:
- 当 final 修饰变量时, 变量变成了常量
- 当 final 修饰了方法, 子类无法重写(override) 父类的方法
- 当 final 修饰了类, 类无法被继承.
示例代码如下:
package com.yi21.modifier; public class FinalDemo { final static String name = "FinalDemo"; static class Bird { final int footNumber() { return 2; } public void hello() { System.out.println("Some bird sounds."); } } final static class Poultry extends Bird { /* 无法覆盖父类 final 方法 int footNumber() { return 3; } */ public void hello() { System.out.println("Some poultry sounds."); } } /* 无法继承 final 类 static class Duck extends Poultry { } */ public static void hello() { //无法修改 name 的值 //name = "OK"; System.out.println(name); Poultry poultry = new Poultry(); System.out.println(poultry.footNumber()); poultry.hello(); } }
上面代码中, 所有被注释的试图修改, 重写, 继承 final 定义的部分, 都会报错.
更多其他的修饰符
除了上述修饰符外, Java 中还存在其他修饰符, 以下是一些举例:
- 线程访问修饰符: Java synchronized 和 volatile 修饰符
- 严格浮点计算修饰符: Java 的 strictfp 修饰符
好了, 以上就是有关 Java 修饰符的全部内容了. 接下来我们讲 Java 中如何声明一个方法