Apa perbedaan antara a.getClass () dan A.class di Java?

101

Di Jawa, apa pro / kontra seputar pilihan untuk menggunakan a.getClass()atau A.class? Keduanya dapat digunakan di mana pun yang Class<?>diharapkan, tetapi saya membayangkan bahwa akan ada kinerja atau manfaat halus lainnya untuk menggunakan keduanya dalam keadaan yang berbeda (seperti halnya dengan Class.forName()dan ClassLoader.loadClass().

IAmYourFaja
sumber

Jawaban:

163

Saya tidak akan membandingkannya dalam hal pro / kontra karena mereka memiliki tujuan yang berbeda dan jarang ada "pilihan" untuk dibuat di antara keduanya.

  • a.getClass()mengembalikan jenis waktu proses a. Yaitu, jika sudah A a = new B();maka a.getClass()akan mengembalikan Bkelas.

  • A.classmengevaluasi Akelas secara statis , dan digunakan untuk tujuan lain yang sering dikaitkan dengan refleksi.

Dalam hal kinerja, mungkin ada perbedaan yang terukur, tetapi saya tidak akan mengatakan apa-apa tentang itu karena pada akhirnya itu tergantung pada JVM dan / atau kompiler.


Posting ini telah ditulis ulang sebagai artikel di sini .

aioobe
sumber
2
Bagaimana dengan A.class.getClass()?
pengguna1870400
5
Itu akan memberi Anda Classobjek dari kelas yang mewakili A.classobjek yang lagi-lagi merupakan turunan dari java.lang.Class.
aioobe
Bagaimana dengan A.getClass().class?
Shikhar Mainalee
@ShikharMainalee, itu tidak masuk akal jika itu Aadalah kelas. Tidak ada getClassmetode statis di kelas.
aioobe
bagaimana hal ini berkaitan dengan saran di sini bahwa mereka juga menunjuk ke pemuat kelas yang berbeda. Ini mungkin juga perbedaan yang signifikan antara keduanya?
Jim
32

Mereka sebenarnya berbeda dalam hal tempat Anda dapat menggunakannya. A.classbekerja pada waktu kompilasi sementara a.getClass()membutuhkan sebuah instance dari tipe Adan bekerja pada waktu proses.

Mungkin ada perbedaan kinerja juga. Sementara A.classdapat diselesaikan oleh compiler karena mengetahui jenis sebenarnya A, a.getClass()adalah panggilan metode virtual yang terjadi pada waktu proses.

Sebagai referensi, bytecode penargetan compiler biasanya memancarkan instruksi berikut untuk Integer.getClass():

aload_1
invokevirtual   #3; //Method java/lang/Object.getClass:()Ljava/lang/Class;

dan berikut ini untuk Integer.class:

//const #3 = class  #16;    //  java/lang/Integer

ldc_w   #3; //class java/lang/Integer

Yang pertama biasanya akan melibatkan pengiriman metode virtual dan oleh karena itu mungkin membutuhkan waktu lebih lama untuk dieksekusi. Itu pada akhirnya tergantung JVM.

Tomasz Nurkiewicz
sumber
1
[1] secara teknis Spesifikasi Bahasa Java tidak menyebutkan kumpulan konstan sama sekali ...
aioobe
@aioobe: Saya kira Anda benar, itulah mengapa saya memeriksa bytecode yang dihasilkan oleh Sun JDK.
Tomasz Nurkiewicz
1
... yang secara teknis juga tidak memberikan jawaban otoritatif, karena Spesifikasi Bahasa Java bahkan tidak menyebutkan bytecode dalam hal semantik.
aioobe
@aioobe: Saya mengerti maksud Anda. Saya tidak pernah menyebutkan JLS, hanya memeriksa secara empiris cara kerjanya, karena saya tidak yakin. OP bertanya tentang kinerja dan memeriksa bytecode sepertinya ide yang bagus. Jangan ragu untuk mengedit posting saya atau menghapus pernyataan ambigu
Tomasz Nurkiewicz
1
memutar kembali jika Anda tidak menyukainya ;-)
aioobe
8

lihat contoh di bawah ini

a.getClass()!= A.class, Yaitu a bukanlah turunan dari A tetapi dari sub kelas anonim A

a.getClass() membutuhkan instance tipe A

Massimiliano Peluso
sumber
4

Gunakan a.getClassjika Anda memiliki instance kelas / jenis dan Anda ingin mendapatkan jenis yang tepat. while a.classdigunakan ketika Anda memiliki typetersedia dan Anda ingin membuat instance darinya.
Juga getClass()mengembalikan jenis runtime dari instance saat .classdievaluasi pada waktu kompilasi.
Mempertimbangkan kinerja getClass()dan .class, .classmemiliki kinerja yang lebih baik dari getClass() .
Contoh:

public class PerfomanceClass {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        long time=System.nanoTime();
        Class class1="String".getClass();
        class1="String".getClass();
        class1="String".getClass();
        class1="String".getClass();

        System.out.println("time (getClass()) :"+(System.nanoTime()-time)+" ns");     


        long time2=System.nanoTime();
        Class class2=String.class;
        class2=String.class;
        class2=String.class;
        class2=String.class;

        System.out.println("time (.class):"+(System.nanoTime()-time2)+" ns");
    }

}

Keluaran:

time (getClass()) : 79410 ns
time (.class)     : 8032 ns
Rohan
sumber
1

Ada satu perbedaan yang ingin saya tambahkan. Katakanlah Anda memiliki kelas konstruktor seperti yang ditunjukkan di bawah ini dengan kelas super yang mengambil objek Kelas. Anda ingin bahwa setiap kali objek subkelas dibuat, objek kelas subkelas harus diteruskan ke kelas super. Kode di bawah ini tidak akan dikompilasi karena Anda tidak dapat memanggil metode instance dalam konstruktor. Dalam hal ini jika Anda mengganti myObject.getClass()dengan MyClass.class. Ini akan berjalan dengan sempurna.

Class MyClass
{
    private MyClass myObject = new MyClass();
    public MyClass()
    {
        super(myObject.getClass()); //error line compile time error
    }
}
prashant
sumber
2
Memiliki instance dari kelas yang sama sebagai variabel instan dari kelas yang sama .... Anda akan kehabisan ruang heap saat Anda membuat objek secara rekursif.
Aniket Thakur
1

Menariknya, perbedaan kinerja yang disebutkan dalam contoh di atas, tampaknya terkait dengan alasan lain. Menggunakan 3 Kelas yang berbeda, rata-rata kinerjanya akan hampir sama:

import java.util.LinkedHashMap;
public class PerfomanceClass {

public static void main(String[] args) {

    long time = System.nanoTime();
    Class class1 = "String".getClass();
    Class class11 = "Integer".getClass();
    Class class111 = "LinkedHashMap".getClass();

    System.out.println("time (getClass()) :" + (System.nanoTime() - time) + " ns");

    long time2 = System.nanoTime();
    Class class2 = String.class;
    Class class22 = Integer.class;
    Class class222 = LinkedHashMap.class;

    System.out.println("time (.class):" + (System.nanoTime() - time2) + " ns");
} }

Outputnya akan seperti ini:

time (getClass()) :23506 ns 
time (.class):23838 ns

Dan mengubah urutan panggilan bahkan akan menghasilkan getClass()lebih cepat.

import java.util.LinkedHashMap;

public class PerfomanceClass {

public static void main(String[] args) {
    long time2 = System.nanoTime();
    Class class2 = LinkedHashMap.class;

    System.out.println("time (.class):" + (System.nanoTime() - time2) + " ns");

    long time = System.nanoTime();
    Class class1 = "LinkedHashMap".getClass();

    System.out.println("time (getClass()) :" + (System.nanoTime() - time) + " ns");
}}

Keluaran:

time (.class):33108 ns
time (getClass()) :6622 ns
pengguna4287932
sumber
"Menggunakan 3 Kelas berbeda". Tetapi di bagian getClass () Anda tidak menggunakan 3 kelas yang berbeda. Ini semua adalah String dan oleh karena itu getClass akan mengembalikan java.lang.String untuk semua instance.
Kilian
1

p.getClass(), di mana padalah turunan dari suatu objek, mengembalikan kelas waktu proses dari objek ini p. ptidak bisa menjadi tipe yang akan menyebabkan kesalahan waktu kompilasi, itu harus merupakan turunan dari sebuah objek.

// B extends A
A a = new B();
System.out.println(a.getClass());
//output: class B

p.classadalah ekspresi. Ini .classdisebut sintaks kelas. padalah tipe. Ini bisa berupa nama kelas, antarmuka atau larik dan bahkan tipe primitif. a.getClass() == B.class.

Jika sebuah tipe tersedia dan ada sebuah instance maka dimungkinkan untuk menggunakan getClassmetode untuk mendapatkan nama tipe tersebut. Jika tidak, gunakan .classsintaks

triplestone
sumber