Static
静态变量: 使用static修饰的变量称为静态变量,也称为类变量,它属于类本身而不是实例,所有实例共享同一个静态变量的值。可以通过类名直接访问静态变量,无需创建类的实例。
为什么所有实例共享同一个静态变量的值? 静态变量属于类级别的成员。当类被加载到内存中时,静态变量被初始化并分配内存空间。无论创建多少个类的实例,它们都共享相同的静态变量,因为它们都指向同一个内存空间。
线程安全问题: 在多线程环境下,静态变量的共享可能引发线程安全问题。当多个线程同时访问和修改同一个静态变量时,可能会导致数据不一致或不确定的结果。
类加载时机:
- 创建类的实例:当通过
new关键字创建类的实例时,类的静态变量会在实例创建之前加载到内存中。 - 访问静态成员:当直接访问类的静态变量或调用类的静态方法时,类会被加载到内存中,静态变量也会被初始化。
Spring静态变量注入: Spring无法直接给静态变量注入值,因为静态变量在类加载时就已经初始化了。可以通过静态块或静态方法来赋值给静态变量。
public class MyStaticClass {
public static String myStaticVariable;
static {
// 在静态块中初始化静态变量
myStaticVariable = "Initial value";
}
}
@Component
public class MyStaticClass {
public static String myStaticVariable;
@Value("${myStaticVariable}")
public void setMyStaticVariable(String myStaticVariable) {
this.myStaticVariable = myStaticVariable;
}
}
单例模式:
public class Singleton {
private Singleton() {
// 私有构造函数,防止外部实例化
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
静态方法: 使用static修饰的方法称为静态方法,也称为类方法。静态方法属于类本身而不是实例,可以通过类名直接调用,无需创建类的实例。静态方法只能访问静态成员(包括静态变量和静态方法),不能访问非静态成员。
类加载时机: 调用静态方法时会触发类的加载。当Java虚拟机(JVM)执行到静态方法调用的代码时,会首先加载该方法所属的类,然后才能执行对应的静态方法。
非多态: 静态方法不具有多态性。在编译时,编译器根据引用类型来确定调用的静态方法,而不是根据实际运行时的对象类型。因此,无法通过覆盖或子类化来改变静态方法的行为。
class Parent {
static void print() {
System.out.println("Parent's static method");
}
}
class Child extends Parent {
static void print() {
System.out.println("Child's static method");
}
}
public class Main {
public static void main(String[] args) {
Parent parent = new Child();
parent.print(); // 输出 "Parent's static method",而不是 "Child's static method"
}
}
静态代码块: 使用static关键字可以在类中定义静态块,静态块在类加载时执行,用于进行静态成员的初始化操作。静态块在类加载时只执行一次,且先于类的构造方法执行。
静态成员如果没有初始化,值是多少?
- 数值类型(byte、short、int、long、float、double):默认值为0。
- 布尔类型(boolean):默认值为false。
- 字符类型(char):默认值为'\u0000'(空字符)。
- 引用类型(类、接口、数组等):默认值为null。
构造方法、静态代码块等加载顺序:
- 静态代码块
- 构造代码块
- 构造函数
- 普通代码块
继承中代码块执行顺序:
- 父类静态块
- 子类静态块
- 父类代码块
- 父类构造器
- 子类代码块
- 子类构造器
静态内部类: 静态内部类可以用于封装一些与外部类相关但独立于外部类实例的功能。它提供了更好的代码组织和封装性,同时降低了与外部类的耦合度。
public class MainClass {
public static void main(String[] args) {
HelperClass helper = new HelperClass();
helper.doSomething();
}
private static class HelperClass {
public void doSomething() {
System.out.println("Doing something in HelperClass");
}
}
}
通过将HelperClass定义为MainClass的内部类,并将其声明为私有,我们可以实现封装并限制对HelperClass的访问,使其只能在MainClass内部使用。这样可以提高代码的可维护性和安全性。
静态内部类是外部类的一个静态成员,可以通过外部类的类名直接访问,无需创建外部类的实例。
静态内部类可以访问外部类的静态成员,包括私有的静态成员,因为它们在同一个类作用域中。
静态内部类不能直接访问外部类的实例成员,因为它们与外部类的实例无关。如果需要访问外部类的实例成员,可以通过创建外部类的实例来实现。