Java 方法在重写的JTable中的构造函数之前调用
我有一个扩展JScrollPane的类,它创建了另一个扩展JTable的类的对象。基本上是这样的:Java 方法在重写的JTable中的构造函数之前调用,java,Java,我有一个扩展JScrollPane的类,它创建了另一个扩展JTable的类的对象。基本上是这样的: class CustomScrollPane{ private CustomTable table public CustomScrollPane(..){ table = new CustomTable(this); .. } public void scrollToBottom(){ ... } } 在CustomTable类别I中,重
class CustomScrollPane{
private CustomTable table
public CustomScrollPane(..){
table = new CustomTable(this);
..
}
public void scrollToBottom(){
...
}
}
在CustomTable类别I中,重写tableChanged:
public class CustomTable extends JTable{
private CustomScrollPane scrollPane;
public CustomTable(CustomScrollPane scrollPane){
super();
this.scrollPane = scrollPane;
}
@Override
public void tableChanged(TableModelEvent e) {
super.tableChanged(e);
scrollPane.scrollToBottom();
}
当我运行这个程序时,在tableChanged()的scrollPane上会出现一个NullPointerException,这怎么可能呢?在构造函数中设置scrollPane时,scrollPane如何可以为null?在调试器中运行它表明tableChanged()在构造函数之前被调用。添加条件
if (scrollPane != null)
实际上解决了这个问题,因为稍后会调用构造函数。此外,将JTable定义为其构造的,如:
table = new JTable(){
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
final Component c = super.prepareRenderer(new CustomTableCellRenderer(), row, column);
if (c instanceof JComponent){
((JComponent) c).setOpaque(true);
}
return c;
}
@Override
public void paint(Graphics g) {
int scrolling = scrollPane.getViewport().getViewPosition().y;
super.paint(g);
g.drawImage(image.getImage(), -30, -50 + scrolling, null, null);
}
@Override
public void tableChanged(TableModelEvent e) {
super.tableChanged(e);
scrollPane.scrollToBottom();
}
};
直接在CustomScrollPane构造函数中也可以工作。为什么不能将其拆分为一个单独的类?这是一种典型的非常糟糕的模式,即部分初始化的实例脱离了构造函数的作用域 我猜CustomScrollPane在调用新的CustomTable时会向CustomTable触发一些事件(如下所示) 由于滚动窗格尚未初始化,因此您将获得NPE
千万不要让事情逃出构造函数,这样你就安全了。这是典型的非常糟糕的模式,部分初始化的实例逃出了构造函数的作用域 我猜CustomScrollPane在调用新的CustomTable时会向CustomTable触发一些事件(如下所示) 由于滚动窗格尚未初始化,因此您将获得NPE
千万不要让东西逃逸构造函数,这样你就安全了。它看起来像是
JTable
构造函数调用方法tableChanged(…)
——这意味着它是在你能够初始化滚动窗格
实例变量之前被调用的
首先,我建议你看看书中的一些谜题——特别是谜题51:重点是什么,也许谜题53:做你自己的事。他们应该帮助你了解发生了什么。基本上,CustomTable
构造函数的第一行调用JTable
构造函数(通过super()
)。JTable
构造函数正在尝试调用已被覆盖的tableChanged
。被覆盖的表已更改
尝试操作滚动窗格
。。。但是所有这些都发生在构造函数的第1行(super()
)-在执行第this.scrollPane=scrollPane
行之前,因此scrollPane
仍然为空
接下来,我建议使用。这里有两个对象—滚动窗格和自定义表—当另一个对象发生更改时,需要通知其中一个对象。这是教科书上的观察者模式。以下是大概的想法:
文件CustomTable.java
它看起来像是
JTable
构造函数调用了方法tableChanged(…)
——这意味着它是在您能够初始化滚动窗格
实例变量之前被调用的
首先,我建议你看看书中的一些谜题——特别是谜题51:重点是什么,也许谜题53:做你自己的事。他们应该帮助你了解发生了什么。基本上,CustomTable
构造函数的第一行调用JTable
构造函数(通过super()
)。JTable
构造函数正在尝试调用已被覆盖的tableChanged
。被覆盖的表已更改
尝试操作滚动窗格
。。。但是所有这些都发生在构造函数的第1行(super()
)-在执行第this.scrollPane=scrollPane
行之前,因此scrollPane
仍然为空
接下来,我建议使用。这里有两个对象—滚动窗格和自定义表—当另一个对象发生更改时,需要通知其中一个对象。这是教科书上的观察者模式。以下是大概的想法:
文件CustomTable.java
您确定在CustomScrollPane或CustomTable中没有另一个实际被调用的构造函数吗?再次运行调试器,查看CustomTable中的哪个构造函数是从CustomScrollPane中的哪个构造函数调用的。是的,我想你是对的。它似乎调用了JPanel中的其他构造函数,我觉得这有点奇怪,因为该构造函数,不管它是什么,都不可能具有与我相同的参数(我自己类的对象)。您确定在CustomScrollPane或CustomTable中没有另一个实际被调用的构造函数吗?再次运行调试器,查看CustomTable中的哪个构造函数是从CustomScrollPane中的哪个构造函数调用的。是的,我想你是对的。它似乎调用了来自JPanel的其他构造函数,我觉得有点奇怪,因为这个构造函数,不管它是什么,都不可能有和我相同的参数(我自己类的对象)。我不确定我是否理解你的建议。你认为我应该删除table=newcustomtable(这个);从构造函数中添加一个setTable()方法?请看下面的答案,它非常详细地描述了我的观点。我不确定我是否理解你的建议。你认为我应该删除table=newcustomtable(这个);从构造函数中添加一个setTable()方法?请看下面的答案,它非常详细地描述了我的观点感谢构造函数信息、链接和模式建议!感谢构造器信息、链接和模式建议!
public class CustomTable extends JTable {
// No more scroll pane; only observers
private List<ChangeListener> listeners = [];
// no more scroll pagne
public CustomTable(){
super();
}
@Override
public void tableChanged(TableModelEvent e) {
super.tableChanged(e);
this.fireChangeEvent();
}
/* new methods */
public void addChangeListener(ChangeListener listener) {
listeners.add(listener);
}
public void removeChangeListener(ChangeListener listener) {
// ...
}
private void fireChangeEvent() {
for(String l : listeners ){
l.onChange();
}
}
}
class CustomScrollPane implements ChangeListener{
private CustomTable table
public CustomScrollPane(/*...*/){
table = new CustomTable();
table.addChangeListener(this);
//...
}
public void scrollToBottom(){
//...
}
/* new methods */
@Override
public void onChange() {
scrollToBottom();
}
}