static关键字

发布于:2025-04-20 ⋅ 阅读:(86) ⋅ 点赞:(0)

思维导图:

  

在 Java 中,static 是一个非常重要的关键字,它可以用来修饰类的成员,包括变量、方法、代码块以及内部类。下面为你详细介绍 static 关键字的各种用法和特点。

一.修饰内部类

  静态内部类:当 static 修饰内部类时,这个内部类就成为了静态内部类。静态内部类不依赖于外部类的实例,可以直接创建。它只能访问外部类的静态成员,因为静态内部类在加载时可能还没有创建外部类的实例。

代码示例:

class Outer {
    static int outerStaticVariable = 10;
    int outerInstanceVariable = 20;

    // 静态内部类
    static class StaticInner {
        public void display() {
            // 可以访问外部类的静态成员
            System.out.println("Outer static variable: " + outerStaticVariable);
            // 以下代码会编译报错,因为静态内部类不能访问外部类的实例成员
            // System.out.println("Outer instance variable: " + outerInstanceVariable); 
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // 可以直接创建静态内部类的实例
        Outer.StaticInner inner = new Outer.StaticInner();
        inner.display();
    }
}

说明:

  StaticInner是Outer 类的静态内部类。在 StaticInner 类的 display 方法里,可以访问外部类的静态变量 outerStaticVariable,但不能访问外部类的实例变量 outerInstanceVariable在 Main 类的 main 方法中,可以直接创建 Outer.StaticInner 类的实例,无需先创建 Outer 类的实例。
 

  static关键字不能修饰顶层类(直接定义在包中的类)。

代码示例:

// 以下代码会编译报错,因为 static 不能修饰顶层类
// static class TopLevelClass {
//     public void method() {
//         System.out.println("This is a top - level class.");
//     }
// }

  原因:顶层类代表一个独立的实体,其设计目的是为了被其他类继承或者实例化,从而实现不同的功能。而 static 关键字的作用是将成员和类相关联,而非和类的实例相关联。若将顶层类用 static 修饰,就会违背顶层类的设计初衷,所以 Java 语法不允许使用 static 修饰顶层类。

二.修饰成员变量和成员方法

2.1修饰成员变量

public class StaticTest01 {


    //修饰成员变量,此时是静态变量
    private static int age;
    private static String name;
    private static int number1 = 10;
    
    //实例变量
    private int number2 = 20;



    public static void main(String[] args) {
        StaticTest01.setAge(18);
        StaticTest01.setName("张三");

        //访问成员变量   类名.变量名
        System.out.println(StaticTest01.getAge() + "->" + StaticTest01.getName());

    }
}

2.2修饰成员方法同理

访问方式: 类名.方法名

2.3修饰代码块

public class StaticTest01 {


    private static int number1 = 10;
    private int number2 = 20;

    static {
        System.out.println(number1);  //number1是静态的
//      System.out.println(number2);  //编译错误 静态不能访问实例变量
    }

注意:在实例方法,实例代码块中可以访问类变量,类方法;但是类变量,类方法,静态代码块不可以访问实例方法,实例变量,实例代码块。

原因:

  1. 静态方法/变量/代码块和类强相关;它不依赖于对象,在类加载时,静态方法/变量/代码块就被加载到内存中,无需创建类的实例就能调用。
  2. 实例方法/变量/代码块和实例对象强相关。调用实例方法/变量时,必须通过类的实例来调用,(对象的引用来调用)。

2.4static不能修饰构造方法 

public class StaticTest01 {

//     public static StaticTest01() {
//         static不能修饰构造方法
//     }
}

不能用 static 修饰构造方法的原因

  1. 语义冲突:构造方法的目的是创建并初始化对象,而静态成员是属于类本身,不依赖于实例。如果构造方法被 static 修饰,这就与构造方法创建实例的初衷相违背。因为静态方法可以在没有创建任何实例的情况下被调用,若构造方法是静态的,那么就无法通过它来初始化特定的实例。
  2. 逻辑矛盾:构造方法在对象创建时自动调用,并且与具体的对象实例相关联。而静态方法没有 this 引用,this 引用指向调用该方法的对象实例。如果构造方法是静态的,就不存在 this 引用,也就无法对特定的对象实例进行初始化操作。
  3. 设计原则:从设计角度来看,构造方法和静态方法有着不同的职责。构造方法负责对象的创建和初始化,而静态方法通常用于执行与类相关的通用操作,不涉及特定对象的状态。将两者区分开来可以使代码更加清晰和易于维护。

三.构造方法,静态代码块,普通代码块的执行流程

执行流程

当创建一个类的对象时,执行流程如下:

  1. 先进行类的加载,此时会执行静态代码块。静态代码块在类加载时只执一次。
  2. 创建对象实例,在调用构造方法之前,会先执行实例代码块。
  3. 执行构造方法完成对象的初始化。

代码示例:

public class Parent {

    public Parent() {
        System.out.println("父类构造方法执行");
    }

    {
        System.out.println("父类普通代码块执行");
    }

    static {
        System.out.println("父类静态执行");
    }
}




public class Child extends Parent {
    public Child() {
        System.out.println("子类构造方法执行");
    }

    {
        System.out.println("子类普通代码块执行");
    }

    static {
        System.out.println("子类静态执行");
    }

    public static void main(String[] args) {
        Parent parent = new Child();
        System.out.println("=========证明static修饰的代码只会执行一次============");
        Parent parent2 = new Child();
    }
}

运行结果:

四.static成员的继承

4.1静态成员变量的继承

静态成员变量属于类,而非类的某个实例。当子类继承父类时,会继承父类的静态成员变量。不过,子类和父类实际上共享同一份静态成员变量,这意味着无论通过父类还是子类来访问或修改静态成员变量,操作的都是同一个变量。

代码示例:

class Parent {
    static int staticVariable = 10;
}

class Child extends Parent {
    // 继承了 Parent 类的 staticVariable
}

public class Main {
    public static void main(String[] args) {
        System.out.println(Parent.staticVariable); // 输出 10
        System.out.println(Child.staticVariable);  // 输出 10

        Child.staticVariable = 20;
        System.out.println(Parent.staticVariable); // 输出 20
        System.out.println(Child.staticVariable);  // 输出 20
    }
}

在上述代码中,Child类继承了Parent类的staticVariable 静态成员变量。当通过 Child 类修改staticVariable 的值后,再通过 Parent 类访问该变量,得到的是修改后的值,这表明它们共享同一份静态成员变量。

4.2静态方法的继承

静态方法同样属于类,子类可以继承父类的静态方法。子类可以直接使用父类的静态方法,也可以定义与父类同名的静态方法,不过这并非方法重写(Override),而是方法隐藏(Hide)。方法隐藏是指子类定义了与父类同名、同参数列表的静态方法,此时通过子类调用该方法时,调用的是子类的方法;通过父类调用该方法时,调用的是父类的方法。

代码示例:

class Parent {
    static void staticMethod() {
        System.out.println("Parent's static method");
    }
}

class Child extends Parent {
    static void staticMethod() {
        System.out.println("Child's static method");
    }
}

public class Main {
    public static void main(String[] args) {
        Parent.staticMethod(); // 输出 "Parent's static method"
        Child.staticMethod();  // 输出 "Child's static method"

        Parent parent = new Child();
        parent.staticMethod(); // 输出 "Parent's static method",因为静态方法根据引用类型调用
    }
}

在上述代码中,Child 类定义了与 Parent类同名的静态方法 staticMethod,这是方法隐藏。当通过 Parent 类引用调用 staticMethod 时,调用的是 Parent 类的方法;当通过 Child 类引用调用 staticMethod 时,调用的是 Child 类的方法。
 

总结:

 Java类中包含了成员变量、成员方法、构造方法、初始化块和内部类(包括接口、枚举)5种成员,static关键字可以修饰除了构造方法外的其他4种成员。static关键字修饰的成员被称为类成员。类成员属于整个类,不属于单个对象。 static关键字有一条非常重要的规则,即类成员不能访问实例成员,因为类成员属于类的,类成员的作用域比实例成员的作用域更大,很容易出现类成员初始化完成时,但实例成员还没被初始化,这时如果类成员访问实力成员就会引起大量错误。

 static修饰的部分会和类同时被加载。被static修饰的成员先于对象存在,因此,当一个类加载完毕,即使没有创建对象也可以去访问被static修饰的部分。 静态方法中没有this关键词,因为静态方法是和类同时被加载的,而this是随着对象的创建存在的。静态比对象优先存在。也就是说,静态可以访问静态,但静态不能访问非静态,而非静态可以访问静态。


网站公告

今日签到

点亮在社区的每一天
去签到