The simple answer is to create your own, based on something like AbstractTableModel
For example...
public abstract class AbstractGenericTableModel<R> extends AbstractTableModel {
    protected ArrayList<R> rows;
    protected List columnIdentifiers;
    public AbstractGenericTableModel() {
        this(0, 0);
    }
    public AbstractGenericTableModel(int rowCount, int columnCount) {
        this(new ArrayList(columnCount), rowCount);
    }
    public AbstractGenericTableModel(List columnNames, int rowCount) {
        setData(new ArrayList<>(rowCount), columnNames);
    }
    public AbstractGenericTableModel(List<R> data, List columnNames) {
        setData(data, columnNames);
    }
    public List<R> getRowData() {
        return rows;
    }
    private List nonNullVector(List v) {
        return (v != null) ? v : new ArrayList();
    }
    public void setData(List<R> data, List columnIdentifiers) {
        this.rows = new ArrayList<>(nonNullVector(data));
        this.columnIdentifiers = nonNullVector(columnIdentifiers);
        fireTableStructureChanged();
    }
    public void addRow(R rowData) {
        insertRow(getRowCount(), rowData);
    }
    public void insertRow(int row, R rowData) {
        rows.add(row, rowData);
        fireTableRowsInserted(row, row);
    }
    /**
     * Removes the row at <code>row</code> from the model. Notification of the row being removed will be sent to all the listeners.
     *
     * @param row the row index of the row to be removed
     * @exception ArrayIndexOutOfBoundsException if the row was invalid
     */
    public void removeRow(int row) {
        rows.remove(row);
        fireTableRowsDeleted(row, row);
    }
    public void setColumnIdentifiers(List columnIdentifiers) {
        setData(rows, columnIdentifiers);
    }
    @Override
    public int getRowCount() {
        return rows.size();
    }
    @Override
    public int getColumnCount() {
        return columnIdentifiers.size();
    }
    @Override
    public String getColumnName(int column) {
        Object id = null;
        // This test is to cover the case when
        // getColumnCount has been subclassed by mistake ...
        if (column < columnIdentifiers.size() && (column >= 0)) {
            id = columnIdentifiers.get(column);
        }
        return (id == null) ? super.getColumnName(column)
                        : id.toString();
    }
}
public class ArrayListTableModel extends AbstractGenericTableModel<ArrayList> {
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        List<ArrayList> rows = getRowData();
        return rows.get(rowIndex).get(columnIndex);
    }
}
This creates two classes, an "abstract generics" based model, which allows you to specify the physical data which backs a row and a ArrayListTableModel which allows you to use a ArrayList for the individual data.
What this assumes though, is each row has the same number of elements, but it makes no checks
I suggest you have a closer look at How to Use Tables for more details