Bagaimana cara menentukan kelas objek?

510

Jika kelas Bdan kelas Cmemperluas kelas Adan saya memiliki objek tipe Batau C, bagaimana saya bisa menentukan tipe mana yang merupakan instance?

pembawa
sumber
14
@starblue Casting akan menjadi hal pertama yang terlintas dalam pikiran. Saya ragu operator instance akan ada jika tidak ada kebutuhan untuk itu.
b1nary.atr0phy
@ b1nary.atr0phy bukankah sebaiknya menggunakan operator isntanceof terlebih dahulu. Jika ada cast ke tipe tidak kompatibel, saya percaya bahwa akan menghasilkan ClassCastException
committedandroider

Jawaban:

801
if (obj instanceof C) {
//your code
}
IAdapter
sumber
31
Penting untuk mencatat cek balik atau cara memeriksa apakah Obyek BUKAN turunan kelas:if(!(obj instanceof C))
Dzhuneyt
32
Saya percaya metode getClass () adalah jawaban untuk pertanyaan awal. Dalam hal ini (instance instanceof A) juga akan memberikan output "benar" tetapi tujuannya adalah untuk menemukan kelas runtime objek dalam gambar. Jika Parent1 diperpanjang oleh Child1 dan Child2, coba code Child1 berikut child1 = new Child1 (); Parent1 parentChild = new Child2 (); Child2 child2 = new Child2 (); (child1 instance dari Parent1); (child1 instanceof Child1); (instance parentChild Child2); (instance parentChild dari Parent1); (instance parentChild Child1); code , itu dapat menghapus maksud instanceof.
Bhavesh Agarwal
Pasti merupakan alternatif untuk membangun antarmuka
JohnMerlino
3
Bagaimana jika saya memiliki dua kelas yang mengimplementasikan antarmuka tunggal? Bagaimana cara membedakan kelas objek yang tepat?
olyv
3
Satu hal, itu tidak berfungsi jika obj adalah null. Solusinya kemudian adalah ParentInterface.class.isAssignableFrom (Child.class)
alexbt
351

Gunakan Object.getClass () . Ini mengembalikan tipe objek runtime.

Bill the Lizard
sumber
12
Ini sebenarnya cara Anda menentukan kelas objek
AA_PV
jawaban sempurna @Bill
gaurav
1
Tidak yakin mengapa ini bukan jawaban yang paling populer
eicksl
178

Beberapa jawaban benar disajikan, tetapi masih ada lebih banyak metode: Class.isAssignableFrom()dan hanya berusaha untuk melemparkan objek (yang mungkin melempar a ClassCastException).

Cara yang mungkin dirangkum

Mari merangkum cara-cara yang mungkin untuk menguji apakah suatu objek objadalah turunan dari tipe C:

// Method #1
if (obj instanceof C)
    ;

// Method #2
if (C.class.isInstance(obj))
    ;

// Method #3
if (C.class.isAssignableFrom(obj.getClass()))
    ;

// Method #4
try {
    C c = (C) obj;
    // No exception: obj is of type C or IT MIGHT BE NULL!
} catch (ClassCastException e) {
}

// Method #5
try {
    C c = C.class.cast(obj);
    // No exception: obj is of type C or IT MIGHT BE NULL!
} catch (ClassCastException e) {
}

Perbedaan dalam nullpenanganan

Namun ada perbedaan nullpenanganan:

  • Dalam 2 metode pertama ekspresi mengevaluasi falsejika objini null( nulltidak instance dari apa-apa).
  • Metode ke-3 akan melempar dengan NullPointerExceptionjelas.
  • Metode 4 dan 5 sebaliknya menerima nullkarena nulldapat digunakan untuk semua jenis!

Yang perlu diingat: null ini bukan turunan dari tipe apa pun tetapi dapat dilemparkan ke tipe apa pun.

Catatan

  • Class.getName()tidak boleh digunakan untuk melakukan tes "adalah-contoh-dari" karena objek bukan tipe Ctetapi subkelasnya, ia mungkin memiliki nama dan paket yang sama sekali berbeda (oleh karena itu nama kelas jelas tidak akan cocok) tetapi itu adalah masih bertipe C.
  • Untuk alasan pewarisan yang sama Class.isAssignableFrom()tidak simetris :
    obj.getClass().isAssignableFrom(C.class)akan kembali falsejika jenisnya objadalah subkelas dari C.
icza
sumber
6
Ini adalah ringkasan yang sangat bagus dari banyak jebakan dalam metode yang berbeda. Terima kasih atas penulisan lengkapnya!
Kelsin
32

Kamu bisa menggunakan:

Object instance = new SomeClass();
instance.getClass().getName(); //will return the name (as String) (== "SomeClass")
instance.getClass(); //will return the SomeClass' Class object

HTH. Tapi saya pikir sebagian besar waktu itu bukan praktik yang baik untuk menggunakannya untuk aliran kontrol atau sesuatu yang serupa ...

Johannes Weiss
sumber
Saya menggunakannya untuk membuat logger generik, Jadi saya mengirim objek ke logger, dan log tergantung pada nama kelas objek, daripada memberikan tag log atau string log setiap kali. terima kasih
MBH
24

Setiap penggunaan metode yang disarankan dianggap sebagai bau kode yang didasarkan pada desain OO yang buruk.

Jika desain Anda bagus, Anda seharusnya tidak perlu menggunakan getClass()atau instanceof.

Salah satu metode yang disarankan akan dilakukan, tetapi hanya sesuatu yang perlu diingat, desain-bijaksana.

Yuval Adam
sumber
3
Ya, mungkin 99% penggunaan getClass dan instanceof dapat dihindari dengan panggilan metode polimorfik.
Bill the Lizard
3
saya setuju. dalam hal ini saya sedang bekerja dengan objek yang dihasilkan dari xml mengikuti skema yang dirancang dengan buruk yang tidak saya miliki.
operator
28
Tidak selamanya. Kadang-kadang pemisahan antarmuka bagus. Ada saat-saat ketika Anda ingin tahu apakah A adalah B, tetapi Anda tidak ingin membuatnya wajib bahwa A adalah B, karena hanya A yang diperlukan untuk sebagian besar fungsi - B memiliki fungsi opsional.
MetroidFan2002
8
Juga, ada saat-saat ketika Anda perlu memastikan bahwa objek tersebut memiliki kelas yang sama dengan yang Anda bandingkan; misalnya saya ingin mengganti metode equals Object ketika saya membuat kelas saya sendiri. Saya selalu memverifikasi objek yang masuk adalah dari kelas yang sama.
StackOverflowed
58
Juga, saya akan mengatakan mengatakan kepada orang-orang sesuatu yang buruk tanpa menjelaskan dengan tepat mengapa atau memberikan referensi ke kertas, buku, atau sumber daya lain di mana masalah ini dijelaskan dianggap tidak konstruktif. Karena itu dan mengetahui bahwa saya berada di StackOverflow, saya tidak tahu mengapa orang begitu banyak memilih jawaban ini. Sesuatu sedang berubah di sini ...
Adrián Pérez
15

Kita dapat menggunakan refleksi dalam kasus ini

objectName.getClass().getName();

Contoh:-

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    String name = request.getClass().getName();
}

Dalam hal ini Anda akan mendapatkan nama kelas yang objek dilewatkan ke HttpServletRequestvariabel referensi antarmuka.

pengguna1884500
sumber
ini benar. hanya menggunakan obj.getClass()akan mengembalikan className, awalan dengan kataclass
x6iae
request.getClass().getName();mencetak semua paket! bersama dengan nama kelas
shareef
13

Ada juga .isInstancemetode di kelas " Class". jika Anda mendapatkan kelas objek melalui myBanana.getClass()Anda dapat melihat apakah objek Anda myAppleadalah instance dari kelas yang sama dengan myBananavia

myBanana.getClass().isInstance(myApple)
Andreas Petersson
sumber
1

mengecek dengan isinstance()tidak akan cukup jika Anda ingin tahu di run time. menggunakan:

if(someObject.getClass().equals(C.class){
    // do something
}
Alon Gouldman
sumber
0

Saya menggunakan fungsi blow di kelas GeneralUtils saya, periksa semoga bermanfaat

    public String getFieldType(Object o) {
    if (o == null) {
        return "Unable to identify the class name";
    }
    return o.getClass().getName();
}
Ahmed Salem
sumber
0

Saya Menggunakan Java 8 generics untuk mendapatkan instance objek saat runtime daripada harus menggunakan switch case

 public <T> void print(T data) {
    System.out.println(data.getClass().getName()+" => The data is " + data);
}

lulus semua jenis data dan metode ini akan mencetak jenis data yang Anda lewati saat memanggilnya. misalnya

    String str = "Hello World";
    int number = 10;
    double decimal = 10.0;
    float f = 10F;
    long l = 10L;
    List list = new ArrayList();
    print(str);
    print(number);
    print(decimal);
    print(f);
    print(l);
    print(list);

Berikut ini adalah output

java.lang.String => The data is Hello World
java.lang.Integer => The data is 10
java.lang.Double => The data is 10.0
java.lang.Float => The data is 10.0
java.lang.Long => The data is 10
java.util.ArrayList => The data is []
Saurabh Verma
sumber