ฉันจะพิมพ์วัตถุ Java ของฉันโดยไม่ได้รับ“ SomeType @ 2f92e0f4” ได้อย่างไร


300

ฉันมีคลาสที่กำหนดดังนี้:

public class Person {
  private String name;

  // constructor and getter/setter omitted
}

ฉันพยายามพิมพ์ตัวอย่างของชั้นเรียนของฉัน:

System.out.println(myPerson);

แต่ฉันได้ผลลัพธ์ต่อไปนี้: com.foo.Person@2f92e0f4.

สิ่งที่คล้ายกันเกิดขึ้นเมื่อฉันพยายามพิมพ์อาร์เรย์ของPersonวัตถุ:

Person[] people = //...
System.out.println(people); 

ฉันได้รับผลลัพธ์: [Lcom.foo.Person;@28a418fc

ผลลัพธ์นี้หมายความว่าอย่างไร ฉันจะเปลี่ยนผลลัพธ์นี้เพื่อให้มีชื่อของบุคคลของฉันได้อย่างไร และฉันจะพิมพ์คอลเล็กชันของวัตถุของฉันได้อย่างไร

หมายเหตุ : นี่เป็นคำถามและคำตอบที่เป็นที่ยอมรับเกี่ยวกับเรื่องนี้


1
คุณสามารถใช้ไลบรารีGSONเพื่อแปลงวัตถุเป็น json และในทางกลับกัน มีประโยชน์มากสำหรับการแก้ไขข้อบกพร่อง
Ashish Rawat

คำตอบ:


403

พื้นหลัง

วัตถุ Java ทั้งหมดมีtoString()วิธีการซึ่งถูกเรียกเมื่อคุณลองและพิมพ์วัตถุ

System.out.println(myObject);  // invokes myObject.toString()

วิธีนี้ถูกกำหนดไว้ในObjectคลาส (superclass ของวัตถุ Java ทั้งหมด) Object.toString()วิธีการส่งกลับสตริงมองน่าเกลียดอย่างเป็นธรรมประกอบด้วยชื่อของชั้นเรียนนั้น@สัญลักษณ์และแฮชโค้ดของวัตถุในฐานสิบหก รหัสสำหรับสิ่งนี้ดูเหมือนว่า:

// Code of Object.toString()
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

ผลลัพธ์เช่นcom.foo.MyType@2f92e0f4สามารถอธิบายได้ดังนี้:

  • com.foo.MyType - ชื่อของชั้นคือระดับคือในแพคเกจMyTypecom.foo
  • @ - รวมสตริงเข้าด้วยกัน
  • 2f92e0f4 hashcode ของวัตถุ

ชื่อของชั้นเรียนอาร์เรย์มีลักษณะที่แตกต่างกันเล็ก ๆ น้อย ๆ ซึ่งจะมีการอธิบายได้ดีใน Javadocs Class.getName()สำหรับ ตัวอย่างเช่น[Ljava.lang.Stringหมายถึง:

  • [- อาร์เรย์แบบมิติเดียว (ตรงข้ามกับ[[หรือ[[[เป็นต้น)
  • L - อาร์เรย์มีคลาสหรือส่วนต่อประสาน
  • java.lang.String - ประเภทของวัตถุในอาร์เรย์

การปรับแต่งเอาต์พุต

หากต้องการพิมพ์สิ่งที่แตกต่างเมื่อคุณเรียกSystem.out.println(myObject)คุณต้องแทนที่toString()วิธีการในชั้นเรียนของคุณเอง นี่คือตัวอย่างง่ายๆ:

public class Person {

  private String name;

  // constructors and other methods omitted

  @Override
  public String toString() {
    return name;
  }
}

ตอนนี้ถ้าเราพิมพ์เราจะเห็นชื่อของพวกเขามากกว่าPersoncom.foo.Person@12345678

จำไว้ว่าtoString()เป็นเพียงหนึ่งในวิธีการที่วัตถุจะถูกแปลงเป็นสตริง โดยทั่วไปผลลัพธ์นี้ควรอธิบายวัตถุของคุณอย่างชัดเจนและรัดกุม อาจดีกว่าtoString()สำหรับPersonชั้นเรียนของเรา:

@Override
public String toString() {
  return getClass().getSimpleName() + "[name=" + name + "]";
}

Person[name=Henry]ซึ่งจะพิมพ์เช่น นั่นเป็นข้อมูลที่มีประโยชน์จริงๆสำหรับการดีบัก / ทดสอบ

String toElegantReport() {...}หากคุณต้องการที่จะมุ่งเน้นเพียงแง่มุมหนึ่งของวัตถุของคุณหรือรวมจำนวนมากของการจัดรูปแบบทันสมัยที่คุณอาจจะดีกว่าที่จะกำหนดวิธีการแยกจากกันแทนเช่น


สร้างเอาต์พุตโดยอัตโนมัติ

IDEsจำนวนมากให้การสนับสนุนtoString()วิธีการสร้างอัตโนมัติตามฟิลด์ในชั้นเรียน ดูเอกสารสำหรับEclipseและIntelliJยกตัวอย่างเช่น

ห้องสมุด Java ยอดนิยมหลายแห่งเสนอคุณสมบัตินี้เช่นกัน ตัวอย่างบางส่วน ได้แก่ :


การพิมพ์กลุ่มของวัตถุ

ดังนั้นคุณได้สร้างสิ่งที่ดีtoString()สำหรับชั้นเรียนของคุณ จะเกิดอะไรขึ้นถ้าคลาสนั้นถูกวางในอาร์เรย์หรือคอลเล็กชัน

อาร์เรย์

หากคุณมีอาเรย์ของวัตถุคุณสามารถโทรArrays.toString()เพื่อสร้างการแสดงเนื้อหาของอาเรย์อย่างง่าย ตัวอย่างเช่นพิจารณาอาร์เรย์ของPersonวัตถุนี้:

Person[] people = { new Person("Fred"), new Person("Mike") };
System.out.println(Arrays.toString(people));

// Prints: [Fred, Mike]

หมายเหตุ: นี่เป็นการเรียกใช้เมธอดสแตติกที่เรียกว่าtoString()ในคลาส Arrays ซึ่งแตกต่างจากสิ่งที่เราได้พูดถึงข้างต้น

หากคุณมีอาเรย์หลายมิติคุณสามารถใช้Arrays.deepToString()เพื่อให้ได้ผลลัพธ์ในประเภทเดียวกัน

คอลเลกชัน

คอลเลกชันส่วนใหญ่จะให้ผลลัพธ์ที่ดีโดยอิงจากการเรียก.toString()ใช้ทุกองค์ประกอบ

List<Person> people = new ArrayList<>();
people.add(new Person("Alice"));
people.add(new Person("Bob"));    
System.out.println(people);

// Prints [Alice, Bob]

ดังนั้นคุณเพียงแค่ต้องให้แน่ใจว่าองค์ประกอบรายการของคุณกำหนดสิ่งที่ดีtoString()ตามที่กล่าวไว้ข้างต้น


return String.format( getClass().getSimpleName() + "[ name=%s ]", name);และแทนที่จะใช้nameมันควรใช้ getter getName()(แต่ getters ถูกละเว้นในคลาส Person ... ) แต่ถ้าใช้ getter ...return String.format( getClass().getSimpleName() + "[ name=%s ]", getName());
CrandellWS

ถ้าฉันมีสองคลาสในไฟล์ java แล้ววิธีการสร้างวัตถุของคลาสที่ไม่สาธารณะ A.java สาธารณะชั้น A {} คลาส B {} ------ C.java สาธารณะชั้น C {A = ใหม่ A ( ); }
yatinbc

โปรดทราบว่ามีเวอร์ชันที่มีการโอเวอร์โหลดมากเกินไปArrays.toString()ดังนั้นคุณจึงสามารถใช้สำหรับอาร์เรย์ที่มีเนื้อหาดั้งเดิมได้ ( int[], double[]) ยังArrays.deepToString()จัดการอาร์เรย์หลายมิติของดั้งเดิมได้อย่างดี
Ole VV

1
@ MasterJoe2 ไม่แน่ใจบางทีพวกเขาคิดว่ามันน่าจะพยายามเข้ารหัสค่าลบในสตริงหรือไม่?
Duncan Jones

55

ฉันคิดว่า apache ให้คลาส util ที่ดีกว่าซึ่งมีฟังก์ชั่นในการรับสตริง

ReflectionToStringBuilder.toString(object)

5
นี่เป็นข้อดีที่ไม่จำเป็นต้องแก้ไขชั้นเรียนซึ่งบางครั้งก็เป็นไปไม่ได้ อย่างไรก็ตามฉันจะพิมพ์ซ้ำวัตถุที่ซ้อนกันด้วยซ้ำได้อย่างไร
lukas84

35

ชั้นในชวาทุกรายมีวิธีการในการได้โดยเริ่มต้นที่เรียกว่าถ้าคุณผ่านวัตถุของคลาสที่บางอย่างเพื่อtoString() System.out.println()โดยค่าเริ่มต้นการเรียกนี้ส่งคืน className @ hashcode ของวัตถุนั้น

{
    SomeClass sc = new SomeClass();
    // Class @ followed by hashcode of object in Hexadecimal
    System.out.println(sc);
}

คุณสามารถแทนที่เมธอด toString ของคลาสเพื่อรับเอาต์พุตที่ต่างกัน ดูตัวอย่างนี้

class A {
    String s = "I am just a object";
    @Override
    public String toString()
    {
        return s;
    }
}

class B {
    public static void main(String args[])
    {
        A obj = new A();
        System.out.println(obj);
    }
}

3
นี่เป็นคำตอบที่สั้นและดี แต่เพื่อชี้แจงว่าทำไม OP ถึงได้รับ[Lcom.foo.Person;@28a418fcเป็นเอาต์พุต: นั่นคือผลลัพธ์ของtoString()เมธอดด้วยเช่นกัน แต่เป็นคำตอบที่นำมาใช้ในคลาสที่สร้างขึ้นที่รันไทม์สำหรับประเภทPerson[]ไม่ใช่Person(ดูstackoverflow.com/a/8546532/1542343 )
gvlasov

เอาต์พุตนี้หมายถึง package.Class@Hashcode วิธีการเริ่มต้น toString () มีประเภทผลตอบแทนเช่น return Object.hasCode () หรือข้อความสั่งคืนที่คล้ายกันซึ่งกำลังส่งคืน hashcode ในรูปแบบเลขฐานสิบหกพร้อมกับชื่อคลาส
Pankaj Manali

14

ใน Eclipse ไปที่คลาสของคุณคลิกขวา -> ซอร์ส -> สร้างtoString();

มันจะแทนที่toString()วิธีการและจะพิมพ์วัตถุของชั้นเรียนที่


10

ฉันชอบที่จะใช้ฟังก์ชั่นยูทิลิตี้ที่ใช้GSONเพื่อยกเลิกการทำให้เป็นวัตถุวัตถุ Java เป็นสตริง JSON

/**
 * This class provides basic/common functionalities to be applied on Java Objects.
 */
public final class ObjectUtils {

    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();

    private ObjectUtils() {
         throw new UnsupportedOperationException("Instantiation of this class is not permitted in case you are using reflection.");
    }

    /**
     * This method is responsible for de-serializing the Java Object into Json String.
     *
     * @param object Object to be de-serialized.
     * @return String
     */
    public static String deserializeObjectToString(final Object object) {
        return GSON.toJson(object);
    }
}

มันควรจะเป็นreturn Gson.toJson(object);อย่างอื่นทำงานอย่างสมบูรณ์
Nakrule

มันเป็นอย่างนั้นเท่านั้น
Agam

5

ใน Intellij คุณสามารถสร้างวิธี toString โดยอัตโนมัติโดยกด alt + inset จากนั้นเลือก toString () ที่นี่เป็นตัวเลือกสำหรับคลาสทดสอบ:

public class test  {
int a;
char b;
String c;
Test2 test2;

@Override
public String toString() {
    return "test{" +
            "a=" + a +
            ", b=" + b +
            ", c='" + c + '\'' +
            ", test2=" + test2 +
            '}';
 }
}

อย่างที่คุณเห็นมันสร้าง String โดยการเชื่อมโยงหลาย ๆ แอ็ตทริบิวต์ของคลาสเพื่อให้มันพิมพ์ค่าของมันและสำหรับประเภทการอ้างอิงที่จะใช้ประเภทคลาสของพวกเขา (ในกรณีนี้กับวิธีสตริงของ Test2)


4

โดยค่าเริ่มต้นทุกวัตถุใน Java มีtoString()วิธีการที่ส่งออก ObjectType @ HashCode

ถ้าคุณต้องการข้อมูลที่มีความหมายมากกว่านี้คุณจำเป็นต้องแทนที่toString()เมธอดในคลาสของคุณ

public class Person {
  private String name;

  // constructor and getter/setter omitted

  // overridding toString() to print name
  public String toString(){
     return name;  
  }
}

ตอนนี้เมื่อคุณพิมพ์วัตถุบุคคลที่ใช้System.out.prtinln(personObj);มันจะพิมพ์ชื่อของบุคคลแทน classname และ hashcode

ในกรณีที่สองของคุณเมื่อคุณพยายามพิมพ์อาร์เรย์มันจะพิมพ์[Lcom.foo.Person;@28a418fcArray type และ hashcode


หากคุณต้องการพิมพ์ชื่อบุคคลมีหลายวิธี

คุณสามารถเขียนฟังก์ชั่นของคุณเองที่ทำซ้ำแต่ละคนและพิมพ์

void printPersonArray(Person[] persons){
    for(Person person: persons){
        System.out.println(person);
    }
}

คุณสามารถพิมพ์โดยใช้ Arrays.toString () ดูเหมือนจะง่ายที่สุดสำหรับฉัน

 System.out.println(Arrays.toString(persons));
 System.out.println(Arrays.deepToString(persons));  // for nested arrays  

คุณสามารถพิมพ์ด้วยวิธี java 8 (ใช้สตรีมและการอ้างอิงวิธีการ)

 Arrays.stream(persons).forEach(System.out::println);

อาจมีวิธีอื่นเช่นกัน หวังว่านี่จะช่วยได้ :)


3

หากคุณพิมพ์วัตถุใด ๆ ของบุคคลโดยตรงClassName@HashCodeรหัสนี้จะเป็นรหัส

ในกรณีของคุณcom.foo.Person@2f92e0f4กำลังพิมพ์ ในกรณีที่Personเป็นชั้นที่วัตถุที่เป็นและ2f92e0f4เป็น hashCode ของวัตถุ

public class Person {
  private String name;

  public Person(String name){
  this.name = name;
  }
  // getter/setter omitted

   @override
   public String toString(){
        return name;
   }
}

ตอนนี้ถ้าคุณพยายามใช้วัตถุของ Personแล้วมันจะพิมพ์ชื่อ

Class Test
 {
  public static void main(String... args){
    Person obj = new Person("YourName");
    System.out.println(obj.toString());
  }
}

2

หากคุณดูที่คลาส Object (คลาสพาเรนต์ของคลาสทั้งหมดใน Java) การใช้เมธอด toString () คือ

    public String toString() {
       return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

เมื่อใดก็ตามที่คุณพิมพ์วัตถุใด ๆ ใน Java จากนั้น toString () จะถูกเรียก ตอนนี้ก็ขึ้นอยู่กับคุณถ้าคุณแทนที่ toString () แล้ววิธีการของคุณจะเรียกการเรียกวิธีการวัตถุคลาสอื่น ๆ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.