论坛首页 Java版

有点怪异的JTable问题,请教各位

浏览 4851 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
时间:2004-06-05
下面是一段例子代码:

[code:1]import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;

public class TestTable {

private int count = 0;

public TestTable(){
MyTable table = new MyTable();
}

private class MyTable extends JTable{

public void valueChanged(ListSelectionEvent e){
System.out.println(count);
}
}

public static void main(String[] args){
TestTable t = new TestTable();
}
}[/code:1]

问题在于创建MyTable时,需要调用valueChanged方法,但是在该方法中变量count是不存在的。这是为什么?

程序运行是总抛出以下异常:
[code:1]java.lang.NullPointerException

at TestTable.access$100(TestTable.java:5)

at TestTable$MyTable.valueChanged(TestTable.java:16)

at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:187)

at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:167)

at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:214)

at javax.swing.DefaultListSelectionModel.setAnchorSelectionIndex(DefaultListSelectionModel.java:606)

at javax.swing.JTable.initializeLocalVars(JTable.java:3547)

at javax.swing.JTable.<init>(JTable.java:370)

at javax.swing.JTable.<init>(JTable.java:295)

at TestTable$MyTable.<init>(TestTable.java:13)

at TestTable$MyTable.<init>(TestTable.java:13)

at TestTable.<init>(TestTable.java:10)

at TestTable.main(TestTable.java:21)

Exception in thread "main" [/code:1]
   
时间:2004-06-05
重载了缺省构造方法,导致TestTable没有初始化完成就有MyTable调用了该对象的句柄。MyTable调用的count成员前面缺省有一个TestTable.的修饰,由于初始化没有完成,该句柄处于空状态,于是出现了控制针错误。
   
0 请登录后投票
时间:2004-06-06
wolfsquare 写道
重载了缺省构造方法,导致TestTable没有初始化完成就有MyTable调用了该对象的句柄。MyTable调用的count成员前面缺省有一个TestTable.的修饰,由于初始化没有完成,该句柄处于空状态,于是出现了控制针错误。


按照你所说的,那么下面的情况应该会出现空指针,但是结果不是,只有在重载JTable的valueChanged这个方法的时候才会出现:
[code:1]
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;

public class TestTable {

private int count = 0;

public TestTable(){
MyTable table = new MyTable();
}

private class MyTable extends JTable{
public MyTable(){
System.out.println(count);
}

public void valueChanged(ListSelectionEvent e){
}
}

public static void main(String[] args){
TestTable t = new TestTable();
}
}
[/code:1]
   
0 请登录后投票
时间:2004-06-07
mochow 写道

在初始化JTable的时候,会调用valueChanged方法,这里又出现一个疑点,就是JTable调用的是它的子类MyTable的valueChanged方法,而不是它自己的,由于这个时候TestTable类还没有被初始化,因此valueChanged方法里引用的TestTable的变量自然也没有被初始化,因此才会抛出空指针来。

相对某一class来说,它的实例变量和初始化块是在其构造函数的调用前初始化的,所以TestTable类肯定已经被初始化了。
之所以会抛出空指针,我估计是JTable构造函数调用valueChanged()时,其子类MyTable对TestTable的隐藏引用尚未初始化,从而找不到count造成的。
   
0 请登录后投票
时间:2004-06-07
pufan 写道
mochow 写道

在初始化JTable的时候,会调用valueChanged方法,这里又出现一个疑点,就是JTable调用的是它的子类MyTable的valueChanged方法,而不是它自己的,由于这个时候TestTable类还没有被初始化,因此valueChanged方法里引用的TestTable的变量自然也没有被初始化,因此才会抛出空指针来。

相对某一class来说,它的实例变量和初始化块是在其构造函数的调用前初始化的,所以TestTable类肯定已经被初始化了。
之所以会抛出空指针,我估计是JTable构造函数调用valueChanged()时,其子类MyTable对TestTable的隐藏引用尚未初始化,从而找不到count造成的。


当初始化JTable的时候,MyTable对TestTable的引用尚未被赋值,JTable初始化完了之后,在初始化MyTable之前才赋值的。
   
0 请登录后投票
时间:2004-06-07
作为一个内部类,在外部类没有初始化完成时得到外部类的句柄并进行调用,无疑容易导致不可预料的事情发生,因此抛出控制针异常是正确的做法。
   
0 请登录后投票
时间:2004-06-07
wolfsquare 写道
作为一个内部类,在外部类没有初始化完成时得到外部类的句柄并进行调用,无疑容易导致不可预料的事情发生,因此抛出控制针异常是正确的做法。


看了你的话,我不得不认为你没有看明白我们所说的,我不觉得这个问题是编码的人的关系,我觉得是jvm自己的初始化机制有问题。

同样的东西推而广之,都会出现这个问题,外部类A,内部类B,B的父类C,C有方法methodC,C的构造方法里调用了methodC,B又override了方法methodC,如果在这个方法里又引用了类A的非静态变量或者方法,则,运行到methodC这里的时候,就会出现空指针。

当然也可以避免,可以在override methodC的时候加一句判断:
[code:1]
public void methodC(){
if(A.this==null){
return;
}
//...
}
[/code:1]
   
0 请登录后投票
时间:2004-06-07
你的form在哪里?JTable应该有个可以放的地方吧?也许这是出错的原因。
   
0 请登录后投票
时间:2004-06-07
不好意思,键盘不好敲字困难就没有写太多...
我详细说明一下我的意思:

作为一个内部类,在外部类没有初始化完成时使用外部类的句柄并进行调用,
这里就是被缺省隐含了的:
System.out.println(count);
这里的count 应该为 外部类实例.count,或者等价形式.有一个指向外部类实例的句柄.
在普通情况下是没有问题的,但是在构造中问题就来了,我认为当一个类在初始化过程中允许别的类调用正在初始化类的功能是非常危险的行为,对比继承的初始化顺序就明白了,父类的初始化一定是先完成的,这是为了保证初始化的原子性而设定的规则,同理外部类和内部类的关系也一样.
   
0 请登录后投票
时间:2004-06-07
wolfsquare 写道
不好意思,键盘不好敲字困难就没有写太多...
我详细说明一下我的意思:

作为一个内部类,在外部类没有初始化完成时使用外部类的句柄并进行调用,
这里就是被缺省隐含了的:
System.out.println(count);
这里的count 应该为 外部类实例.count,或者等价形式.有一个指向外部类实例的句柄.
在普通情况下是没有问题的,但是在构造中问题就来了,我认为当一个类在初始化过程中允许别的类调用正在初始化类的功能是非常危险的行为,对比继承的初始化顺序就明白了,父类的初始化一定是先完成的,这是为了保证初始化的原子性而设定的规则,同理外部类和内部类的关系也一样.


请举一个错误的例子,给出一段代码展示这样的问题。
   
0 请登录后投票
论坛首页 Java版

跳转论坛:
JavaEye推荐