访问权限修饰符
在 Java 中,针对类、成员方法和属性提供了四种访问级别,分别是 private
、default
、protected
和 public
-
private
(当前类访问级别):对于私有成员变量和方法,只有在本类中创建该类的对象时,这个对象才能访问自己的私有成员变量和类中的私有方法 -
default
(包访问级别):类的成员变量和方法什么修饰符都没有,又叫包修饰符,只有类本身成员和当前包下类的成员可以访问 -
protected
(子类访问级别):用protected
修饰的成员变量和方法能被该类的成员以及其子类成员访问,还可以被同一个包中的其他类的成员访问 -
public
(公共访问级别):无论访问类和被访问类是否在同一个包中,都可以访问
本类 | 本包 | 子类 | 其他包的类 | |
---|---|---|---|---|
private | √ | |||
默认 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
final
关键字
final
用于修饰类、方法和变量
final
关键字修饰类
final
关键字修饰的类不能被子类继承
- 例如,
String
、System
final
类中的成员方法也默认是 final
修饰
final
类中的变量值是可以改变的
final
关键字修饰方法
final
关键字修饰的成员方法不能被子类重写;不能与 abstract
共存
但是,当父类方法为 private
修饰的 final
方法时,子类中可以出现相同方法名、相同参数列表(类型、个数和顺序)的方法,而不属于方法重写
因为,private
的方法仅本类可见,对于子类而言,是不可见的
final
关键字修饰变量
final
关键字修饰的变量,如果是基本数据类型的变量,则其值一旦在初始化之后便不能更改了,也即是常量
final
关键字修饰的变量,如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象
final
关键字可以修饰局部变量
final
关键字修饰的变量都是常量
不建议修饰引用类型数据,因为,对于引用数据类型,即使加了
final
,仍然可以通过引用修改对象的内部数据,意义不大
public class Test {
final int a = 10;
final String s = new String("123");
public Test() {
// 以下两行均会报错
// 常量,不可修改
this.a++;
// 不可以指向另一个对象
s = new String("abc");
}
}
this
关键字
this
,表示当前对象的一个引用,本质是一个对象
所谓当前对象,指的是调用类中方法或者属性的那个对象
this
只能在方法内部使用,表示对 “调用方法的那个对象” 的引用
每一个普通方法都有一个 this
,谁调用该方法,this
就指向谁
this.属性名 : 表示当前对象自己的属性
this.方法名 : 表示当前对象自己的方法
this
关键字可以调用类的重载构造函数,但是 必须位于构造函数的第一行
this()
可以调用无参构造
public class Person {
String name;
int age;
public Person(int age) {
this.age = age;
}
public Person(String name) {
this(1); // 调用有参构造
this.name = name;
}
}
this
关键字不能用于静态方法和静态代码块
main
方法也是静态的,所以 this
也不能用于 main
方法
public class Person {
String name;
int age;
public static void main(String[] args) {
// 报错
this.name = "鸿蒙";
this.age = 1;
}
}
super
关键字
在继承中,子类的构造函数必须依赖父类提供的构造函数
- 如果父类只有有参构造函数,子类的构造也必须依赖于父类提供的有参构造
super
调用父类的构造函数,必须在构造函数的第一行
super(参数列表)
访问父类的有参构造函数
在子类的方法或者构造器中,可以通过使用 super.属性
的方式来表示调用的是父类中声明的属性;特别是当子类和父类中定义了同名的属性时
在子类的方法或者构造器中,可以通过使用 super.方法名
的方式来表示调用的是父类中声明的方法;特别是当子类和父类中定义了同名的方法时
super
与 this
super()
调用父类的构造函数,必须在构造函数的第一行
this()
调用本类的构造函数,必须在构造函数的第一行
所以,super()
和 this()
不能同时调用构造函数
-
代表对象不同
this
:代表本身调用者这个对象
super
: 代表父类对象的引用 -
使用条件
this
:没有继承也可以使用
super
:只能在继承的条件下才能使用 -
构造方法
this
: 本类的构造
super
: 父类的构造
static
关键字
static
修饰的变量称作静态变量、也叫做类变量
static
修饰的方法称作静态方法、也叫做类方法
被修饰的属性和方法 为本类所有对象共享,也即属于本类
随意修改静态变量的值是有风险的,为了降低风险,可以同时用 final
关键字修饰,即公有静态常量(注意命名的变化):
public final static 变量类型 XXX_YYY_ZZZ = 变量值;
通过类名即可调用静态变量,也可以通过 对象名.静态变量名
调用
因为静态变量被所有的对象所共享,所以在内存中只存在一个副本
当且仅当在类初次加载时,静态变量会被初始化
注意:
static
可以修饰类、成员变量和成员方法
但是static
不能修饰局部变量
实例变量
实例变量声明在一个类中,但是在方法、构造方法和语句块之外
无 static
修饰
无初始化时,具有默认值
实例变量属于该类的对象,必须先产生该类的对象,才能调用实例变量
数值型变量默认为
0
或者0.0
布尔型变量默认为false
引用类型默认值为null
静态变量与实例变量
-
静态变量属于类,该类不需要产生对象,即可通过类名进行调用静态变量;
实例变量属于该类的对象,必须产生该类对象,才能调用实例变量 -
静态变量随着类的加载存在于 方法区中;
实例变量随着对象的建立存在于 堆内存中 -
静态变量在程序开始时创建,在程序结束时销毁;
实例变量在对象创建时创建,在对象被销毁时销毁
静态方法
static
修饰的方法称为静态方法、类方法
静态方法中不能直接访问类的非静态成员变量和非静态成员方法
静态方法中不能使用 this
关键字
通过类名可以调用静态方法,也可以通过 对象名.静态方法名
调用
使用场景:
只需要访问静态成员,不需要访问对象状态,所需参数都由参数列表显式提供
静态代码块
静态代码块在类加载时执行,并且只执行一次
静态代码块和匿名块都在构造函数执行之前执行
静态代码块在类中可以有多个
静态代码块中不能有 this
关键字
volatile
关键字
volatile
修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值;保证变量的可见性。
而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
一个 volatile
对象引用可能是 null
public class MyRunnable implements Runnable {
private volatile boolean active;
public void run() {
active = true;
while (active) { // 第一行
// 代码
}
}
public void stop() {
active = false; // 第二行
}
}
通常情况下,在一个线程调用 run()
方法(在 Runnable
开启的线程),在另一个线程调用 stop()
方法
如果第一行中缓冲区的 active
值被使用,那么在第二行的 active
值为 false
时循环不会停止
但是以上代码中我们使用了 volatile
修饰 active
,所以该循环会停止
因为,volatile
修饰后,active
一旦修改,其他的线程也会收到修改后的值
volatile
的另一个作用是:禁止 volatile
变量与普通变量重排序
重排序:
为了优化程序性能,对原有的指令执行顺序进行优化重新排序;
重排序可能发生在多个阶段,比如编译重排序、CPU重排序
synchronized
修饰符
synchronized
关键字声明的方法同一时间只能被一个线程访问;用于保证多线程的线程安全
synchronized
修饰符可以应用于四个访问修饰符
public synchronized void showDetails(){
.......
}
尽量不要使用 synchronized(String a)
因为 JVM 中,字符串常量池具有缓存功能
:由于字符串常量池的原因不同的变量可能引用着同一个对象,锁不同变量的时候会锁成同一个对象,从而造成意料之外的同步,降低效率
volatile
与 synchronized
volatile
关键字是线程同步的轻量级实现,所以volatile
性能比synchronized
关键字要好;但是volatile
关键字只能用于变量而synchronized
关键字可以修饰方法以及代码块 。volatile
关键字能保证数据的可见性,但不能保证数据的原子性;synchronized
关键字两者都能保证。volatile
关键字主要用于解决变量在多个线程之间的可见性,而synchronized
关键字解决的是多个线程之间访问资源的同步性。