关键字static详解

关键字static详解

参考:[Java之static作用的全方位总结](Java之static作用的全方位总结 - 小勇DW3 - 博客园 (cnblogs.com))

引用其中的一句话:如果别人问你static的作用;如果你说静态修饰 类的属性 和 类的方法 别人认为你是合格的;如果是说 可以构成 静态代码块,那别人认为你还可以; 如果你说可以构成 静态内部类, 那别人认为你不错;如果你说了静态导包,那别人认为你很OK。

1. static方法

static方法称作静态方法,静态方法不依赖于任何对象能够进行访问,所以方法中不能出现this。因为非静态方法和非静态变量(实例变量)是依赖于对象的,所以静态方法不能调用非静态方法和非静态变量。

代码如下:

public class StaticTest {
    public static int id = 123456;
    public String name = "张三";

    public static void method1(){
        System.out.println(id);
        System.out.println(name);//非静态变量存在错误
        method2();//非静态方法,存在错误
    }

    public void method2(){
        System.out.println(id);
        System.out.println(name);
        method1();
    }
}

代码分析:

以上静态方法和变量为method1和id,是不依赖对象而存在的。非静态方法和变量为method2和name,是依赖于对象而存在的。方法method1调用method2和name,是存在错误的。

另外:由于构造方法能够使用super()和this(),所以构造方法不是静态方法。

2. static变量

static变量被称为静态变量,静态变量是不依赖对象的。静态变量是被所有对象共享的,有一个对象的静态变量改变,所有对象的该变量都会改变,存放在方法区中,它当且仅当在类初次加载时会被初始化【加final和不加final的static变量初始化的位置不一样】。非静态变量是跟随对象存在的,不是所有对象共享的,有一个对象的非静态变量改变,所有对象的该变量不会改变。

特点:

  • 静态变量不能出现在构造方法中。因为构造方法是一个非静态方法。
  • 静态变量是被所有对象共享的,有一个对象的静态变量改变,所有对象的该变量都会改变。

3. static代码块

代码块的作用:用来初始化类、对象

static代码块的作用,就是能够优化程序性能。static代码块的位置能够放置在类中的任何地方,类中能够包含多个静态代码块。在类初次被加载的时候,能够按照代码块的顺序执行每个代码块,并且只会执行一次根据class加载原理,每个类加载一次使用,双亲委派机制

初始化顺序:静态代码块>构造代码块>构造函数

代码如下:

public class StaticTest1 {
    private int m;
    private static int kk;
    {
        //构造代码块
        System.out.println("执行构造代码块");
    }
    static {
        //静态代码块:可以存放一些在整个类中都确定需要的变量
        System.out.println("执行静态代码块");
        int kk = 10;
    }

    public StaticTest1() {
    }

    public StaticTest1(int m) {
        this.m = m;
    }

    public boolean isok(){
        //int kk = 10;
        return m>kk;//kk需要在外边定义
        
    }

    public static void main(String[] args) {
        StaticTest1 staticTest1 = new StaticTest1(15);
        System.out.println(staticTest1.isok());
    }
}

在方法isok中,我们判断属性m是否大于10,每次调用isok时,都会生成一个int对象,这样会造成空间浪费。为了让效率和空间存储更好,利用静态代码块在内存中加载一次的机制。

因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

4.静态内部类

首先来讲一些内部类:

静态内部类:在定义内部类的时候,可以在其前面加上一个权限修饰符static,此时这个内部类就变成了静态内部类。静态内部类也叫作嵌套类。

内部类的特点:

  • 静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似。要创建嵌套类的对象,并不需要其外围类的对象。
  • 静态内部类不能使用和访问外部类的非静态变量和方法。
  • 静态内部类可以声明静态成员和非静态成员
  • 访问静态内部类中的静态变量不需要创建对象,创建静态内部类对象不需要外部类对象,

``

public class Outer3 {
    static int a;
    int b;

    public static void test() {
        System.out.println("outer class static function");
    }

    public static void main(String[] args) {
        // new一个外部类
        Outer3 outer3 = new Outer3();
        // 通过外部类的对象new一个非静态的内部类
        InnerClass no_static_inner = outer3.new InnerClass();
        // 调用非静态内部类的方法
        System.out.println(no_static_inner.getKey());

        // 调用静态内部类的静态变量
        System.out.println(Outer3.InnerStaticClass.static_value);
        // 不依赖于外部类实例,直接实例化内部静态类
        Outer3.InnerStaticClass inner = new Outer3.InnerStaticClass();
        // 调用静态内部类的非静态方法
        System.out.println(inner.getValue());
        // 调用内部静态类的静态方法
        System.out.println(Outer3.InnerStaticClass.getMessage());
    }

    private class InnerClass {
        // 只有在静态内部类中才能够声明或定义静态成员
        // private static String tt = "0";
        private int flag = 0;

        public InnerClass() {
            // 三.非静态内部类的非静态成员可以访问外部类的非静态变量和静态变量
            System.out.println("InnerClass create a:" + a);
            System.out.println("InnerClass create b:" + b);
            System.out.println("InnerClass create flag:" + flag);
            //
            System.out.println("InnerClass call outer static function");
            // 调用外部类的静态方法
            test();
        }

        public  String getKey() {
            return "no-static-inner";
        }
    }

    private static class InnerStaticClass {
        // 静态内部类可以有静态成员,而非静态内部类则不能有静态成员。
        private static String static_value = "0";

        private int flag = 0;

        public InnerStaticClass() {
            System.out.println("InnerClass create a:" + a);
            // 静态内部类不能够访问外部类的非静态成员
            // System.out.println("InnerClass create b:" + b);
            System.out.println("InnerStaticClass flag is " + flag);
            System.out.println("InnerStaticClass tt is " + static_value);
        }

        public int getValue() {
            // 静态内部类访问外部类的静态方法
            test();
            return 1;
        }

        public static String getMessage() {
            return "static-inner";
        }
    }

    public Outer3() {
        // new一个非静态的内部类
        InnerClass ic = new InnerClass();
        System.out.println("OuterClass create");
    }

}

5.静态导包

静态导包就是java包的静态导入,这个是JDK1.5中的新特性。

通过import static代替import导入包,具体形式为:import static com.....ClassName.*,导入所有的静态方法。也可以只导入某个静态方法。

好处:简化方法调用,可以不使用类就直接调用方法。

我认为:尽管静态导包能够使方法使用节省代码,但是对于变量和方法的使用失去来源说明,所以我们在使用时,可以少的使用静态导入。尤其是具有同名变量的属性,比如Long和Integer中的MAX_VALUE。

6.注意点:

  1. static关键字不会改变类中成员的访问权限,访问权限由访问权限符public、protected、default和private决定。
  2. 通过this是可以访问静态变量的。尽管静态变量为所有对象共有,但是可以通过某一个对象去调用,尽量不要修改。

执行顺序:

父类静态代码块(静态变量)>子类静态代码块(静态变量),父类构造代码块(成员变量),父类构造方法,子类构造代码块(成员变量),子类构造方法

验证代码:

public class StaticTest2 {

    {
        System.out.println("执行构造代码块");
    }
    public static Class1 c1 = new Class1();
    Class2 c2 = new Class2();

    static {
        System.out.println("执行静态代码块");
    }

    public static void main(String[] args) {
        StaticTest2 staticTest2 = new StaticTest2();
    }
}

class Class1{
    public Class1() {
        System.out.println("静态变量");
    }
}
class Class2{
    public Class2(){
        System.out.println("成员变量");
    }
}

执行结果:

静态变量
执行静态代码块
执行构造代码块
成员变量

再如:

public class StaticTest2 {

    {
        System.out.println("执行构造代码块");
    }
    public static StaticTest2 s2 = new StaticTest2();
    public static Class1 c1 = new Class1();
//    Class2 c2 = new Class2();

    static {
        System.out.println("执行静态代码块");
    }

    public static void main(String[] args) {
        StaticTest2 staticTest2 = new StaticTest2();
    }
}

class Class1{
    {
        System.out.println("执行class1代码块");
    }
    static {
        System.out.println("执行class1静态代码块");
    }

    public Class1() {
        System.out.println("静态变量");
    }
}
class Class2{
    public Class2(){
        System.out.println("成员变量");
    }
}

结果显示:

执行构造代码块
执行class1静态代码块
执行class1代码块
静态变量
执行静态代码块
执行构造代码块

当在本类中加载本类对象,会先加载构造代码块。

posted @   疯狂的豆包  阅读(239)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示