instanceof Vs getClass ()


114

Tôi thấy hiệu suất đạt được khi sử dụng getClass()==toán tử hơn instanceOftoán tử.

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

Có bất kỳ hướng dẫn, cái nào để sử dụng getClass()hoặc instanceOf?

Đưa ra một tình huống: Tôi biết chính xác các lớp sẽ được so khớp, nghĩa là String, Integer(đây là các lớp cuối cùng), v.v.

Sử dụng instanceOftoán tử có thực hành xấu không?


3
Điều này được giải thích trong: stackoverflow.com/questions/596462/… .
Clement P

2
Phương pháp tính thời gian của bạn đang gây ra sự chậm trễ giả tạo và tạo ra kết quả tính thời gian không chính xác. Hoán đổi thứ tự bạn thực hiện séc và bạn sẽ thấy séc đầu tiên bạn thực hiện (== hoặc instanceof) sẽ luôn dài hơn. Tôi đoán đó là println () s. Bạn không bao giờ nên đưa những thứ đó vào khối thời gian của mình.
kurtzmarc

Chỉ khác một nhận xét, để so sánh hiệu suất, hãy sử dụng nhiều lần lặp lại chu kỳ (ví dụ: 10000) để cải thiện độ chính xác. Một lời kêu gọi không phải là một biện pháp tốt.
martins.tuga

Câu trả lời:


140

Lý do mà hiệu suất của instanceofgetClass() == ...khác nhau là họ đang làm những điều khác nhau.

  • instanceofkiểm tra xem tham chiếu đối tượng ở phía bên trái (LHS) là một phiên bản của loại ở phía bên phải (RHS) hay một số loại phụ .

  • getClass() == ... kiểm tra xem các loại có giống nhau không.

Vì vậy, khuyến nghị là bỏ qua vấn đề hiệu suất và sử dụng giải pháp thay thế cung cấp cho bạn câu trả lời mà bạn cần.

Đang sử dụng instanceOf toán tử có thực hành không tốt không?

Không cần thiết. Lạm dụng một trong hai instanceOfhoặcgetClass() có thể là "mùi thiết kế". Nếu bạn không cẩn thận, bạn sẽ kết thúc với một thiết kế mà việc bổ sung các lớp con mới dẫn đến một lượng lớn mã phải làm lại. Trong hầu hết các tình huống, cách tiếp cận ưu tiên là sử dụng tính đa hình.

Tuy nhiên, có những trường hợp KHÔNG phải là "mùi thiết kế". Ví dụ, equals(Object)bạn cần kiểm tra loại thực tế của đối số và trả về falsenếu nó không khớp. Điều này được thực hiện tốt nhất bằng cách sử dụng getClass().


Các thuật ngữ như "phương pháp hay nhất", "phương pháp xấu", "mùi thiết kế", "phản vật chất", v.v. nên được sử dụng một cách tiết kiệm và được xử lý một cách nghi ngờ. Họ khuyến khích suy nghĩ đen hoặc trắng. Tốt hơn là bạn nên đưa ra những đánh giá của mình trong ngữ cảnh, thay vì chỉ dựa hoàn toàn vào giáo điều; ví dụ như điều gì đó mà ai đó đã nói là "phương pháp hay nhất".


@StephenC Như bạn đã nói, đó là code smellsử dụng cả hai. Điều đó có nghĩa là, đó là hệ quả của mã thiết kế xấu (không đa hình) khiến bạn phải sử dụng. tôi có thể suy ra cách sử dụng của một trong hai cách này không?
trao đổi quá

@overexchange - 1) Tôi đã nói "sử dụng quá mức" chứ không phải "sử dụng". 2) Ngoài điều đó ra, tôi không hiểu bạn đang hỏi gì. Ý bạn là gì khi "suy ra cách sử dụng ..." ??? Mã hoặc sử dụng những thứ này, hoặc không.
Stephen C

Tôi suy luận rằng, việc sử dụng instanceof&getClass() đi vào hình ảnh do thiết kế xấu hiện có (không đa hình) của mã. tôi có đúng không
trao đổi quá

5
@overexchange - Bạn không thể suy luận hợp lệ rằng tất cả việc sử dụng instanceof(ví dụ) là thiết kế xấu. Có những tình huống mà nó có thể là giải pháp tốt nhất. Tương tự cho getClass(). Tôi sẽ lặp lại rằng tôi đã nói "sử dụng quá mức" chứ không phải "sử dụng" . Mọi trường hợp cần phải được xét xử dựa trên giá trị của nó ... chứ không phải bằng cách áp dụng một cách mù quáng một quy tắc giáo điều thiếu căn cứ nào.
Stephen C,

44

Bạn có muốn đối sánh chính xác một lớp , ví dụ: chỉ đối sánh FileInputStreamthay vì bất kỳ lớp con nào của FileInputStream? Nếu vậy, hãy sử dụng getClass()==. Tôi thường làm điều này trong một equals, để một phiên bản của X không được coi là bằng một phiên bản của một lớp con của X - nếu không, bạn có thể gặp phải các vấn đề phức tạp về đối xứng. Mặt khác, điều đó thường hữu ích hơn khi so sánh hai đối tượng giống nhau lớp hơn là của một lớp cụ thể.

Nếu không, hãy sử dụng instanceof. Lưu ý rằng với getClass()bạn sẽ cần phải đảm bảo rằng bạn có một tham chiếu không rỗng để bắt đầu, nếu không bạn sẽ nhận được NullPointerException, trong khi instanceofsẽ chỉ trả vềfalse nếu toán hạng đầu tiên là null.

Cá nhân tôi cho rằng instanceofnó mang tính thành ngữ hơn - nhưng việc sử dụng rộng rãi một trong hai chúng là một mùi thiết kế trong hầu hết các trường hợp.


18

Tôi biết nó đã được một thời gian kể từ khi điều này được hỏi, nhưng tôi đã biết một giải pháp thay thế vào ngày hôm qua

Chúng tôi đều biết bạn có thể làm:

if(o instanceof String) {   // etc

nhưng nếu bạn không biết chính xác loại lớp đó cần là gì? nói chung bạn không thể làm:

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

vì nó gây ra lỗi biên dịch.
Thay vào đó, đây là một giải pháp thay thế - isAssignableFrom ()

Ví dụ:

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

    return classTypeWeWant.isAssignableFrom(objectWeHave.getClass())
}

8
Không sử dụng isAssignableFrom. Cách chính xác để viết o instanceof Stringbằng cách sử dụng phản xạ là String.getClass().isInstance(o). Javadoc thậm chí còn nói như vậy: Phương thức này là tương đương động của instanceoftoán tử ngôn ngữ Java .
Andreas

3

getClass () có hạn chế là các đối tượng chỉ bằng với các đối tượng khác cùng lớp, cùng kiểu thời gian chạy, như được minh họa trong đầu ra của mã dưới đây:

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

Kết quả đầu ra:

SubClass mở rộng ParentClass. subClassInstance là instanceof ParentClass.

Các kết quả getClass () khác nhau trả về với subClassInstance và parentClassInstance.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.