Bagaimana cara mencetak objek Java saya tanpa mendapatkan "SomeType @ 2f92e0f4"?

301

Saya memiliki kelas yang didefinisikan sebagai berikut:

public class Person {
  private String name;

  // constructor and getter/setter omitted
}

Saya mencoba mencetak instance kelas saya:

System.out.println(myPerson);

tapi aku punya output sebagai berikut: com.foo.Person@2f92e0f4.

Hal serupa terjadi ketika saya mencoba mencetak array Personobjek:

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

Saya mendapat hasilnya: [Lcom.foo.Person;@28a418fc

Apa artinya output ini? Bagaimana cara mengubah output ini sehingga berisi nama orang saya? Dan bagaimana cara mencetak koleksi benda saya?

Catatan : ini dimaksudkan sebagai tanya jawab kanonik tentang subjek ini.

Duncan Jones
sumber
1
Anda dapat menggunakan perpustakaan GSON untuk mengonversi objek ke json dan sebaliknya. Sangat berguna untuk debugging.
Ashish Rawat

Jawaban:

403

Latar Belakang

Semua objek Java memiliki toString()metode, yang dipanggil ketika Anda mencoba dan mencetak objek.

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

Metode ini didefinisikan dalam Objectkelas (superclass dari semua objek Java). The Object.toString()method mengembalikan string mencari cukup jelek, terdiri dari nama kelas, sebuah @simbol dan kode hash dari objek dalam heksadesimal. Kode untuk ini terlihat seperti:

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

Karena itu hasil seperti com.foo.MyType@2f92e0f4itu dapat dijelaskan sebagai:

  • com.foo.MyType - nama kelas, yaitu kelas yang ada MyTypedalam paket com.foo.
  • @ - Menggabungkan string bersama
  • 2f92e0f4 kode hash objek.

Nama kelas array terlihat sedikit berbeda, yang dijelaskan dengan baik di Javadocs untuk Class.getName(). Misalnya, [Ljava.lang.Stringberarti:

  • [- array satu dimensi (sebagai lawan [[atau [[[dll.)
  • L - array berisi kelas atau antarmuka
  • java.lang.String - jenis objek dalam array

Menyesuaikan Output

Untuk mencetak sesuatu yang berbeda ketika Anda menelepon System.out.println(myObject), Anda harus menimpa para toString()metode di kelas Anda sendiri. Berikut ini contoh sederhana:

public class Person {

  private String name;
  
  // constructors and other methods omitted
  
  @Override
  public String toString() {
    return name;
  }
}

Sekarang jika kita mencetak a Person, kita melihat namanya daripada com.foo.Person@12345678.

Ingatlah bahwa toString()itu hanyalah salah satu cara bagi suatu objek untuk dikonversi menjadi string. Biasanya keluaran ini harus sepenuhnya menggambarkan objek Anda dengan cara yang jelas dan ringkas. Yang lebih baik toString()untuk Personkelas kita mungkin:

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

Yang akan mencetak, misalnya Person[name=Henry],. Itu adalah bagian data yang sangat berguna untuk debugging / pengujian.

Jika Anda ingin fokus hanya pada satu aspek objek Anda atau memasukkan banyak format jazzy, Anda mungkin lebih baik untuk mendefinisikan metode terpisah, misalnya String toElegantReport() {...}.


Menghasilkan Output secara otomatis

Banyak IDE menawarkan dukungan untuk toString()metode pembuatan-otomatis , berdasarkan bidang di kelas. Lihat dokumen untuk Eclipse dan IntelliJ , misalnya.

Beberapa perpustakaan Java populer juga menawarkan fitur ini. Beberapa contoh termasuk:


Mencetak kelompok objek

Jadi, Anda telah membuat yang bagus toString()untuk kelas Anda. Apa yang terjadi jika kelas itu ditempatkan ke dalam array atau koleksi?

Array

Jika Anda memiliki array objek, Anda bisa menelepon Arrays.toString()untuk menghasilkan representasi sederhana dari isi array. Misalnya, pertimbangkan berbagai Personobjek ini:

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

// Prints: [Fred, Mike]

Catatan: ini adalah panggilan ke metode statis yang disebuttoString() dalam kelas Array, yang berbeda dengan apa yang telah kita bahas di atas.

Jika Anda memiliki array multi dimensi , Anda dapat menggunakan Arrays.deepToString()untuk mencapai jenis output yang sama.

Koleksi

Sebagian besar koleksi akan menghasilkan output yang cantik berdasarkan panggilan .toString()pada setiap elemen.

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

// Prints [Alice, Bob]

Jadi, Anda hanya perlu memastikan elemen daftar Anda mendefinisikan yang bagus toString()seperti yang dibahas di atas.

Duncan Jones
sumber
return String.format( getClass().getSimpleName() + "[ name=%s ]", name);dan benar-benar alih-alih nameharus menggunakan getter getName()(tetapi getter dihilangkan di kelas Person ...) tetapi jika getter digunakan ...return String.format( getClass().getSimpleName() + "[ name=%s ]", getName());
CrandellWS
jika saya memiliki dua kelas dalam file java maka bagaimana membuat objek kelas yang tidak publik A.java public class A {} class B {} ------ C.java public class C {A a = new A ( ); }
yatinbc
Perhatikan bahwa ada versi overload Arrays.toString()sehingga Anda dapat menggunakannya untuk array primitif juga ( int[], double[]). Juga Arrays.deepToString()menangani array multidimensi primitif dengan baik.
Ole VV
1
@ MasterJoe2 Tidak yakin, mungkin mereka pikir itu akan terlihat jelek mencoba untuk menyandikan nilai negatif ke dalam string?
Duncan Jones
55

Saya pikir apache menyediakan kelas util yang lebih baik yang menyediakan fungsi untuk mendapatkan string

ReflectionToStringBuilder.toString(object)
Rohith K
sumber
5
Ini memiliki keuntungan yang tidak perlu diedit kelas, yang kadang-kadang tidak mungkin. Namun, bagaimana saya bisa mencetak objek bersarang secara rekursif juga?
lukas84
35

Setiap kelas di Jawa memiliki toString()metode di dalamnya secara default, yang dipanggil jika Anda melewatkan beberapa objek dari kelas itu ke System.out.println(). Secara default, panggilan ini mengembalikan kode nama className @ hash.

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

Anda bisa mengganti metode toString suatu kelas untuk mendapatkan hasil yang berbeda. Lihat contoh ini

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);
    }
}
Pankaj Manali
sumber
3
Ini adalah jawaban yang mudah dan singkat, tetapi untuk mengklarifikasi mengapa OP mendapatkan [Lcom.foo.Person;@28a418fcsebagai output: itu adalah output dari toString()metode juga, tetapi dari salah satu yang diimplementasikan di kelas yang dihasilkan saat runtime untuk jenisnya Person[], bukan Person(lihat stackoverflow.com/a/8546532/1542343 ).
gvlasov
Output ini berarti package.Class@Hashcode. Metode toString () default memiliki tipe return like. return Object.hasCode () atau pernyataan pengembalian serupa yang mengembalikan kode hash dalam bentuk heksadesimal bersama dengan nama kelas.
Pankaj Manali
14

Di Eclipse, Pergi ke kelas Anda, Klik kanan-> sumber-> Hasilkan toString() ;

Ini akan menimpa toString()metode dan akan mencetak objek dari kelas itu.

ketankk
sumber
10

Saya lebih suka menggunakan fungsi utilitas yang menggunakan GSON untuk menghapus serialisasi objek Java menjadi string 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);
    }
}
Agam
sumber
Seharusnya return Gson.toJson(object);, jika tidak bekerja dengan sempurna.
Nakrule
Hanya itu saja.
Agam
5

Di intellij Anda dapat membuat metode toString secara otomatis dengan menekan alt + inset dan kemudian memilih toString () di sini adalah put out untuk kelas tes:

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 +
            '}';
 }
}

Seperti yang Anda lihat, ia menghasilkan sebuah String dengan menggabungkan, beberapa atribut kelas, untuk primitif akan mencetak nilai-nilai mereka dan untuk tipe referensi itu akan menggunakan tipe kelas mereka (dalam hal ini untuk metode string dari Test2).

Mr.Q
sumber
4

Secara default, setiap Objek di Jawa memiliki toString() metode yang menampilkan ObjectType @ HashCode.

Jika Anda ingin informasi yang lebih bermakna maka Anda perlu mengganti toString()metode di kelas Anda.

public class Person {
  private String name;

  // constructor and getter/setter omitted

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

Sekarang ketika Anda mencetak objek orang menggunakan System.out.prtinln(personObj); akan mencetak nama orang tersebut alih-alih nama kelas dan kode hash.

Dalam kasus kedua Anda ketika Anda mencoba untuk mencetak array, ia mencetak [Lcom.foo.Person;@28a418fcjenis Array dan itu kode hash.


Jika Anda ingin mencetak nama orang, ada banyak cara.

Anda dapat menulis fungsi Anda sendiri yang mengulang setiap orang dan mencetak

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

Anda dapat mencetaknya menggunakan Arrays.toString (). Ini tampaknya yang paling sederhana bagi saya.

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

Anda bisa mencetaknya dengan cara java 8 (menggunakan stream dan referensi metode).

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

Mungkin ada cara lain juga. Semoga ini membantu. :)

dan.911
sumber
3

Jika Anda langsung mencetak objek Person, Ini akan menjadi ClassName@HashCode ke Kode.

dalam kasus Anda com.foo.Person@2f92e0f4semakin dicetak. Di mana Personkelas di mana objek milik dan 2f92e0f4kode hash Obyek.

public class Person {
  private String name;

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

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

Sekarang jika Anda mencoba Menggunakan objek Personmaka akan mencetak nama

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

Jika Anda melihat kelas Object (kelas Induk semua kelas di Jawa) implementasi metode toString () adalah

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

setiap kali Anda mencetak objek apa pun di Jawa, maka toString () akan dipanggil. Sekarang terserah Anda jika Anda mengganti toString () maka metode Anda akan memanggil panggilan metode kelas objek lainnya.

Yasir Shabbir Choudhary
sumber