在 Java 里定义一个类的时候,很多时候我们需要提供成员变量,成员变量专业叫法是 Memeber Variable 或者干脆的叫作 Field. 根据是否使用 static 关键字修饰,可以将 Field 分为两种:
- static field:也称作 class variable,这种 filed 属于 class,并不属于单个 instance,所有该 class 的 intance 共享内存中的同一份 class field。
- non-static field:也称作 instance variable,它属于每一个具体的 instance,class 的每一个 instance 独享一份 non-static field。
接下来进入本文的主题:java 中 field 的初始化方式。
从初始化代码所在的位置看,可以粗略的分为三种:
- 在声明 field 的地方进行初始化。
- 在类的构造方法(constructor) 里对 field 进行初始化
- 在初始化块(initialization block) 中对已声明的 field 进行初始化
第一种方式主要用于简单的赋值,使用这种方式的前提是作为初始化变量的值是已知的并且通常可以使用单行的赋值语句完成(例外?参见 Double Brace Initialization)。
public class Foo { // class variable initializer private static Logger logger = LoggerFactory.getLogger(Foo.class); // instance variable initializer private List<String> fooList = new ArrayList<String>(); }
对于复杂的初始化语句,如包含异常处理(try-catch)、使用循环结构初始化等,则需要考虑另外两种初始化方式:constructor 和 initialization block。其中 initialization block 根据是否由 static 关键字修饰,又可分为 static(class) initialization block 和 instance(object) initialization block,前一种只能初始化 class variable,用它进行 instance variable 的初始化会导致编译错误。
构造方法(constructor)可以用于初始化 instance variable。除此之外,少数情况下,instance variable 的初始化需要考虑使用 instance initialization block 完成。例如,在匿名类中的初始化(因匿名类无构造方法),或者类中包含了多个 constructor,而它们有公共的一些复杂初始化操作,此时可以考虑将这些操作提取到 instance initialization block 里。除了这两种情况,在你的代码中应该尽量少使用 instance initialization block。
static initialization block 用于处理带有 class variable 的初始化操作。
public class BarClass { private static Properties propTable; static { try { propTable.load(new FileInputStream("/data/user.prop")); } catch (Exception e) { propTable.put("user", System.getProperty("user")); propTable.put("password", System.getProperty("password")); } } }
static initialization block 的另一个功能与线程安全(thread safe)相关。JVM 保证使用同一个 ClassLoader 加载的类中的 static initialization block 只被执行一次,因而它是线程安全的。也正因为这一点,很多时候我们可以利用 static initialization block 执行一些初始化(write)操作,而无需对该 block 使用任何同步机制。
最后来看一下初始化代码的执行顺序问题。在此之前,先看下面这段代码,它可以完整执行,请试着分析一下最后的输出是什么。
/** * @author wxl24life * */ public class ClassInitializerOrderTest{ public static void main(String[] args) { B a = new B(); } } class A { static int a = initA(); static int initA() { System.out.println("call 1"); return 0; } { System.out.println("call 5"); } { System.out.println("call 6"); } static { System.out.println("call 2"); } static { System.out.println("call 3"); } static int b = initB(); static int initB() { System.out.println("call 4"); return 0; } A() { System.out.println("call 7"); } } class B extends A { { System.out.println("call 8"); } String str = initStr(); String initStr() { System.out.println("call 9"); return "call 8"; } static { System.out.println("call 10"); } B() { super(); System.out.println("call 12"); } { System.out.println("call 11"); } }
用几句话概括下初始化顺序规则(假设调用方式类似于上面代码,即使用 new 操作符 ):
- static 先于 non-static, non-static 先于 constructor。这里的 static 统指 static field 和 static initialization block 两种初始化方式,non-static 同上。
- static 初始化代码按照在源代码中定义的顺序从上往下以此执行,non-static 同上。
- 存在继承关系时,优先执行基类中的初始化语句。
执行顺序测试代码的输出结果:
call 1 call 2 call 3 call 4 call 10 call 5 call 6 call 7 call 8 call 9 call 11 call 12
参考阅读:
相关推荐
详细讲解java类中静态变量,普通标量,对象、基本类型的初始化顺序。
java 使用类作为成员变量 java 使用类作为成员变量
注意:本文所说的全局变量指的是 variables with static storage,措词来自 c++ 的语言标准文档。 什么时候初始化 ... static initialization: 静态初始化指的是用常量来对变量进行初始化,主要包括 zero init
详细介绍了Java的静态成员变量、静态数据块、非静态成员变量和非静态成员变量等初始化顺序
C++类成员和数据成员初始化总结 C++为类中提供类成员的初始化列表 类对象的构造顺序是这样的: 1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员 ...一般的数据成员可以在构造函数中初始化。
Java中的变量的详细介绍 。介绍成员变量和局部变量的区别。成员变量中的实例变量和静态变量的区变。
昨天看了一本叫做《突破程序员基本功的16课》的书,个人感觉还可以,主要对Java的技巧进行了一些深入的讲解,让我对类的初始化和对象的创建有了新的认识
易语言静态变量初始化源码,静态变量初始化,静态变量初始化例子
C++中,全局变量只能声明、初始化,而不能赋值 也就是说,下面这样是不被允许的: #include using namespace std; int a; a = 2; int main() { return 0; } 错误提示是: C++ requires a type specifier for all...
75.java成员变量与局部变量.zip75.java成员变量与局部变量.zip75.java成员变量与局部变量.zip75.java成员变量与局部变量.zip75.java成员变量与局部变量.zip75.java成员变量与局部变量.zip75.java成员变量与局部变量....
Java 面向对象中的两类 变量 : 成员变量和局部变量
1. Re:Qt中关于release版本程序异常结束 2. Re:c++中指向对象的指针为NULL时可 3. Re:c++中指向对象的指针为NULL时可 5.
了解java中类各个成员的初始化顺序是非常重要的,这样你可以对类有全局的认识。不说太多,直接看下面的例子 class Father { static{ System. out.println("父类静态代码块初始化" ); } { System. out.println...
Java类加载器:静态变量初始化.docx
java 利用反射获取内部类静态成员变量的值操作.docx
static所声明的变量在Java中有一个初始化的先后顺序,带着这个问题接下来我们就来进行Java中static静态变量的初始化完全解析:
成员变量:有默认的初始化值 局部变量:没有初始化值,必须手动初始化 生命周期不同 成员变量:随着对象的创建而存在,随着对象的消失而消失 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失 特别...
主要介绍了Java静态和非静态成员变量初始化过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
Java 关键字修饰成员变量例子。
考虑一下效率的可以再构造函数的初始化列表中进行。 class CA { public: int data; …… public: CA(); …… }; CA::CA():data(0)//……#1……初始化列表方式 { //data = 0;//...