อะไรคือความแตกต่างระหว่าง a.getClass () และ A.class ใน Java?


102

ใน Java มีข้อดี / ข้อเสียอะไรอยู่รอบ ๆ ตัวเลือกที่จะใช้a.getClass()หรือA.class? สามารถใช้ได้ทุกที่ที่Class<?>คาดหวัง แต่ฉันคิดว่าจะมีประสิทธิภาพหรือประโยชน์ที่ลึกซึ้งอื่น ๆ ในการใช้ทั้งสองอย่างในสถานการณ์ที่แตกต่างกัน (เช่นเดียวกับที่มีClass.forName()และClassLoader.loadClass().

คำตอบ:


163

ฉันจะไม่เปรียบเทียบพวกเขาในแง่ของข้อดี / ข้อเสียเนื่องจากมีจุดประสงค์ที่แตกต่างกันและแทบไม่มี "ทางเลือก" ที่จะทำระหว่างสองอย่างนี้

  • a.getClass()ส่งคืนชนิดรันไทม์ของa. คือถ้าคุณมีA a = new B();แล้วa.getClass()จะส่งคืนBคลาส

  • A.classประเมินในAชั้นเรียนแบบคงที่และใช้เพื่อวัตถุประสงค์อื่นที่มักเกี่ยวข้องกับการสะท้อนกลับ

ในแง่ของประสิทธิภาพอาจมีความแตกต่างที่วัดได้ แต่ฉันจะไม่พูดอะไรเกี่ยวกับเรื่องนี้เพราะสุดท้ายแล้วมันก็ขึ้นอยู่กับ JVM และ / หรือคอมไพเลอร์


โพสต์นี้ได้รับการเขียนใหม่เป็นบทความที่นี่


2
แล้วไงA.class.getClass()?
user1870400

5
นั่นจะทำให้คุณได้รับClassวัตถุของคลาสที่เป็นตัวแทนของA.classวัตถุซึ่งเป็นตัวอย่างของjava.lang.Class.
aioobe

แล้วไงA.getClass().class?
Shikhar Mainalee

@ShikharMainalee นั่นไม่สมเหตุสมผลเลยถ้าAเป็นชั้น ไม่มีgetClassวิธีการคงที่ในชั้นเรียน
aioobe

สิ่งนี้เกี่ยวข้องกับข้อเสนอแนะที่นี่อย่างไรโดยชี้ไปที่รถตักระดับต่างๆ นี่อาจเป็นความแตกต่างอย่างมีนัยสำคัญระหว่างสอง?
จิม

32

จริงๆแล้วมันแตกต่างกันไปตามที่ที่คุณสามารถใช้ได้ A.classทำงานในเวลาคอมไพล์ในขณะที่a.getClass()ต้องการอินสแตนซ์ประเภทAและทำงานที่รันไทม์

อาจมีความแตกต่างด้านประสิทธิภาพเช่นกัน ในขณะA.classที่คอมไพลเลอร์สามารถแก้ไขได้เนื่องจากทราบชนิดที่แท้จริงAแต่a.getClass()เป็นการเรียกใช้เมธอดเสมือนที่เกิดขึ้นที่รันไทม์

สำหรับการอ้างอิงโดยทั่วไปคอมไพลเลอร์กำหนดเป้าหมาย bytecode จะแสดงคำแนะนำต่อไปนี้สำหรับInteger.getClass():

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

และสิ่งต่อไปนี้สำหรับInteger.class:

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

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

ก่อนหน้านี้มักจะเกี่ยวข้องกับการจัดส่งวิธีการเสมือนดังนั้นจึงน่าจะใช้เวลานานกว่าในการดำเนินการ อย่างไรก็ตามในที่สุดก็ขึ้นอยู่กับ JVM


1
[1] ในทางเทคนิคข้อกำหนดภาษา Java ไม่ได้กล่าวถึงพูลคงที่เลย ...
aioobe

@aioobe: ฉันเดาว่าคุณพูดถูกนั่นคือเหตุผลที่ฉันตรวจสอบรหัส bytecode ที่ Sun JDK สร้างขึ้น
Tomasz Nurkiewicz

1
... ซึ่งการพูดในทางเทคนิคไม่ได้ให้คำตอบที่เชื่อถือได้เช่นกันเนื่องจากข้อกำหนดภาษา Java ไม่ได้กล่าวถึงรหัสไบต์เมื่อพูดถึงความหมาย
aioobe

@aioobe: ฉันเข้าใจแล้ว ฉันไม่เคยพูดถึง JLS เพียงตรวจสอบเชิงประจักษ์ว่ามันทำงานอย่างไรเพราะฉันไม่แน่ใจ OP ถามเกี่ยวกับประสิทธิภาพและการตรวจสอบ bytecode ดูเหมือนจะเป็นความคิดที่ดี อย่าลังเลที่จะแก้ไขโพสต์ของฉันหรือลบข้อความที่คลุมเครือ
Tomasz Nurkiewicz

1
ย้อนกลับถ้าคุณไม่ชอบ ;-)
aioobe


4

ใช้a.getClassเมื่อคุณมีอินสแตนซ์ของคลาส / ประเภทและคุณต้องการได้ประเภทที่แน่นอน ในขณะที่a.classใช้เมื่อคุณมีtypeและคุณต้องการสร้างอินสแตนซ์ของมัน
ยังgetClass()ส่งคืนประเภทรันไทม์ของอินสแตนซ์ในขณะที่.classประเมินในเวลาคอมไพล์
พิจารณาจากประสิทธิภาพการทำงานของgetClass()และ.class, มีประสิทธิภาพดีกว่า.class ตัวอย่าง:getClass()

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");
    }

}

เอาท์พุต:

time (getClass()) : 79410 ns
time (.class)     : 8032 ns

1

มีความแตกต่างอย่างหนึ่งที่ฉันต้องการเพิ่ม สมมติว่าคุณมีคลาส a constructor ดังที่แสดงด้านล่างโดยมี super class ซึ่งรับคลาส object คุณต้องการให้เมื่อใดก็ตามที่วัตถุคลาสย่อยถูกสร้างขึ้นอ็อบเจ็กต์คลาสย่อยควรถูกส่งผ่านไปยังซูเปอร์คลาส โค้ดด้านล่างจะไม่คอมไพล์เนื่องจากคุณไม่สามารถเรียกใช้วิธีการอินสแตนซ์ในตัวสร้างได้ ในกรณีนั้นถ้าคุณแทนที่myObject.getClass()ด้วยMyClass.class. มันจะทำงานได้อย่างสมบูรณ์แบบ

Class MyClass
{
    private MyClass myObject = new MyClass();
    public MyClass()
    {
        super(myObject.getClass()); //error line compile time error
    }
}

2
การมีอินสแตนซ์ของคลาสเดียวกันกับตัวแปรอินสแตนซ์ของคลาสเดียวกัน .... คุณจะไม่มีพื้นที่ฮีปเมื่อคุณสร้างอ็อบเจกต์ซ้ำ ๆ
Aniket Thakur

1

ที่น่าสนใจคือความแตกต่างของประสิทธิภาพที่กล่าวถึงในตัวอย่างข้างต้นดูเหมือนจะเกี่ยวข้องกับเหตุผลอื่น ๆ การใช้คลาสที่แตกต่างกัน 3 คลาสโดยเฉลี่ยแล้วประสิทธิภาพจะใกล้เคียงกัน:

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");
} }

ผลลัพธ์จะเป็นดังนี้:

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

และการสลับลำดับการโทรก็จะทำให้getClass()เร็วขึ้นด้วย

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");
}}

เอาท์พุต:

time (.class):33108 ns
time (getClass()) :6622 ns

"ใช้ 3 คลาสที่แตกต่างกัน". แต่ในส่วน getClass () คุณไม่ได้ใช้ 3 คลาสที่แตกต่างกัน สิ่งเหล่านี้คือ String ทั้งหมดดังนั้น getClass จะส่งคืน java.lang.String สำหรับอินสแตนซ์ทั้งหมด
Kilian

1

p.getClass()โดยที่pเป็นอินสแตนซ์ของอ็อบเจ็กต์ส่งกลับคลาสรันไทม์ของอ็อบเจ็กต์pนี้ pไม่สามารถเป็นประเภทที่จะทำให้เกิดข้อผิดพลาดเวลาคอมไพล์ควรเป็นอินสแตนซ์ของวัตถุ

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

p.classคือการแสดงออก .classเรียกว่าไวยากรณ์ชั้นเรียน pเป็นประเภท อาจเป็นชื่อของคลาสอินเทอร์เฟซหรืออาร์เรย์และแม้แต่ประเภทดั้งเดิม a.getClass() == B.class.

หากมีประเภทและมีอินสแตนซ์คุณสามารถใช้getClassวิธีการเพื่อรับชื่อประเภทได้ มิฉะนั้นให้ใช้.classไวยากรณ์

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