Подтвердить что ты не робот

NPE с инициализированной переменной

Может кто-нибудь объяснить мне, почему я получаю исключение NullPointerException в методе getRowCount()? Переменная инициализируется пустым ArrayList...

public class BeschriftungssetTableModel extends DefaultTableModel {

    private static final long serialVersionUID = -4980235976337188354L;

    private List<BeschriftungssetBean> data = new ArrayList<>();


    public void setData(List<BeschriftungssetBean> data) {
        this.data = data;
    }

    @Override
    public int getColumnCount() {
        return 1;
    }

    @Override
    public int getRowCount() {
        return data.size();
    }

    @Override
    public Object getValueAt(int row, int column) {
        return data.get(row).getBezeichnung();
    }

    @Override
    public String getColumnName(int column) {
        return "Bezeichnung";
    }

    public static void main(String[] args) {
        BeschriftungssetTableModel beschriftungssetTableModel = new BeschriftungssetTableModel();
        beschriftungssetTableModel.getRowCount();
    }
}



public class BeschriftungssetBean {
    private String objId;
    private String bezeichnung;

    public String getBezeichnung() {
        return bezeichnung;
    }

    public void setBezeichnung(String bezeichnung) {
        this.bezeichnung = bezeichnung;
    }

    public String getObjId() {
        return objId;
    }

    public void setObjId(String objId) {
        this.objId = objId;
    }
}

Exception in thread "main" java.lang.NullPointerException
at ch.aaa.xxx.yyy.gruppen.plugin.anzeige.beschriftungseinstellungen.BeschriftungssetTableModel.getRowCount(BeschriftungssetTableModel.java:36)
at javax.swing.table.DefaultTableModel.setDataVector(DefaultTableModel.java:224)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:124)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:106)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:86)
at ch.aaa.xxx.yyy.gruppen.plugin.anzeige.beschriftungseinstellungen.BeschriftungssetTableModel.<init>(BeschriftungssetTableModel.java:18)
at ch.aaa.xxx.yyy.gruppen.plugin.anzeige.beschriftungseinstellungen.BeschriftungssetTableModel.main(BeschriftungssetTableModel.java:50)
4b9b3361

Ответ 1

Конструктор DefaultTableModel вызывает getRowCount прежде чем подкласс имеет возможность инициализировать его содержимое, что приведет к NPE с вашим исполнением. Это плохой дизайн базового класса, так как вызов переопределяемых методов изнутри конструктора считается плохой практикой, но, к сожалению, Swing API имеет немало из них :)

Ср Что случилось с переопределяемыми вызовами метода в конструкторах?

Ответ 2

Не DefaultTableModel, вместо этого расширьте AbstractTableModel.

DefaultTableModel использует вектор для сохранения данных и не ожидает, что у вас есть собственные данные в подклассе. Как писал @spi, он вызывает getRowCount который был переопределен, чтобы вернуть размер data которые еще не инициализированы.

AbstractTableModel легко расширяется (также используется DefaultTableModel), только эти 3 метода должны быть реализованы (уже сделано в кодах вопросов):

public int getRowCount();
public int getColumnCount();
public Object getValueAt(int row, int column);

Другие методы можно переопределить, чтобы настроить его поведение, например isCellEditable или getColumnClass. Если данные изменены, следует вызвать соответствующий метод fireXXX чтобы вызываемые зарегистрированные слушатели были вызваны (например, JTable с использованием этой модели).

Альтернативой является реализация TableModel, но AbstractTableModel заботится о некоторых стандартных (неприятных?) TableModel, таких как поддержка слушателей.

(плохая альтернатива, просто проверьте значение null, но это, вероятно, испортит код DefaultTableModel - не делайте этого)