如何覆盖 class 中的 toString 方法

How to override toString method in a class

我正在尝试生成 classes 的 jList。

如果我这样做:

package test;

import javax.swing.DefaultListModel;

public class TestFrame extends javax.swing.JFrame {

    DefaultListModel jList1Model = new DefaultListModel();

    public TestFrame() {

        initComponents();

        jList1Model.addElement(TestClass.class);
        jList1.setModel(jList1Model);

    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        jList1 = new javax.swing.JList<>();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jList1.setModel(new javax.swing.AbstractListModel<String>() {
            String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            public int getSize() { return strings.length; }
            public String getElementAt(int i) { return strings[i]; }
        });
        jScrollPane1.setViewportView(jList1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>                        

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TestFrame().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JList<String> jList1;
    private javax.swing.JScrollPane jScrollPane1;
    // End of variables declaration                   
}

成为我的 TestClass:

package test;

public class TestClass {

    public static String name = "Test Class 1";
    public int foo;
    public int bar;


}

然后我得到:

到目前为止,还不错。

现在我想在 jList1 中显示 name class 属性的内容而不是 class test.TestClass

我试过这个:

public class TestClass {

    public static String name = "Test Class 1";
    public int foo;
    public int bar;

    public static String toString() {
        return name;
    }

}

但我什至无法编译它,因为我得到:

toString() in TestClass cannot override toString() in Object overriding mehtod is static.

不是覆盖 toString 方法的答案,而是如何让列表显示与 toString 返回的内容不同的解决方案。在列表中添加 ListCellRenderer。基本上扩展默认的(JLabel 本身的扩展)并更改应显示的内容:

class ClassRenderer extends DefaultListCellRenderer {
    @Override
    public Component getListCellRendererComponent(
            JList<?> list, Object value, int index, boolean selected, boolean focus) {
        if (value instanceof Class) {
            value = ((Class<?>) value).getSimpleName();
        }
        return super.getListCellRendererComponent(list, value, index, selected, focus);
    }
}

要使用它只需调用(在显示列表之前)

list.setCellrenderer(new ClassRenderer());

更多细节,更好的解释可以在官方教程中找到:Providing a Custom Renderer


JB Nizet建议的解决方案(我的解释,希望我理解正确):创建一个对象来保存 Class 及其标签;将其实例添加到列表中:

public class LabeledClass {

    private final String label;
    private final Class<?> theClass;

    LabeledClass(String label, Class<?> theClass) {
        this.label = Objects.requireNonNull(label);
        this.theClass = theClass;  // TODO null check?
    }

    public Class<?> getTheClass() {
        return theClass;
    }

    @Override
    public String toString() {
        return label;
    }

    // TOD hashcode, equals ?
}

用作:

model.addElement(new LabeledClass("Test", TestClass.class));

无需为此更改默认的单元格渲染器。优点:如果更改为在您的图表中使用,则更 OO,非常简单的示例,而不是 LabeledClass:

public abstract class ChartEnricher {

    private final String name;

    protected ChartEnricher(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public abstract void enrichChart();

    @Override
    public String toString() {
        return name;
    }
}

enrichChart 方法必须为每个可能的条目实现,或者有一个通用的方法,使用给定其构造函数的 Class(如 LabeledClass)。显然,如果需要更多功能,这可以根据用例进行扩展。

为了以防万一,使用原始 OP 的输入,我最终将接受的答案与名为 getClassName 的静态方法结合起来,该方法通过反射调用。

注意:我包含了最终代码,它使用的名称略有不同,但仍显示了反射用法。我的真实应用程序显然比包含的简化 OP 发布示例要复杂一些,因为它旨在使用从抽象 class 扩展的许多 classes,强制执行扩展 classes 来实现几种方法。

附带说明:我唯一没有强制执行的是静态 getClassName 方法的实现,显然你不能在 Java 中强制执行静态方法(显然是抽象的静态方法是不可能的)。

class IndicatorsRenderer extends DefaultListCellRenderer {


    @Override
    public Component getListCellRendererComponent(JList<?> list,
                                                   Object value,
                                                   int index,
                                                   boolean isSelected,
                                                   boolean cellHasFocus) {


        Class<? extends BaseIndicator> baseIndicatorClass = ((Class<? extends BaseIndicator>) value);

        try {
            return super.getListCellRendererComponent(list, baseIndicatorClass.getMethod("getClassName").invoke(baseIndicatorClass), index, isSelected, cellHasFocus);
        } catch (NoSuchMethodException ex) {
            Logger.getLogger(IndicatorsRenderer.class.getName()).log(Level.SEVERE, "No such method exception while trying to access Name of indicator. Exception {0}", ex);
            System.exit(1);
        } catch (SecurityException ex) {
            Logger.getLogger(IndicatorsRenderer.class.getName()).log(Level.SEVERE, "Security exception while trying to access Name of indicador. Exception {0}", ex);
            System.exit(1);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(IndicatorsRenderer.class.getName()).log(Level.SEVERE, "Illegal Access Exception while trying to access Name of indicator. Exception {0}", ex);
            System.exit(1);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(IndicatorsRenderer.class.getName()).log(Level.SEVERE, "Illegal Argument Exception while trying to access Name of indicator. Exception {0}", ex);
            System.exit(1);
        } catch (InvocationTargetException ex) {
            Logger.getLogger(IndicatorsRenderer.class.getName()).log(Level.SEVERE, "Invocation Target Exception while trying to access Name of indicator. Exception {0}", ex);
            System.exit(1);
        }

        return null;

     }
 }