instanceof Vs getClass ()

114

Saya melihat peningkatan kinerja saat menggunakan getClass()dan ==operator melebihi instanceOfoperator.

Object  str = new Integer("2000");

long starttime = System.nanoTime();

if(str instanceof String) {
    System.out.println("its string");
} else {
    if (str instanceof Integer) {
        System.out.println("its integer");

    }
}

System.out.println((System.nanoTime()-starttime));

starttime = System.nanoTime();

if(str.getClass() == String.class) {
    System.out.println("its string in equals");
} else {
    if(str.getClass() == Integer.class) {
        System.out.println("its integer");
    }
}

System.out.println((System.nanoTime()-starttime));

Apakah ada pedoman, yang mana yang akan digunakan getClass()atau instanceOf?

Diberikan skenario: Saya tahu kelas yang tepat untuk dicocokkan, yaitu String, Integer(ini adalah kelas terakhir), dll.

Apakah menggunakan instanceOfoperator merupakan praktik yang buruk?

gumpal
sumber
3
Ini dijelaskan di: stackoverflow.com/questions/596462/… .
Clement P
2
Metode waktu Anda menyebabkan penundaan buatan dan menghasilkan hasil pengaturan waktu yang salah. Tukar urutan saat Anda melakukan pemeriksaan dan Anda akan melihat pemeriksaan pertama yang Anda lakukan (baik == atau instance) akan selalu lebih lama. Saya kira itu println () s. Anda tidak boleh memasukkan hal-hal itu ke dalam blok waktu Anda.
kurtzmarc
Hanya satu komentar terpisah, untuk membandingkan kinerja, gunakan beberapa siklus iterasi (misalnya 10000) untuk meningkatkan akurasi. Satu doa bukanlah ukuran yang baik.
martins.tuga

Jawaban:

140

Alasan mengapa kinerja instanceofdan getClass() == ...berbeda adalah karena mereka melakukan hal yang berbeda.

  • instanceofmenguji apakah referensi objek di sisi kiri (kiri) adalah turunan dari tipe di sisi kanan (kanan) atau beberapa subtipe .

  • getClass() == ... menguji apakah jenisnya identik.

Jadi rekomendasinya adalah mengabaikan masalah kinerja dan menggunakan alternatif yang memberi Anda jawaban yang Anda butuhkan.

Apakah menggunakan instanceOfoperator merupakan praktik yang buruk?

Belum tentu. Terlalu sering menggunakan salah satu instanceOfatau getClass() mungkin "bau desain". Jika Anda tidak berhati-hati, Anda akan mendapatkan desain di mana penambahan subclass baru menghasilkan sejumlah besar pengerjaan ulang kode. Dalam kebanyakan situasi, pendekatan yang disukai adalah menggunakan polimorfisme.

Namun, ada kasus di mana ini BUKAN "bau desain". Misalnya, equals(Object)Anda perlu menguji tipe sebenarnya dari argumen tersebut, dan mengembalikan falsejika tidak cocok. Ini paling baik dilakukan dengan menggunakan getClass().


Istilah-istilah seperti "praktik terbaik", "praktik buruk", "bau desain", "antipattern", dan seterusnya harus digunakan dengan hemat dan diperlakukan dengan curiga. Mereka mendorong pemikiran hitam-putih. Lebih baik membuat penilaian Anda dalam konteks, daripada hanya berdasarkan dogma; misalnya, sesuatu yang dikatakan seseorang adalah "praktik terbaik".

Stephen C
sumber
@StephenC Seperti yang Anda katakan, itu adalah code smelluntuk menggunakan baik. Artinya, ini adalah konsekuensi dari kode desain yang buruk (non-polimorfik) yang membuat Anda menggunakan keduanya. dapatkah saya menyimpulkan penggunaan salah satunya dengan cara ini?
pertukaran berlebih
@ overexchange - 1) Saya bilang "overuse" bukan "use". 2) Selain itu, saya tidak mengerti apa yang Anda minta. Apa yang Anda maksud dengan "menyimpulkan penggunaan ..." ??? Kode menggunakan hal-hal ini, atau tidak.
Stephen C
Saya menyimpulkan bahwa, penggunaan instanceof& getClass()muncul karena desain kode yang buruk (non-polimorfik). Apakah saya benar?
pertukaran berlebih
5
@ overexchange - Anda tidak dapat secara valid menyimpulkan bahwa semua penggunaan instanceof(misalnya) adalah desain yang buruk. Ada situasi di mana ini mungkin merupakan solusi terbaik. Sama untuk getClass(). Saya akan mengulangi bahwa saya mengatakan "penggunaan berlebihan" dan bukan "penggunaan" . Setiap kasus perlu dinilai berdasarkan manfaatnya ... bukan dengan secara membabi buta menerapkan beberapa aturan dogmatis yang tidak berdasar.
Stephen C
44

Apakah Anda ingin mencocokkan kelas secara tepat , misalnya hanya mencocokkan FileInputStreamdaripada subkelas mana pun FileInputStream? Jika ya, gunakan getClass()dan ==. Saya biasanya akan melakukan ini dalam sebuah equals, sehingga sebuah instance dari X tidak dianggap sama dengan sebuah instance dari subclass X - jika tidak, Anda dapat mengalami masalah simetri yang rumit. Di sisi lain, itu biasanya lebih berguna untuk membandingkan bahwa dua objek memiliki kelas yang sama daripada satu kelas tertentu.

Jika tidak, gunakan instanceof. Perhatikan bahwa dengan getClass()Anda perlu memastikan bahwa Anda memiliki referensi non-null untuk memulai, atau Anda akan mendapatkan a NullPointerException, sedangkan instanceofhanya akan kembali falsejika operan pertama adalah null.

Secara pribadi menurut saya instanceoflebih idiomatis - tetapi menggunakan salah satu dari mereka secara ekstensif adalah bau desain dalam banyak kasus.

Jon Skeet
sumber
18

Saya tahu sudah lama sejak ini ditanyakan, tetapi saya belajar alternatif kemarin

Kami tahu Anda bisa melakukan:

if(o instanceof String) {   // etc

tetapi bagaimana jika Anda tidak tahu persis jenis kelas apa yang dibutuhkan? Anda tidak dapat secara umum melakukan:

if(o instanceof <Class variable>.getClass()) {   

karena memberikan kesalahan kompilasi.
Sebagai gantinya, berikut adalah alternatif - isAssignableFrom ()

Sebagai contoh:

public static boolean isASubClass(Class classTypeWeWant, Object objectWeHave) {

    return classTypeWeWant.isAssignableFrom(objectWeHave.getClass())
}
Andy Dingfelder
sumber
8
Jangan gunakan isAssignableFrom. Cara yang benar untuk menulis o instanceof Stringdengan refleksi adalah String.getClass().isInstance(o). Javadoc bahkan mengatakan demikian: Metode ini adalah padanan dinamis dari instanceofoperator bahasa Java .
Andreas
3

getClass () memiliki batasan bahwa objek hanya sama dengan objek lain dari kelas yang sama, jenis waktu proses yang sama, seperti yang diilustrasikan dalam output kode di bawah ini:

class ParentClass{
}
public class SubClass extends ParentClass{
    public static void main(String []args){
        ParentClass parentClassInstance = new ParentClass();
        SubClass subClassInstance = new SubClass();
        if(subClassInstance instanceof ParentClass){
            System.out.println("SubClass extends ParentClass. subClassInstance is instanceof ParentClass");
        }
        if(subClassInstance.getClass() != parentClassInstance.getClass()){
            System.out.println("Different getClass() return results with subClassInstance and parentClassInstance ");
        }
    }
}

Keluaran:

SubClass memperluas ParentClass. subClassInstance adalah turunan dari ParentClass.

GetClass () yang berbeda mengembalikan hasil dengan subClassInstance dan parentClassInstance.

Saurav Sahu
sumber