Java static 关键字总结
static 关键字的作用
static 可以用于修饰变量,方法,类和代码块。通过 static 声明的成员属于类本身,而不是类的任何特定对象。无论创建多少类的实例,静态成员都只有一份拷贝。
static 修饰变量
static 全局变量
static 可以修饰全局变量,被修饰的变量称为静态变量或者类变量,静态变量属于类而非类的实例。所有实例共享同一个静态变量,也就是说,当某个实例修改了静态变量的值,这个修改会反映到其他所有实例上。
class MyClass {
static int count = 0; // 静态变量
// 每次构造MyClass,都会在静态变量中累加数值
MyClass() {
count++;
}
static int getCount() {
return count;
}
}
public class Test {
public static void main(String[] args) {
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
System.out.println(MyClass.getCount()); // 输出 2
}
}
static 局部变量
static 不能修饰局部变量。
static 修饰方法
static 可以修饰方法,被修饰的方法称为静态方法,静态方法属于类,而不属于类的任何特定实例。这意味着可以不创建类的实例而直接调用静态方法。静态方法只能直接访问类的静态变量和静态方法。
class MyClass {
static int count = 0;
static void increment() {
count++;
}
}
public class Test {
public static void main(String[] args) {
// 直接使用类名调用方法,而不需要创建类实例
MyClass.increment();
System.out.println(MyClass.count); // 输出 1
}
}
static 方法的继承关系
static 方法继承的关键点:
- 静态方法不能被覆盖:当一个子类有与父类同名的静态方法时,该方法在子类中不是覆盖父类方法,而是隐藏了父类的同名静态方法。
- 方法调用与类型相关:静态方法的调用取决于它们被调用时的对象类型(声明类型)而非实际对象的类。也就是说,静态方法的行为不依赖于对象的实例,而是与类相关。
class Parent {
static void show() {
System.out.println("Parent's show()");
}
}
class Child extends Parent {
static void show() {
System.out.println("Child's show()");
}
}
public class Test {
public static void main(String[] args) {
Parent parent = new Parent();
Parent child = new Child();
parent.show(); // 输出 "Parent's show()"
child.show(); // 也输出 "Parent's show()",因为静态方法的调用取决于声明的类型,而不是实际的类型,child 声明的类型为 Parent。
Child child2 = new Child();
child2.show(); // 输出 "Child's show()",因为静态方法的调用取决于声明的类型,child2 声明的类型为 Child。
Child.show(); // 输出 "Child's show()",直接通过子类名称调用
}
}
static 修饰代码块
static 可以修饰代码块,修饰的代码块称为静态代码块,静态代码块只能在全局作用域,无法修饰方法内部的代码块。
public class MyClass {
static int age;
static String name;
// 静态代码块
static {
System.out.println("静态代码块执行");
age = 20;
name = "Java";
}
// 构造方法
public MyClass() {
System.out.println("构造方法执行");
}
public static void main(String[] args) {
MyClass obj1 = new MyClass(); // 第一次触发静态代码块和构造方法
MyClass obj2 = new MyClass(); // 只触发构造方法
}
}
静态代码块的用途
初始化静态变量
public class MyClass {
static int age;
sttaic {
age = 20;
}
}
执行只需要进行一次的操作,例如:配置文件的读取。
public class MyClass {
private static Properties properties = new Properties();
static {
try (FileInputStream input = new FileInputStream("config.properties")) {
properties.load(input);
} catch (IOException e) {
e.printStackTrace();
}
}
}
静态代码块的执行时机和执行顺序
执行时机
- 静态代码块只在类被加载到 JVM 时执行一次,
- 与实例初始化块不同,无论创建多少对象实例,静态代码块只执行一次。
执行顺序 - 静态代码块的执行优先于实例初始化块和构造方法。
- 如果类中有多个静态代码块,它们按照在代码中的顺序执行。
public class TestStaticBlock {
static {
// 这个静态代码块只在类第一次被加载到JVM时执行
System.out.println("静态代码块1执行了!"); //顺序一
}
static {
// 这个静态代码块只在类第一次被加载到JVM时执行
System.out.println("静态代码块2执行了!"); //顺序二
}
public TestStaticBlock() {
System.out.println("构造函数执行了!"); //顺序四,五
}
public static void main(String[] args) {
System.out.println("主函数开始执行"); //顺序三
// 创建TestStaticBlock的第一个实例
TestStaticBlock t1 = new TestStaticBlock();
// 创建TestStaticBlock的第二个实例
TestStaticBlock t2 = new TestStaticBlock();
System.out.println("主函数执行结束"); //顺序六
}
}
//输出结果:
// 静态代码块1执行了!
// 静态代码块2执行了!
// 主函数开始执行
// 构造函数执行了!
// 构造函数执行了!
// 主函数执行结束
static 修饰类
static 关键字不能用于修饰顶层类(外部类)。static 关键字主要用于修饰内部类。当把一个内部类声明为 static,它就成为了一个静态内部类,这意味着可以不必实例化外部类就能创建该内部类的实例。
static 修饰内部类:
package com.example.demo;
public class OuterClass {
private static String outerField = "外部类的静态字段";
// 静态内部类
static class StaticInnerClass {
private String staticInnerField = "静态内部类的字段";
public void display() {
// 静态内部类可以访问外部类的静态成员
System.out.println(outerField);
System.out.println(staticInnerField);
}
}
// 非静态内部类
class InnerClass {
private String innerField = "内部类的字段";
public void display() {
System.out.println(outerField);
System.out.println(innerField);
}
}
public static void main(String[] args) {
// 无需外部类实例,直接创建静态内部类实例
StaticInnerClass staticInner = new OuterClass.StaticInnerClass();
staticInner.display();
// 创建外部类实例,然后创建内部类实例
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass inner = outerClass.new InnerClass();
inner.display();
}
}
// 输出结果:
// 外部类的静态字段
// 静态内部类的字段
// 外部类的静态字段
// 内部类的字段
外部类和内部类的静态代码块执行顺序
- 当外部类和内部类都定义了静态代码块时,会先执行外部类的静态代码块,再执行内部类的静态代码块
public class OuterClass {
static {
System.out.println("OuterClass.staticBlock");
}
// 非静态内部类
class InnerClass {
static {
System.out.println("InnerClass.staticBlock");
}
public void display() {
System.out.println("InnerClass.display()");
}
}
public static void main(String[] args) {
// 创建外部类实例,然后创建内部类实例
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass inner = outerClass.new InnerClass();
inner.display();
}
}
// 输出结果
// OuterClass.staticBlock
// InnerClass.staticBlock
// InnerClass.display()
- 外部类和内部静态类都定义了静态代码块,也是县知县外部类的静态代码块,再执行内部类的静态代码快
public class OuterClass {
static {
System.out.println("OuterClass.staticBlock");
}
// 静态内部类
static class StaticInnerClass {
static {
System.out.println("StaticInnerClass.staticBlock");
}
public void display() {
System.out.println("StaticInnerClass.display()");
}
}
public static void main(String[] args) {
// 无需外部类实例,直接创建静态内部类实例
StaticInnerClass staticInner = new OuterClass.StaticInnerClass();
staticInner.display();
}
}
// 输出结果
//OuterClass.staticBlock
//StaticInnerClass.staticBlock
//StaticInnerClass.display()

浙公网安备 33010602011771号