简体   繁体   中英

How to override toString method in a class

I am trying to generate a jList of classes.

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 :

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.

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 . Add a ListCellRenderer to the list. Basically extend the default one (an extension of JLabel itself) and change what should be displayed:

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; 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 :

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 ). 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.

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.

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).

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;

     }
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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