Làm thế nào để ghi đè toString () đúng cách trong Java?


87

Nghe có vẻ hơi ngu ngốc, nhưng tôi cần trợ giúp về toString()phương pháp của mình và điều đó rất khó chịu. Tôi đã cố gắng tìm kiếm trực tuyến bởi vì toStringnó là một trong những nơi nó đang trục trặc và "không tìm thấy hàm tạo Kid # 2" mặc dù nó ở đó và tôi thậm chí sẽ làm một cái gì đó khác nhưng nó không hoạt động. Ok, đó là rất nhiều vì vậy đây là mã của tôi:

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 

Ok Vì vậy, toString của tôi ở trên (tôi biết, tham số thứ ba của tôi bị tắt, phải là một Chuỗi) đã tắt. Nếu tôi mã hóa một giá trị cho điều thứ ba, nó sẽ kêu lên và nói rằng nó không thể tìm thấy giá trị này (ở trên). Vì vậy, làm thế nào tôi có thể có được ngày và chia tay nó?

Lớp gọi cái này ở bên dưới

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  

Tôi đã thử nghiên cứu nhiều hàm tạo và nó thực sự không giúp được gì. Tôi đã thử nghiên cứu toString()các phương pháp và thử sử dụng toString()logic các phương pháp trước đó mà tôi đã tạo trước đó nhưng điều này là hoàn toàn mới nên nó không bao giờ hoạt động.

Cứu giúp?


5
Vui lòng gửi mã thực sự sẽ biên dịch. toString()Phương thức của bạn không trả về một chuỗi và bạn không thể gọi một hàm tạo như vậy. Không rõ bạn thậm chí đang cố gắng đạt được điều gì. Vui lòng đọc tinyurl.com/so-hints và làm rõ câu hỏi của bạn.
Jon Skeet

Spring's ToStringCreator ( github.com/SpringSource/spring-framework/tree/master/… ) thực hiện công việc rất tốt.
Ritesh

FYI, người già lớp ngày thời gian khủng khiếp phiền hà như java.util.Date, java.util.GregorianCalendarjava.text.SimpleDateFormatbây giờ là di sản , thay thế bởi sự java.time class built vào Java 8 và sau đó. Xem Hướng dẫn của Oracle .
Basil Bourque

Câu trả lời:


134

toStringphải trả lại a String.

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

Tôi khuyên bạn nên sử dụng các tính năng IDE của mình để tạo toStringphương pháp. Đừng viết mã nó bằng tay.

Ví dụ, Eclipse có thể làm như vậy nếu bạn chỉ cần nhấp chuột phải vào mã nguồn và chọn Source > Generate toString


1
Đây không phải là cách thực hành tốt, vì bạn đang sử dụng cách nối chuỗi.
Amit

1
StringBuilder là lựa chọn tốt hơn trong tình huống như vậy.
Amit

9
@Amit Trình biên dịch Java sử dụng StringBuilderngầm định. Không có vấn đề gì trừ khi bạn đang sử dụng nó trong một vòng lặp.
chrylis -cautilyoptimistic-

Trong Netbeans; nó đang ở dưới Source -> Insert Code...sau đó chọntoString
Fer

10

Phương thức toString () trong Java

Nếu bạn muốn biểu diễn bất kỳ đối tượng nào dưới dạng chuỗi, phương thức toString () sẽ ra đời.

Phương thức toString () trả về biểu diễn chuỗi của đối tượng.

Nếu bạn in bất kỳ đối tượng nào, trình biên dịch java sẽ gọi nội bộ phương thức toString () trên đối tượng. Vì vậy, việc ghi đè phương thức toString (), trả về kết quả đầu ra mong muốn, nó có thể là trạng thái của một đối tượng, v.v. tùy thuộc vào việc triển khai của bạn.

Lợi thế của phương thức toString () trong Java

Bằng cách ghi đè phương thức toString () của lớp Object, chúng ta có thể trả về các giá trị của đối tượng, vì vậy chúng ta không cần phải viết nhiều mã.

Đầu ra không có phương thức 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

Bạn có thể thấy trong ví dụ # 1 ở trên. in s1 và s2 in các giá trị Hashcode của các đối tượng nhưng tôi muốn in các giá trị của các đối tượng này. Vì trình biên dịch java gọi nội bộ phương thức toString (), ghi đè phương thức này sẽ trả về các giá trị được chỉ định. Hãy hiểu nó với ví dụ dưới đây:

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

Lưu ý rằng toString () chủ yếu liên quan đến khái niệm đa hình trong Java. Trong Eclipse, hãy thử nhấp vào toString () và nhấp chuột phải vào nó, sau đó nhấp vào Mở Khai báo và xem Superclass toString () đến từ đâu.


4

Bạn có thể tạo đối tượng mới trong toString (). sử dụng

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

thay vì

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

Bạn có thể thay đổi chuỗi trả về theo yêu cầu. Có nhiều cách khác để lưu trữ ngày thay thế.


3

Bạn không thể gọi một hàm tạo như thể nó là một phương thức bình thường, bạn chỉ có thể gọi nó bằng newđể tạo một đối tượng mới:

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

Nhưng việc xây dựng một đối tượng mới từ phương thức toString () của bạn không phải là điều bạn muốn làm.


3

Như những người khác đã giải thích, toStringđây không phải là nơi để khởi tạo lớp học của bạn. Thay vào đó, toStringphương thức này nhằm mục đích xây dựng một chuỗi đại diện cho giá trị của một phiên bản thuộc lớp của bạn, báo cáo về ít nhất các trường dữ liệu quan trọng nhất được lưu trữ trong đối tượng đó. Trong hầu hết các trường hợp, toStringđược sử dụng để gỡ lỗi và ghi nhật ký, không phải cho logic kinh doanh của bạn.

Để tạo văn bản đại diện cho giá trị của một đối tượng để hiển thị cho người dùng, hãy thêm một phương thức khác. Mọi người thường đặt tên cho phương pháp này như thế nào getDisplayName. Ví dụ, DayOfWeek::getDisplayNameMonth::getDisplayName.

StringJoiner

Kể từ Java 8 trở lên, cách hiện đại nhất để triển khai toStringsẽ sử dụng StringJoinerlớp. Như bác sĩ nói:

StringJoiner được sử dụng để xây dựng một chuỗi các ký tự được phân tách bằng dấu phân cách và tùy chọn bắt đầu bằng tiền tố được cung cấp và kết thúc bằng hậu tố được cung cấp.

Sử dụng như thế này:

@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.
}

Người [tên = Alice | phone = 555.867.5309]


1
điều đó thanh lịch hơn
esQmo_

2

Mã sau là một mẫu. Câu hỏi dựa trên cùng, thay vì sử dụng chuyển đổi dựa trên IDE, có cách nào nhanh hơn để triển khai để trong tương lai các thay đổi xảy ra, chúng ta không cần phải sửa đổi các giá trị nhiều lần không?

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

2

Nếu bạn quan tâm đến Unit-Test, thì bạn có thể khai báo một "ToStringTemplate" công khai, và sau đó bạn có thể kiểm tra đơn vị toString của mình. Ngay cả khi bạn không kiểm tra đơn vị nó, tôi nghĩ nó "sạch" hơn và sử dụng 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());
    } 
}

Giờ đây, bạn có thể kiểm tra đơn vị bằng cách tạo Kid, thiết lập các thuộc tính và thực hiện định dạng string.format của riêng bạn trên ToStringTemplate và so sánh.

làm cho ToStringTemplate static-final có nghĩa là "MỘT PHIÊN BẢN" của sự thật, thay vì có "bản sao" của mẫu trong bài kiểm tra đơn vị.


1

Thực ra bạn sẽ cần trả về một thứ như thế này vì toString phải trả về một chuỗi

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

và bạn thực sự đã làm sai điều gì đó trong trình tạo mà bạn đặt biến mà người dùng đặt thành tên trong khi bạn cần làm ngược lại. Những gì bạn không nên làm

n = this.name

Bạn nên làm gì

this.name = n

Hy vọng điều này sẽ giúp cảm ơn


1

chúng ta thậm chí có thể viết như thế này bằng cách tạo một đối tượng String mới trong lớp và gán cho nó những gì chúng ta muốn trong hàm tạo và trả về trong phương thức toString bị ghi đè

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

Luôn luôn có cách dễ dàng: Nhấp chuột phải > Tạo > toString () > chọn mẫu bạn muốn. nhập mô tả hình ảnh ở đây


0

Cách tốt nhất theo ý kiến ​​của tôi là sử dụng thư viện google gson:

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

hoặc apache commons lang phản ánh cách


0
  1. nếu bạn đang sử dụng bằng notepad: thì

    public String toString(){
    
     return ""; ---now here you can use variables which you have created for your class
    
    }
    
  2. nếu bạn đang sử dụng IDE nhật thực thì nhấn

    -alt +shift +s 
    

    -click vào override toString method ở đây bạn sẽ nhận được các tùy chọn để chọn loại biến mà bạn muốn chọn.


0

Cách tốt và ngắn gọn là sử dụng chú thích Lombok. Nó có @ToStringchú thích, sẽ tạo ra một triển khai của toString()phương thức. Theo mặc định, nó sẽ in tên lớp của bạn, cùng với mỗi trường, theo thứ tự, được phân tách bằng dấu phẩy. Bạn có thể dễ dàng tùy chỉnh đầu ra của mình bằng cách chuyển các tham số tới chú thích, ví dụ:

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

Tương đương với Java thuần túy:

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

0

Nếu bạn chỉ sử dụng toString()để gỡ lỗi DTO , bạn có thể tự động tạo đầu ra có thể đọc được của con người bằng những thứ như sau:

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

Tuy nhiên, điều này không thích hợp cho việc triển khai sản xuất nếu DTO có thể chứa PII (không nên ghi lại trong nhật ký).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.