final类型变量的深入理解
2014-10-17 10:57
453 查看
大家都知道,final修饰的变量是不可改变值的,方法是不可被重写的,类是不可被继承的。
一直以来,我以为final修饰的变量一定是在定义时就初始化好,编译之后一直不变。原来final修饰的还有另一种变量,这种
情况在定义时并不能知道它的值。
下面详细分析一下:
final类型的变量一般还会选择用static的,因为final已经是不可改变的,那就可以在加载时就为其分配空间存储值。final修饰的变量分为以下两种情况,主要从调用其会不会造成类对象的初始化来看。
1)编译时可确定的;也就是说变量在定义时就明确初始化了。这种情况,当生成该对象的引用时,不会致使该类的初始化,因为在加载时已经将该变量的值存放在一个公共空间中。
2)编译时不可确定的,但在第一次使用之前一定要初始化,之后值就会一直保持不变。这种情况下,在不同的实例对象中,该final类型的变量可能会有不同的值。此时,生成一个该类的引用,若调用这种类型的变量,则会造成对象的初始化,才能知道该变量的值。
下面是个例子:
package com.ngnt.test.classInitialization;
import java.util.Random;
class TestSuper {
static {
System.out.println("Super Test class");
}
TestSuper() {
System.out.println("Super Test class constructor");
}
}
class Initable extends TestSuper {
static final int staticFinal = 123;
static final int staticFinal2 = TestClassInitialization.rand.nextInt(1000);
static {
System.out.println("Initailizing Initable class");
}
Initable() {
System.out.println("Initable class's constructor.");
}
}
class Initable2 {
static int staticNonFinal = 145;
static {
System.out.println("Initailizing Initable2 class");
}
Initable2() {
System.out.println("Initable2 class's constructor.");
}
}
class Initable3 {
static int staticNonFinal = 38;
static {
System.out.println("Initializing Initable3 class");
}
Initable3() {
System.out.println("Initable3 class's constructor.");
}
}
public class TestClassInitialization {
public static Random rand = new Random(47);
private final int a = 1;
public static void main(String[] ars) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class initable = Initable.class;
// initable.newInstance();
System.out.println("After creating Initable reference.");
// Does not trigger initialization
System.out.println(Initable.staticFinal);
// Does trigger initialization, first initialize super class
System.out.println(Initable.staticFinal2);
// Does trigger initailization
System.out.println(Initable2.staticNonFinal);
Class initable3 = Class.forName("com.ngnt.test.classInitialization.Initable3");
initable3.newInstance();
System.out.println("After creating Initable3 reference.");
System.out.println(Initable3.staticNonFinal);
}
}
提示:生成一个类的引用有两种方式:
1. Class.forName("类名"); 注意这里的类名要是完整路径的类名,而且注意大小写。这种情况得到的对象的引用会立即初始化该对象,就不会出现上面说的访问时初始化情况了。
2. 类名.class; 这种情况得到的对象的引用不会立即初始化该对象。
一直以来,我以为final修饰的变量一定是在定义时就初始化好,编译之后一直不变。原来final修饰的还有另一种变量,这种
情况在定义时并不能知道它的值。
下面详细分析一下:
final类型的变量一般还会选择用static的,因为final已经是不可改变的,那就可以在加载时就为其分配空间存储值。final修饰的变量分为以下两种情况,主要从调用其会不会造成类对象的初始化来看。
1)编译时可确定的;也就是说变量在定义时就明确初始化了。这种情况,当生成该对象的引用时,不会致使该类的初始化,因为在加载时已经将该变量的值存放在一个公共空间中。
2)编译时不可确定的,但在第一次使用之前一定要初始化,之后值就会一直保持不变。这种情况下,在不同的实例对象中,该final类型的变量可能会有不同的值。此时,生成一个该类的引用,若调用这种类型的变量,则会造成对象的初始化,才能知道该变量的值。
下面是个例子:
package com.ngnt.test.classInitialization;
import java.util.Random;
class TestSuper {
static {
System.out.println("Super Test class");
}
TestSuper() {
System.out.println("Super Test class constructor");
}
}
class Initable extends TestSuper {
static final int staticFinal = 123;
static final int staticFinal2 = TestClassInitialization.rand.nextInt(1000);
static {
System.out.println("Initailizing Initable class");
}
Initable() {
System.out.println("Initable class's constructor.");
}
}
class Initable2 {
static int staticNonFinal = 145;
static {
System.out.println("Initailizing Initable2 class");
}
Initable2() {
System.out.println("Initable2 class's constructor.");
}
}
class Initable3 {
static int staticNonFinal = 38;
static {
System.out.println("Initializing Initable3 class");
}
Initable3() {
System.out.println("Initable3 class's constructor.");
}
}
public class TestClassInitialization {
public static Random rand = new Random(47);
private final int a = 1;
public static void main(String[] ars) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class initable = Initable.class;
// initable.newInstance();
System.out.println("After creating Initable reference.");
// Does not trigger initialization
System.out.println(Initable.staticFinal);
// Does trigger initialization, first initialize super class
System.out.println(Initable.staticFinal2);
// Does trigger initailization
System.out.println(Initable2.staticNonFinal);
Class initable3 = Class.forName("com.ngnt.test.classInitialization.Initable3");
initable3.newInstance();
System.out.println("After creating Initable3 reference.");
System.out.println(Initable3.staticNonFinal);
}
}
提示:生成一个类的引用有两种方式:
1. Class.forName("类名"); 注意这里的类名要是完整路径的类名,而且注意大小写。这种情况得到的对象的引用会立即初始化该对象,就不会出现上面说的访问时初始化情况了。
2. 类名.class; 这种情况得到的对象的引用不会立即初始化该对象。
相关文章推荐
- 深入理解数据类型、变量类型属性、内存四区和指针
- 深入理解 Java final 变量的内存模型
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的结构和类型--PHP的哈希实现
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的作用域
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的结构和类型--静态变量
- 深入理解C系列:不同类型变量的变量名和内存间的关系
- perl——深入理解(包、命名空间、符号表、类型团、GLOB、变量和函数)
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的结构和类型--链表
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的结构和类型
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的赋值和销毁
- 深入理解PHP变量的值类型和引用类型
- 深入理解C系列:不同类型变量的变量名和内存间的关系
- 深入理解PHP内核(五)变量及数据类型-变量的结构和类型
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的结构和类型--常量
- 深入理解C系列:不同类型变量的变量名和内存间的关系
- 深入理解 Java final 变量的内存模型
- 深入理解PHP内核(九)变量及数据类型-静态变量
- 深入理解PHP内核(十)变量及数据类型-类型提示的实现
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的结构和类型--类型提示的实现
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的结构和类型--预定义变量