如何在Java中正确覆盖toString()?


87

听起来有些愚蠢,但是我需要toString()方法方面的帮助,这非常令人讨厌。我尝试在线查找,因为那toString是一个正在搞砸的地方,即使在那里,它也“找不到第二个Kid构造函数”,我什至会做其他事情,但它不起作用。好了,所以这是我的代码:

import java.util.*; 
   class Kid {  
      String name; 
      double height; 
      GregorianCalendar bDay; 

      public Kid () { 
         this.name = "HEAD";
         this.height = 1; 
         this.bDay = new GregorianCalendar(1111,1,1); 
      } 

      public Kid (String n, double h, String date) {
      // method that toString() can't find somehow
         StringTokenizer st = new StringTokenizer(date, "/", true);
         n = this.name;
         h = this.height;
      } 

      public String toString() { 
         return Kid(this.name, this.height, this.bDay);
      } 
   } //end class 

好的,所以我上面的toString(我知道,我的第三个参数已关闭,应该是String)已关闭。如果我在第三件事中硬编码一个值,它就会变成麻烦,并说找不到它(上面)。那么如何获取日期并将其拆分呢?

调用此的类如下

class Driver {   
   public static void main (String[] args) {   
      Kid kid1 = new Kid("Lexie", 2.6, "11/5/2009");   
      System.out.println(kid1.toString());
   } //end main method 
} //end class  

我尝试研究多个构造函数,但实际上并没有帮助。我尝试研究toString()方法,并尝试使用以前toString()创建的逻辑,但这是全新的,因此从未奏效。

救命?


5
请发布实际会编译的代码。您的toString()方法不返回字符串,因此无法调用类似的构造函数。目前尚不清楚您甚至想要实现什么。请阅读tinyurl.com/so-hints并澄清您的问题。
乔恩·斯基特

Spring的ToStringCreator(github.com/SpringSource/spring-framework/tree/master/…)做得很好。
里特什

仅供参考,非常麻烦旧日期,时间类,如java.util.Datejava.util.GregorianCalendarjava.text.SimpleDateFormat现在的遗产,由取代java.time内置到Java 8和更高等级。请参见Oracle教程
罗勒·布尔克

Answers:


134

toString应该返回String

public String toString() { 
    return "Name: '" + this.name + "', Height: '" + this.height + "', Birthday: '" + this.bDay + "'";
} 

我建议您利用IDE的功能来生成该toString方法。不要手工编码。

例如,如果您只需右键单击源代码并选择Eclipse,便可以做到这一点。 Source > Generate toString


1
这不是一个好习惯,因为您正在使用字符串连接。
阿米特(Amit)2013年

1
在这种情况下,StringBuilder是更好的选择。
阿米特(Amit)2013年

9
@Amit Java编译器StringBuilder隐式使用。除非您在循环中使用它,否则没有问题。
克莱里斯-cautiouslyoptimistic-

在Netbeans中;它是Source -> Insert Code...然后然后选择toString
Fer

10

Java toString()方法

如果要将任何对象表示为字符串,则存在toString()方法。

toString()方法返回对象的字符串表示形式。

如果打印任何对象,则Java编译器会在内部调用该对象的toString()方法。因此,重写toString()方法,返回所需的输出,它可以是对象的状态,等等。这取决于您的实现。

Java toString()方法的优势

通过重写Object类的toString()方法,我们可以返回对象的值,因此无需编写太多代码。

没有toString()方法的输出

class Student{  
 int id;  
 String name;  
 String address;  

 Student(int id, String name, String address){  
 this.id=id;  
 this.name=name;  
 this.address=address;  
 }  

 public static void main(String args[]){  
   Student s1=new Student(100,”Joe”,”success”);  
   Student s2=new Student(50,”Jeff”,”fail”);  

   System.out.println(s1);//compiler writes here s1.toString()  
   System.out.println(s2);//compiler writes here s2.toString()  
 }  
}  

Output:Student@2kaa9dc
       Student@4bbc148

您可以在上面的示例#1中看到。打印s1和s2打印对象的哈希码值,但我想打印这些对象的值。由于java编译器内部调用toString()方法,因此重写此方法将返回指定的值。让我们用下面给出的例子来理解它:

Example#2

Output with overriding toString() method

class Student{  
 int id;  
 String name;  
 String address;  

 Student(int id, String name, String address){  
 this.id=id;  
 this.name=name;  
 this.address=address;  
 }  

//overriding the toString() method  
public String toString(){ 
  return id+" "+name+" "+address;  
 }  
 public static void main(String args[]){  
   Student s1=new Student(100,”Joe”,”success”);  
   Student s2=new Student(50,”Jeff”,”fail”);  

   System.out.println(s1);//compiler writes here s1.toString()  
   System.out.println(s2);//compiler writes here s2.toString()  
 }  
} 

Output:100 Joe success
       50 Jeff fail

注意,toString()主要与Java中的多态性概念有关。在Eclipse中,尝试单击toString()并右键单击它,然后单击Open Declaration并查看超类toString()的来源。


4

您可以在toString()中创建新对象。使用

return "Name = " + this.name +" height= " + this.height;

代替

return Kid(this.name, this.height, this.bDay);

您可以根据需要更改返回字符串。还有其他存储日期而不是日历的方法。


3

您不能像使用普通方法那样调用构造函数,只能将其调用new以创建新对象:

Kid newKid = new Kid(this.name, this.height, this.bDay);

但是,从您的toString()方法构造一个新对象并不是您想要做的。


3

正如其他人解释的那样,toString并不是实例化您的课程的地方。相反,该toString方法旨在构建一个表示类实例值的字符串,并至少报告存储在该对象中的最重要数据字段。在多数情况下,toString用于调试和日志记录,而不用于您的业务逻辑。

若要生成表示对象值的文本以显示给用户,请添加另一种方法。人们通常将方法命名为getDisplayName。例如DayOfWeek::getDisplayNameMonth::getDisplayName

StringJoiner

从Java 8及更高版本开始,最现代的实现方式toString将使用StringJoiner该类。正如文档所说:

StringJoiner用于构造由定界符分隔的字符序列,并可选地以提供的前缀开头和以提供的后缀结尾。

像这样使用:

@Override
public String toString ()
{
    return new StringJoiner(                           // In Java 8 and later, StringJoiner is used to construct a sequence of characters separated by a delimiter and optionally starting with a supplied prefix and ending with a supplied suffix.
                " | " ,                                // Delimiter
                Person.class.getSimpleName() + "[ " ,  // Prefix
                " ]"                                   // Suffix
            )
            .add( "name=" + name )                     // Append
            .add( "phone=" + phone )                   // Append
            .toString();                               // Convert entire sequence to a single `String` object.
}

人[name = Alice | 电话= 555.867.5309]


1
更优雅
esQmo_

2

以下代码是一个示例。基于相同的问题,而不是使用基于IDE的转换,是否有更快的实现方法,以便将来发生更改时,我们不需要一遍又一遍地修改值?

@Override
    public String toString() {
        return "ContractDTO{" +
                "contractId='" + contractId + '\'' +
                ", contractTemplateId='" + contractTemplateId + '\'' +
                '}';
    }

2

如果您对单元测试感兴趣,则可以声明一个公共的“ ToStringTemplate”,然后可以对您的toString进行单元测试。即使您不对它进行单元测试,我也认为它“更干净”并使用String.format。

public class Kid {

    public static final String ToStringTemplate = "KidName='%1s', Height='%2s', GregCalendar='%3s'";

    private String kidName;
    private double height;
    private GregorianCalendar gregCalendar;

    public String getKidName() {
        return kidName;
    }

    public void setKidName(String kidName) {
        this.kidName = kidName;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public GregorianCalendar getGregCalendar() {
        return gregCalendar;
    }

    public void setGregCalendar(GregorianCalendar gregCalendar) {
        this.gregCalendar = gregCalendar;
    }

    public String toString() { 
        return String.format(ToStringTemplate, this.getKidName(), this.getHeight(), this.getGregCalendar());
    } 
}

现在,您可以通过创建Kid,设置属性并在ToStringTemplate上进行自己的string.format并进行比较来进行单元测试。

使ToStringTemplate成为静态决赛的意思是事实的“一个版本”,而不是在单元测试中拥有模板的“副本”。


1

好吧,实际上您将需要返回这样的内容,因为toString必须返回一个字符串

public String toString() {
 return "Name :" + this.name + "whatever :" + this.whatever + "";
}

而实际上在构造函数中做错了事,您将用户设置的变量设置为名称,而您需要做相反的事情。你不应该做的

n = this.name

你应该怎么做

this.name = n

希望这可以帮助谢谢


1

我们甚至可以通过在类中创建一个新的String对象并将其分配给构造函数中所需的内容,并在被重写的toString方法中返回它,来编写这样的代码

public class Student{  
 int id;  
 String name;  
 String address;  
 String details;
 Student(int id, String name, String address){  
 this.id=id;  
 this.name=name;  
 this.address=address;  
 this.details=id+"  "+name+"  "+address;  
 }  

//overriding the toString() method  
public String toString(){ 
  return details;  
 }  
 public static void main(String args[]){  
   Student s1=new Student(100,"Joe","success");  
   Student s2=new Student(50,"Jeff","fail");  

   System.out.println(s1);//compiler writes here s1.toString()  
   System.out.println(s2);//compiler writes here s2.toString()  
 }  
}

1

始终有简单的方法:右键单击>生成> toString() >选择所需的模板。 在此处输入图片说明


0

我认为最好的方法是使用Google gson库:

        @Override
public String toString() {
    return new GsonBuilder().setPrettyPrinting().create().toJson(this);
}

或Apache Commons Lang反射方式


0
  1. 如果您使用记事本:然后

    public String toString(){
    
     return ""; ---now here you can use variables which you have created for your class
    
    }
    
  2. 如果您使用的是eclipse IDE,请按

    -alt +shift +s 
    

    单击覆盖toString方法,在这里您将获得选择要选择的变量类型的选项。


0

简洁明了的方法是使用Lombok批注。它具有@ToString注释,它将生成该toString()方法的实现。默认情况下,它将按顺序打印您的班级名称以及每个字段,并以逗号分隔。您可以通过将参数传递给注释来轻松自定义输出,例如:

@ToString(of = {"name", "lastName"})

这等效于纯Java:

public String toString() {
        return "Person(name=" + this.name + ", lastName=" + this.experienceInYears + ")";
    }

0

如果您仅toString()用于调试DTO,则可以使用以下内容自动生成可读的输出:

import com.fasterxml.jackson.databind.ObjectMapper;
...
public String toString() {
    try { return new ObjectMapper().writeValueAsString(this); }
    catch (Exception e) { return "{ObjectMapper failed}"; }
}

但是,如果DTO可能包含PII(不应在日志中捕获),则这不适用于生产部署。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.