Java语言提供了很多修饰符,主要分为以下两类:
访问控制修饰符
非访问修饰符
访问控制修饰符
private
:私有访问权限,用于修饰类的属性和方法。被private修饰的成员只能在本类中进行访问。- default(默认访问权限,无修饰符):如果一个类中的属性或方法没有显式指定访问修饰符,它将具有默认的访问权限。默认访问权限允许本包中的其他类访问,但不能被其他包的类访问。
protected
:受保护访问权限。被protected修饰的成员可以在本包及不同包的子类中访问。public
:公共访问权限。被public修饰的成员可以在所有类中访问,不论是否在同一包中。
下面通过一张表总结上述的访问控制权限。
综上所述:
可以理解为将整个世界都打包成一块,同时划分为四个层次: 联合国(public)【其他包】、国家(protected)【继承子孙】、洲际(default)【同一包】、个人(private)【当前类】。
联合国制定规则所有人都可以用,国家制定的只有在国家内可以用,各联邦洲因地制宜有制定当地民法,个人制定的就给个人使用。
实例
//创建一个名为Person的类
class Person {
private String name; // 私有属性,只能在本类中访问
String gender; // 默认访问权限,本包中的其他类可以访问
protected int age; // 受保护的属性,本包及子类可以访问
public String address; // 公共属性,所有类都可以访问
// 私有方法,只能在本类中调用
private void printName() {
System.out.println("名称:" + name);
}
// 默认访问权限的方法,本包中的其他类可以调用
void printGender() {
System.out.println("性别:" + gender);
}
// 受保护的方法,本包及子类可以调用
protected void printAge() {
System.out.println("年龄:"+ age);
}
// 公共方法,所有类都可以调用
public void printAddress() {
System.out.println("地址:"+ address);
}
}
//创建另一个名为Student的子类,继承自Person类
class Student extends Person {
public void displayInfo() {
// 在子类中可以访问父类的受保护属性和方法
System.out.println("Student Info:");
printName(); // 调用了父类的私有方法,间接访问了private属性
printGender(); // 调用了父类的默认方法,访问本包中的属性
printAge(); // 调用了父类的受保护方法,访问子类继承的属性
System.out.println("Address: " + address); // 直接访问父类的公共属性
}
}
//主程序入口
public class MyClass {
public static void main(String[] args) {
Student student = new Student();
// 在主程序中无法直接访问Person类的私有属性和方法
// student.name = "Alice"; // 错误!私有属性不能在其他类中直接访问
// student.printName(); // 错误!私有方法不能在其他类中直接调用
// 可以访问默认、受保护和公共属性及方法
student.gender = "Female";
student.age = 18;
student.address = "123 Street";
student.displayInfo();
}
}
非访问修饰符
为了实现一些其他的功能,Java 也提供了许多非访问修饰符。
- static:用来修饰类方法和类变量。通过使用static修饰,可以使得方法或变量与类本身相关联,而不是具体的实例对象。静态方法可以直接通过类名调用,而无需创建实例对象。
- final:用来修饰类、方法和变量。被final修饰的类不能被继承,即不能有子类。被final修饰的方法不能被继承类重新定义,即不能被子类重写。被final修饰的变量为常量,即其值在初始化后不可修改。
- abstract:用来创建抽象类和抽象方法。抽象类是不能被实例化的类,主要用作其他类的基类。抽象方法是没有具体实现的方法,必须在子类中进行重写。
- synchronized:用于多线程环境,用于实现线程安全的同步访问,确保多个线程对同一代码块的串行执行。
- volatile:用于多线程环境,用于声明变量是被多个线程共享的,保证了其在多线程环境下的可见性和有序性。
- transient:用于序列化,表示某个字段不会被持久化存储或网络传输,通常用于敏感信息或与序列化无关的临时数据。
- native:表示方法的实现是由外部的本地语言(如C、C++)提供,用于与操作系统或底层硬件进行交互。
- strictfp:用于浮点数计算,强制按照IEEE 754标准执行,保证浮点计算的结果在不同平台上的一致性。
实例
public class ModifierExample {
// static修饰的变量和方法与类本身关联
public static int staticVariable = 10;
public static void staticMethod() {
System.out.println("这是一种静态方法。");
}
// final修饰的变量为常量,值不可修改
public final int finalVariable = 20;
public final void finalMethod() {
System.out.println("这是最后一种方法。");
}
// abstract修饰的方法没有具体实现,需要在子类中重写
public abstract void abstractMethod();
// synchronized修饰的方法确保多个线程对代码块的串行执行
public synchronized void synchronizedMethod() {
System.out.println("这是一种同步方法。");
}
// volatile修饰的变量被多个线程共享,保证可见性和有序性
public volatile int volatileVariable = 0;
// transient修饰的变量不会被序列化存储或网络传输
public transient String transientVariable;
// native修饰的方法使用外部的本地语言提供的实现
public native void nativeMethod();
// strictfp修饰的方法按照IEEE 754标准执行浮点数计算
public strictfp void strictfpMethod() {
double num1 = 0.1;
double num2 = 0.2;
double result = num1 + num2;
System.out.println("结果:"+ result);
}
}
注意:
abstract修饰的方法所在的类必须声明为抽象类。native修饰的方法通常需要与本地语言进行交互。