public class Test {
public static int i=100;
public static void main(String[] args) {
Test t=new Test();
t=null;//已经将t指向空
System.out.println(t.i);//为什么这里i还可以打印100?
}
}对于上面的问题,思考后还是不明白为什么,请高手指点?静态变量、方法在内存中到底是怎么理解?机制是怎么样的?谢谢。
public static int i=100;
public static void main(String[] args) {
Test t=new Test();
t=null;//已经将t指向空
System.out.println(t.i);//为什么这里i还可以打印100?
}
}对于上面的问题,思考后还是不明白为什么,请高手指点?静态变量、方法在内存中到底是怎么理解?机制是怎么样的?谢谢。
解决方案 »
- java初学者
- 正在用java做一个记事本,文本区时用jtextarea做的,但在做事件监听的时候不能用textlistener,所以不能因为文本中的输入字符,删除字符做出事件
- 誰能解釋一下 边界类,控制类,实体类,越详细越好!
- 如何进行整合?
- 初始化与内部类的问题
- Checkbox组.getSelectedCheckbox().getName()
- json字符串解析问题
- 求《java编程思想》第二版的光盘
- 同样的程序为什么在ACCESS中可以运行而在SQL Server不能运行?
- 关于session!
- Serializable 问题
- 开发JSP时碰到的问题,%u554a这样的编码格式用什么解码?
编译器已经帮你换了,和实例无关
java对语法限制的不够严格.
或者说javac的功能强
跟你对static的理解没关系.不管怎么说,如果你有个不对t.i进行转换的编译器,没准就如lz所愿了~
---------------------------------------------
在Eclipse中,用类的实例来引用静态变量好像要报错吧
---------------------------------------------
在Eclipse中,用类的实例来引用静态变量好像要报错吧=======
不会的了,放心好了。
也就是说存在.class文件中的是Test.i,虚拟机根本就看不到t.i,他能看到的就是Test.i因为i是static的,也就是所谓的类成员变量.类变量应该通过类来调用.当你的类被装载的时候,这个变量就已经存在了,不论你是否去创建一个这个类的实例.既然i是类成员变量,那你为什么要通过t.i来调用而不用Test.i来调用呢?
--------------------
此时,class Test 已经被加载,class 初次被加载的时候会初始化static成员,此时Test.i值是100,
在程序启动的时候已经是加载的了,而且无论Test如何引用
int i 都指向同一个内存地址,所以
在Eclipse中 t.i不会报错,只会警告。
类Test的默认构造函数不就是Test(){};吗,只是没写出来
这句Test t=new Test();话调用的不就是默认构造函数?小弟初学,望大虾指点
public static int i=100;
在程序启动的时候已经是加载的了,而且无论Test如何引用
int i 都指向同一个内存地址,所以
--------------
好象是这样的.
Test t;
t.i; //无论你把t指向谁。t是Test类的变量。
System.out.println(t.i);
顺便说一下,一般我用都是用类名来访问静态变量。Test.i;
就是这样。
这句起了一定的实例作用.
说的很详细了~~
对你的程序稍微加了点东西.
public class Test {
public static int i=100;
public int j = 90;
public static void main(String[] args) {
Test t=new Test();
t=null;//已经将t指向空
System.out.println(Test.i);
System.out.println(t.i);//为什么这里i还可以打印100?
System.out.println(t.j);
}
}以下是执行javap -verbose Test后的结果.
Compiled from "Test.java"
public class Test extends java.lang.Object
SourceFile: "Test.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #8.#21; // java/lang/Object."<init>":()V
const #2 = Field #3.#22; // Test.j:I
const #3 = class #23; // Test
const #4 = Method #3.#21; // Test."<init>":()V
const #5 = Field #24.#25; // java/lang/System.out:Ljava/io/PrintS
tream;
const #6 = Field #3.#26; // Test.i:I
const #7 = Method #27.#28; // java/io/PrintStream.println:(I)V
const #8 = class #29; // java/lang/Object
const #9 = Asciz i;
const #10 = Asciz I;
const #11 = Asciz j;
const #12 = Asciz <init>;
const #13 = Asciz ()V;
const #14 = Asciz Code;
const #15 = Asciz LineNumberTable;
const #16 = Asciz main;
const #17 = Asciz ([Ljava/lang/String;)V;
const #18 = Asciz <clinit>;
const #19 = Asciz SourceFile;
const #20 = Asciz Test.java;
const #21 = NameAndType #12:#13;// "<init>":()V
const #22 = NameAndType #11:#10;// j:I
const #23 = Asciz Test;
const #24 = class #30; // java/lang/System
const #25 = NameAndType #31:#32;// out:Ljava/io/PrintStream;
const #26 = NameAndType #9:#10;// i:I
const #27 = class #33; // java/io/PrintStream
const #28 = NameAndType #34:#35;// println:(I)V
const #29 = Asciz java/lang/Object;
const #30 = Asciz java/lang/System;
const #31 = Asciz out;
const #32 = Asciz Ljava/io/PrintStream;;
const #33 = Asciz java/io/PrintStream;
const #34 = Asciz println;
const #35 = Asciz (I)V;{
public static int i;public int j;public Test();
Code:
Stack=2, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 90
7: putfield #2; //Field j:I
10: return
LineNumberTable:
line 1: 0
line 3: 4
public static void main(java.lang.String[]);
Code:
Stack=2, Locals=2, Args_size=1
0: new #3; //class Test
3: dup
4: invokespecial #4; //Method "<init>":()V
7: astore_1
8: aconst_null
9: astore_1
10: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
13: getstatic #6; //Field i:I
16: invokevirtual #7; //Method java/io/PrintStream.println:(I)V
19: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
22: aload_1
23: pop
24: getstatic #6; //Field i:I
27: invokevirtual #7; //Method java/io/PrintStream.println:(I)V
30: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: getfield #2; //Field j:I
37: invokevirtual #7; //Method java/io/PrintStream.println:(I)V
40: return
LineNumberTable:
line 5: 0
line 6: 8
line 7: 10
line 8: 19
line 9: 30
line 10: 40
static {};
Code:
Stack=1, Locals=0, Args_size=0
0: bipush 100
2: putstatic #6; //Field i:I
5: return
LineNumberTable:
line 2: 0
}主要看一下下面这几行:
0: new #3; //class Test
3: dup
4: invokespecial #4; //Method "<init>":()V
7: astore_1
以上这几行表示:创建了一个Test类的对象,调用其实例初始化方法,将该对象的引用存入局部变量区"1"的位置. 8: aconst_null
9: astore_1
表示用null覆盖了这个"1"的位置.对应的就是: t = null;这句 13: getstatic #6; //Field i:I
这行对应的是: Test.i
#6为常量池的符号引用,对应寻找上面的Constant pool,可以知道#6代表的是Test.i:I
getstatic这个操作指令表示读取静态字段(类成员变量),它不需要对象的引用. 22: aload_1 //把刚才那个局部变量区的"1"位置的内容压入栈,实际上就是null
23: pop //把这个null弹出栈,也就是扔掉了
24: getstatic #6; //Field i:I 这行就和上面的Test.i一样了
这几行对应的是: t.i
从这里可以看到,如果使用t.i要比Test.i多除了两个无用的操作.但结果是一样的.而且由于这两个无用的指令,对i的调用还要受到限制.比如不初始化t,是无法通过编译的. 33: aload_1
34: getfield #2; //Field j:I
这几行对应的是: t.j
从这里可以看出,对于实例成员变量和类成员变量完全对应的是不同的操作指令.
getfield有两个操作数,其中一个就是前一句通过aload_1入栈的Test对象的引用.
getfield要用过这个引用来找到这个对象,从而获取其实例成员变量j.虚拟机是完全针对.class文件进行操作的,所以虚拟机能看到到也就是写在.class文件里面的东西,并不是写在.java里面的东西.所以虚拟机会严格按照上面的操作指令执行.
这些在编译时候就已经决定了,并不是虚拟机对t.i和Test.i做了什么不同的处理.最后值得一提的是,前面的代码中有3个方法:
public Test(); //这个就是自动添加的默认构造方法, j在这里被初始化
public static void main(java.lang.String[]);
static {}; //这个方法叫做静态初始化方法,它是类装载,初始化时被调用的,i在这里被初始化