如何覆盖 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;
}
}
我正在尝试生成 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;
}
}