简体   繁体   English

如何覆盖类中的 toString 方法

[英]How to override toString method in a class

I am trying to generate a jList of classes.我正在尝试生成一个 jList 类。

If I do:如果我做:

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                   
}

Being my TestClass :作为我的TestClass

package test;

public class TestClass {

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


}

Then I get:然后我得到:

在此处输入图片说明

So far, so good.到现在为止还挺好。

Now I would like to have the content of the name class attribute instead of class test.TestClass displayed in the jList1.现在我想在 jList1 中显示name class 属性的内容而不是class test.TestClass test.TestClass 。

I have tried this:我试过这个:

public class TestClass {

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

    public static String toString() {
        return name;
    }

}

But I can not even compile it as I get:但我什至无法编译它:

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

Not an answer to overriding the toString method but a solution of how to have a list displaying something different than what is returned by toString .不是覆盖toString方法的答案,而是如何让列表显示与toString返回的内容不同的解决方案。 Add a ListCellRenderer to the list.ListCellRenderer添加到列表中。 Basically extend the default one (an extension of JLabel itself) and change what should be displayed:基本上扩展默认的( 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);
    }
}

To use it just call (before displaying the list)要使用它,只需调用(在显示列表之前)

list.setCellrenderer(new ClassRenderer());

More details, better explanation can be found in official tutorial: Providing a Custom Renderer更多细节,更好的解释可以在官方教程中找到: 提供自定义渲染器


Solution suggested by JB Nizet (my interpretation, hope I did understand it correctly): create an object to hold the Class and its label; JB Nizet建议的解决方案(我的解释,希望我理解正确):创建一个对象来保存Class及其标签; add its instance to the list:将其实例添加到列表中:

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 ?
}

used as:用作:

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

No need to change the default cell renderer for this.无需为此更改默认单元格渲染器。 Advantage: is is more OO if changed to be used in your chart, very simple example, instead of LabeledClass :优点:如果更改为在您的图表中使用,则更面向对象,非常简单的示例,而不是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;
    }
}

The enrichChart method must be implement for each possible entry, or have a generic one that uses a Class given to its constructor (as LabeledClass ).必须为每个可能的条目实现enrichChart方法,或者有一个通用的方法,该方法使用为其构造函数提供的Class (作为LabeledClass )。 Obviously this can be extended if required for more functionality depending on use case.显然,如果需要更多功能,这可以根据用例进行扩展。

Just in case it helps someone, using inputs to original OP I finally combined accepted answer with a static method named getClassName which is invoked via reflection.以防万一它对某人有帮助,使用原始 OP 的输入,我最终将接受的答案与名为getClassName的静态方法结合起来,该方法通过反射调用。

Note: I have included the final code which uses slightly different names but still shows reflection usage.注意:我已经包含了使用稍微不同的名称但仍然显示反射用法的最终代码。 My real app is obviously a bit more complex than the included simplified OP posted example as it is intended to use many classes extended from an abstract class that enforces the extended classes to implement several methods.我的真实应用程序显然比包含的简化 OP 发布示例更复杂,因为它打算使用从抽象类扩展的许多类,这些类强制扩展类来实现多种方法。

As a side note: the only thing I have not managed to enforce is the implementation of the static getClassName method, as apparently you can not enforce static methods implementation in Java (apparently abstract static methods are not possible).附带说明:我唯一没有设法强制执行的是静态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;

     }
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM