class Test { static { System.out.println("***"); } public static final String a = "sss";}class Test1 { public static void main(String[] args) { System.out.println(Test.a); }}
输出 sss 因变量a是final修饰的,外部调用类的静态常量是不会导致类的初始化的! class Test { static { System.out.println("***"); } public static String a = "sss";//注意这里已把final去掉,看运行结果}class Test1 { public static void main(String[] args) { System.out.println(Test.a); }}
Test只有被实例化的时候才会执行静态代码块
再看下面的例子,虽然a是静态常量,但其却被付值为一个非final类型的常量,这仍然会导致类的初始化的! class Test { static { System.out.println("***"); } public static String b = "sss"; public static final String a = b;}class Test1 { public static void main(String[] args) { System.out.println(Test.a); }}
这还是有问题吧? public static final String a = null; 已经声明为final了,不可能再通过其他的方式对它进行初始化了,为何还要尝试查找static语法块并允许呢??关注!!!!
这个地方比较好理解了,首先final是只能赋值一次的,既然已经被赋值了,那么static内肯定不能再赋值 但是如果a不是显式赋值的,那么static块内就可以对其进行赋值了 Java codepublic static final String a;
import java.util.Random;class Testtt{ static{ System.out.println("***"); } static final int i=Testfinal.rand.nextInt(100); } public class Testfinal { public static Random rand=new Random(10); public static void main(String[] args) { System.out.println(Testtt.i); }} 上面的代码,是先输出***的,那是因为i不是编绎是常量,那么在读取它之前,要先为这个域分配存储空间并且初始化该存储空间. 结论:对于编译期常量,不需要对类进行初始化就能被读取
输出SSS 因为a前面加了static final 关键字,a已经是常量,不能再被赋值或修改。
其实可以这么理解,这楼主所说的这个例子中,java编译器会将“sss”这个常数编译到Test类的指令码中。那么,每次当Test1类用到常量a的时候,不会通过引用连接到Test类中进行读取,而是直接使用自己保存在类文件中的副本。 至于为什么这样说: 大家在初学Java的时候可能遇到过这样个问题 我有两个类public class A { public static void main(String[] args){ System.out.println(B.a); }}public class B { public static final int a=111; } 在dos下先编译 B类,然后编译A类,然后执行A类 发现打印的是“111”这当然没什么问题, 这个时候,我们改变B类中的值将其改变为 a=222; 然后编译B类,再执行A 类 你会发现,打印的结果还是111 而不是改变后的值 222,原因就是,A类的指令码中还是保存着原先的111的值的副本。 这个时候,我们再编译一次A类,这时候B类中的常量a 就会以副本的形式保存到A类的指令码中中。当然执行A类的时候就会打印 出222 的结果。 既然是这样一个过程,当然,在楼主所说的这个问题上,你定义了一个常量后,会以一个副本的形式,存放到Test1这个类的指令码中,这样我们执行的时候,就不干Test的事情了。他里面静态快中的内容也不会打印出来。至于为什么会这样我也不知道,这只有问下当初的设计者了。我想可能是起到一个优化的作用,对于常量,我们就不必通过连接(暂时这样称呼吧)去找到他
1.public static final String a = "sss"; java编译器会将“sss”这个常数编译到Test类的指令码中。 2.public static final String a = null;java编译器会将“null”这个常数编译到Test类的指令码中。只知道是一个“null”,但是他不知道这个null是程序员给的值还是类变量自动的默认值,只好去class里看个究竟了。
既然java没有认为“public static final String a=null;”不错,而又没有warning,即没有意义的语句。是因为final的对象是个特殊情况,允许且只允许在类初始化时赋值。 不管这个初始化是指构造方法还是其他什么的,都构成了“类在首次加载”的条件,所以这个类会被正常加载,当然也就要执行static块了。这个并没有表明static是直接被允许的。所以“为何还要尝试查找static语法块并允许呢??”疑问取消。这时我的理解
class Demo { static { System.out.println("***"); } public static final String S = "sss"; }class Test { public static void main(String[] args) { String s = Demo.S; } }class Demo { static { System.out.println("***"); } public static final String S = null; }class Test { public static void main(String[] args) { String s = Demo.S; } }将两者的 Test 类[code=BatchFile]javap -c -l -private -s -verbose Test[/code]前后结果对比一下 JVM 指令,原因就一目了然了。
楼主【liujun999999】截止到2008-07-10 09:31:46的历史汇总数据(不包括此帖):
发帖的总数量:10 发帖的总分数:1610 每贴平均分数:161
回帖的总数量:805 得分贴总数量:494 回帖的得分率:61%
结贴的总数量:10 结贴的总分数:1610
无满意结贴数:0 无满意结贴分:0
未结的帖子数:0 未结的总分数:0
结贴的百分比:100.00% 结分的百分比:100.00%
无满意结贴率:0.00 % 无满意结分率:0.00 %
敬礼!
sssstatic为静态初始化,在构造类的时候自动调用。当Test开始构造的时候执行了
System.out.println("***");
在构造完成后main执行了
System.out.println(Test.a);
sss
Test.a 调用了Test的静态变量,Test并不会运行static块中的代码
sss 因变量a是final修饰的,外部调用类的静态常量是不会导致类的初始化的!
class Test {
static {
System.out.println("***");
}
public static String a = "sss";//注意这里已把final去掉,看运行结果}class Test1 {
public static void main(String[] args) {
System.out.println(Test.a); }}
static {
System.out.println("***");
}
public static String b = "sss";
public static final String a = b;}class Test1 {
public static void main(String[] args) {
System.out.println(Test.a); }}
调用某个类的静态方法时;
使用某个类或接口的静态字段或对该字段赋值时(final字段除外);
调用Java的某些反射方法时
初始化某个类的子类时
在虚拟机启动时某个含有main()方法的那个启动类。
这应该是静态引用吧
并没有构建Test的对象
所以不执行静态块
而是有一个静态常量区域,所以使用的时候不会导致执行static代码段
不知道对不对
Java编译器把所有的类变量初始化语句和类型的静态初始化器通通收集到<clinit>方法内,该方法只能被Jvm调用,专门承担初始化工作。楼主的例子是外部调用类的静态final常量, 并且该常量初始化语句是编译时的常量表达式。 只能说这种情况不符合"类首次主动被使用时"的初始化规则; 因为底层的细节我无法窥探, 我的理解是: 既然是类的静态final常量, 并且类变量初始化语句是编译时的常量表达式, 那么该常量就断然不会依赖于类本身(包括其继承的类层级)的任何类属性及类方法,所以没有必要在外部引用这样的类常量时进行初始化。
public static final String a = "sss";
改成
public static final String a = null;
再看看结果
调用类的final成员不会引发类的初始化操作,所以static语法块不会被执行
当staitc成员变量为null时,会查找static语法快运行以便能够正确初始化static成员
这还是有问题吧?
public static final String a = null;
已经声明为final了,不可能再通过其他的方式对它进行初始化了,为何还要尝试查找static语法块并允许呢??关注!!!!
这个地方比较好理解了,首先final是只能赋值一次的,既然已经被赋值了,那么static内肯定不能再赋值
但是如果a不是显式赋值的,那么static块内就可以对其进行赋值了
Java codepublic static final String a;
static{
System.out.println("***");
}
static final int i=Testfinal.rand.nextInt(100);
}
public class Testfinal {
public static Random rand=new Random(10);
public static void main(String[] args) {
System.out.println(Testtt.i);
}}
上面的代码,是先输出***的,那是因为i不是编绎是常量,那么在读取它之前,要先为这个域分配存储空间并且初始化该存储空间.
结论:对于编译期常量,不需要对类进行初始化就能被读取
因为a前面加了static final 关键字,a已经是常量,不能再被赋值或修改。
至于为什么这样说:
大家在初学Java的时候可能遇到过这样个问题
我有两个类public class A
{
public static void main(String[] args){
System.out.println(B.a);
}}public class B
{
public static final int a=111; }
在dos下先编译 B类,然后编译A类,然后执行A类 发现打印的是“111”这当然没什么问题,
这个时候,我们改变B类中的值将其改变为 a=222; 然后编译B类,再执行A 类
你会发现,打印的结果还是111 而不是改变后的值 222,原因就是,A类的指令码中还是保存着原先的111的值的副本。
这个时候,我们再编译一次A类,这时候B类中的常量a 就会以副本的形式保存到A类的指令码中中。当然执行A类的时候就会打印
出222 的结果。
既然是这样一个过程,当然,在楼主所说的这个问题上,你定义了一个常量后,会以一个副本的形式,存放到Test1这个类的指令码中,这样我们执行的时候,就不干Test的事情了。他里面静态快中的内容也不会打印出来。至于为什么会这样我也不知道,这只有问下当初的设计者了。我想可能是起到一个优化的作用,对于常量,我们就不必通过连接(暂时这样称呼吧)去找到他
在其他的eclipse,jcreate 之类的ide中是看不出来的,
所以对于初学者开始最好不要用什么ide的工具了。呵呵
***
sss
因为静态代码块,方法,变量都是在JVM加载.class是给执行的;
所以先输出了***
而main方法是JVM加载.class加载完后,再通过一个线程调用main方法来运行的,自然后输出sss了
java编译器会将“sss”这个常数编译到Test类的指令码中。
2.public static final String a = null;java编译器会将“null”这个常数编译到Test类的指令码中。只知道是一个“null”,但是他不知道这个null是程序员给的值还是类变量自动的默认值,只好去class里看个究竟了。
既然java没有认为“public static final String a=null;”不错,而又没有warning,即没有意义的语句。是因为final的对象是个特殊情况,允许且只允许在类初始化时赋值。
不管这个初始化是指构造方法还是其他什么的,都构成了“类在首次加载”的条件,所以这个类会被正常加载,当然也就要执行static块了。这个并没有表明static是直接被允许的。所以“为何还要尝试查找static语法块并允许呢??”疑问取消。这时我的理解
sss 因为像 云水谣 说的 test是条用的别的类的常量方法 那个类不能被创建,也就是说static 中的 *** 不会执行。
而且 因为 a都是 final 你用一个非常量的值去给它赋值是不对的 。
感觉应该是sss
代码初始化顺序是先初始化静态代码块,再初始化静态变量
static {
System.out.println("***");
}
public static final String S = "sss";
}class Test {
public static void main(String[] args) {
String s = Demo.S;
}
}class Demo {
static {
System.out.println("***");
}
public static final String S = null;
}class Test {
public static void main(String[] args) {
String s = Demo.S;
}
}将两者的 Test 类[code=BatchFile]javap -c -l -private -s -verbose Test[/code]前后结果对比一下 JVM 指令,原因就一目了然了。