首页 文章

静态和非静态初始化代码块之间有什么区别

提问于
浏览
304

我的问题是静态关键字的一个特定用法 . 可以使用 static 关键字来覆盖不属于任何函数的类中的代码块 . 例如,以下代码编译:

public class Test {
    private static final int a;    
    static {
        a = 5;
        doSomething(a);
    }
    private static int doSomething(int x) {
        return (x+5);
    }
}

如果你删除 static 关键字,它会抱怨,因为变量 afinal . 但是,可以删除 finalstatic 关键字并使其编译 .

这两种方式让我感到困惑 . 我怎么能有一个不属于任何方法的代码部分?如何调用它?一般来说,这种用法的目的是什么?或者更好,我在哪里可以找到关于此的文档?

8 回答

  • 32

    带有static修饰符的代码块表示类初始值设定项;如果没有静态修饰符,则代码块是实例初始值设定项 .

    类初始化器按照它们被定义的顺序执行(自上而下,就像简单的变量初始化器一样)在加载类时(实际上,当它被解析时,但这是技术性的) .

    实例初始化程序在实例化时定义的顺序执行,紧接在执行构造函数代码之前,在超级构造函数的调用之后立即执行 .

    如果从 int a 中删除 static ,它将成为一个实例变量,您无法从静态初始化程序块访问该变量 . 这将无法使用错误"non-static variable a cannot be referenced from a static context"进行编译 .

    如果还从初始化程序块中删除 static ,则它将成为实例初始化程序,因此在构造时初始化 int a .

  • 367

    Uff! what is static initializer?

    静态初始化程序是java类中的 static {} 代码块,在调用构造函数或main方法之前只运行一次 .

    OK! Tell me more...

    • 是任何java类中的代码块 static { ... } . 并在调用类时由虚拟机执行 .

    • 不支持 return 语句 .

    • 不支持任何参数 .
      支持

    • thissuper .

    Hmm where can I use it?

    可以在任何你觉得好的地方使用:)那么简单 . 但我在大多数情况下都会看到在进行数据库连接,API初始化,日志记录等时使用它 .

    Don't just bark! where is example?

    package com.example.learnjava;
    
    import java.util.ArrayList;
    
    public class Fruit {
    
        static {
            System.out.println("Inside Static Initializer.");
    
            // fruits array
            ArrayList<String> fruits = new ArrayList<>();
            fruits.add("Apple");
            fruits.add("Orange");
            fruits.add("Pear");
    
            // print fruits
            for (String fruit : fruits) {
                System.out.println(fruit);
            }
            System.out.println("End Static Initializer.\n");
        }
    
        public static void main(String[] args) {
            System.out.println("Inside Main Method.");
        }
    }
    

    Output???

    内部静态初始化器 . Apple Orange Pear End静态初始化器 . 内部主要方法 .

    希望这可以帮助!

  • 12

    static 块是"static initializer" .

    在加载类时会自动调用它,并且没有其他方法可以调用它(甚至不能通过Reflection) .

    我个人在编写JNI代码时只使用过它:

    class JNIGlue {
        static {
            System.loadLibrary("foo");
        }
    }
    
  • 6

    这直接来自http://www.programcreek.com/2011/10/java-class-instance-initializers/

    1.执行顺序

    看下面的课,你知道哪一个先被执行吗?

    public class Foo {
    
        //instance variable initializer
        String s = "abc";
    
        //constructor
        public Foo() {
            System.out.println("constructor called");
        }
    
        //static initializer
        static {
            System.out.println("static initializer called");
        }
    
        //instance initializer
        {
            System.out.println("instance initializer called");
        }
    
        public static void main(String[] args) {
            new Foo();
            new Foo();
        }
    }
    

    输出:

    static initializer调用实例初始化程序称为构造函数,称为实例初始化程序,称为构造函数调用

    2. Java实例初始化程序如何工作?

    上面的实例初始化程序包含一个println语句 . 为了理解它是如何工作的,我们可以将其视为变量赋值语句,例如 b = 0 . 这可以让人更明白地理解 .

    代替

    int b = 0 ,你可以写

    int b;
    b = 0;
    

    因此,实例初始值设定项和实例变量初始值设定项几乎相同 .

    3.实例初始化器何时有用?

    实例初始值设定项的使用很少,但如果符合以下情况,它仍然可以作为实例变量初始化程序的有用替代方法:

    • 初始化代码必须处理异常

    • 执行无法用实例变量初始化程序表示的计算 .

    当然,这样的代码可以用构造函数编写 . 但是如果一个类有多个构造函数,则必须在每个构造函数中重复代码 .

    使用实例初始化程序,您只需编写一次代码,无论使用何种构造函数创建对象,都将执行该代码 . (我想这只是一个概念,并没有经常使用 . )

    实例初始化器有用的另一种情况是匿名内部类,它根本不能声明任何构造函数 . (这是放置记录功能的好地方吗?)

    感谢Derhein .

    另请注意,实现接口[1]的匿名类没有构造函数 . 因此,在构造时需要实例初始化程序来执行任何类型的表达式 .

  • 6

    “final”保证必须初始化变量在对象初始化代码结束之前 . 同样,“static final”保证变量将在类初始化代码的末尾初始化 . 从初始化代码中省略“静态”会将其转换为对象初始化代码;因此你的变量不再满足其保证 .

  • 4

    您不会将代码写入需要在程序中的任何位置调用的静态块 . 如果要调用代码的目的,则必须将其放在方法中 .

    您可以编写静态初始化程序块来在加载类时初始化静态变量,但此代码可能更复杂 .

    静态初始化程序块看起来像没有名称,没有参数和没有返回类型的方法 . 因为你从不称它为它不需要名字 . 它被调用的唯一时间是虚拟机加载类时 .

  • 51

    当开发人员使用初始化程序块时,Java编译器会将初始化程序复制到当前类的每个构造函数中 .

    例:

    以下代码:

    class MyClass {
    
        private int myField = 3;
        {
            myField = myField + 2;
            //myField is worth 5 for all instance
        }
    
        public MyClass() {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
        }
    
        public MyClass(int _myParam) {
            if (_myParam > 0) {
                myField = myField * 4;
                //myField is worth 20 for all instance initialized with this construtor
                //if _myParam is greater than 0
            } else {
                myField = myField + 5;
                //myField is worth 10 for all instance initialized with this construtor
                //if _myParam is lower than 0 or if _myParam is worth 0
            }
        }
    
        public void setMyField(int _myField) {
            myField = _myField;
        }
    
    
        public int getMyField() {
            return myField;
        }
    }
    
    public class MainClass{
    
        public static void main(String[] args) {
            MyClass myFirstInstance_ = new MyClass();
            System.out.println(myFirstInstance_.getMyField());//20
            MyClass mySecondInstance_ = new MyClass(1);
            System.out.println(mySecondInstance_.getMyField());//20
            MyClass myThirdInstance_ = new MyClass(-1);
            System.out.println(myThirdInstance_.getMyField());//10
        }
    }
    

    相当于:

    class MyClass {
    
        private int myField = 3;
    
        public MyClass() {
            myField = myField + 2;
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
        }
    
        public MyClass(int _myParam) {
            myField = myField + 2;
            if (_myParam > 0) {
                myField = myField * 4;
                //myField is worth 20 for all instance initialized with this construtor
                //if _myParam is greater than 0
            } else {
                myField = myField + 5;
                //myField is worth 10 for all instance initialized with this construtor
                //if _myParam is lower than 0 or if _myParam is worth 0
            }
        }
    
        public void setMyField(int _myField) {
            myField = _myField;
        }
    
    
        public int getMyField() {
            return myField;
        }
    }
    
    public class MainClass{
    
        public static void main(String[] args) {
            MyClass myFirstInstance_ = new MyClass();
            System.out.println(myFirstInstance_.getMyField());//20
            MyClass mySecondInstance_ = new MyClass(1);
            System.out.println(mySecondInstance_.getMyField());//20
            MyClass myThirdInstance_ = new MyClass(-1);
            System.out.println(myThirdInstance_.getMyField());//10
        }
    }
    

    我希望开发人员能理解我的例子 .

  • 145

    静态代码块可用于实例化或初始化类变量(与对象变量相对) . 因此,声明“a”静态意味着只有一个所有Test对象共享,并且静态代码块仅在首次加载Test类时初始化“a”一次,无论创建多少个Test对象 .

相关问题