Làm thế nào để xác định lớp của một đối tượng?


510

Nếu lớp Bvà lớp Cmở rộng lớp Avà tôi có một đối tượng kiểu Bhoặc C, làm thế nào tôi có thể xác định loại đó là một thể hiện?


14
@starblue Casting sẽ là điều đầu tiên bạn nghĩ đến. Tôi nghi ngờ toán tử instanceof sẽ tồn tại nếu không có nhu cầu về nó.
b1nary.atr0phy

@ b1nary.atr0phy sẽ không tốt khi sử dụng toán tử isntanceof trước. Nếu có một dàn diễn viên với một loại không tương thích, tôi tin rằng sẽ dẫn đến một ClassCastException
committedandroider

Câu trả lời:


801
if (obj instanceof C) {
//your code
}

31
Sẽ rất hữu ích khi lưu ý kiểm tra ngược hoặc cách kiểm tra xem Đối tượng KHÔNG phải là phiên bản của một lớp hay không:if(!(obj instanceof C))
Dzhuneyt

32
Tôi tin rằng phương thức getClass () là câu trả lời cho câu hỏi ban đầu. Trong trường hợp này (obj instanceof A) cũng sẽ cho đầu ra "true" nhưng mục đích là tìm lớp thời gian chạy của đối tượng trong ảnh. Nếu Parent1 được mở rộng bởi Child1 và Child2, hãy thử code Child1 child1 = new Child1 (); Parent1 ParentChild = new Child2 (); Child2 child2 = new Child2 (); (child1 dụof Parent1); (child1 dụof Child1); (ParentChild instanceof Child2); (ParentChild dụof Parent1); (ParentChild instanceof Child1); code , nó có thể xóa ý định của instanceof.
Bhavesh Agarwal

Chắc chắn là một sự thay thế để xây dựng một giao diện
JohnMerlino

3
Nếu tôi có hai lớp thực hiện giao diện đơn thì sao? Làm thế nào để tôi phân biệt chính xác lớp của đối tượng?
olyv

3
Một điều mặc dù, nó không hoạt động nếu obj là null. Giải pháp sau đó sẽ là ParentInterface. Class.isAssignableFrom (Child. Class)
alexbt

351

Sử dụng Object.getClass () . Nó trả về kiểu thời gian chạy của đối tượng.


12
Đây thực sự là cách bạn xác định lớp của một đối tượng
AA_PV

câu trả lời hoàn hảo @Bill
gaurav

1
Không chắc chắn tại sao đây không phải là câu trả lời phổ biến nhất
eicksl

178

Nhiều câu trả lời đúng đã được trình bày, nhưng vẫn còn nhiều phương pháp khác: Class.isAssignableFrom()và chỉ đơn giản là cố gắng truyền đối tượng (có thể ném a ClassCastException).

Những cách có thể tóm tắt

Chúng ta hãy tóm tắt các cách có thể để kiểm tra nếu một đối tượng objlà một thể hiện của loại 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) {
}

Sự khác biệt trong nullxử lý

Có một sự khác biệt trong nullxử lý mặc dù:

  • Trong 2 phương thức đầu tiên, biểu thức ước tính là falseif ( không phải là ví dụ của bất kỳ thứ gì).objnullnull
  • Phương pháp thứ 3 sẽ ném một cách NullPointerExceptionrõ ràng.
  • Phương pháp thứ 4 và thứ 5 trái ngược chấp nhận nullnullcó thể được truyền sang bất kỳ loại nào!

Để nhớ: null không phải là một thể hiện của bất kỳ loại nào nhưng nó có thể được chuyển thành bất kỳ loại nào.

Ghi chú

  • Class.getName()không nên được sử dụng để thực hiện một becase thử nghiệm "is-instance-of" nếu đối tượng không phải là loại Cmà là một lớp con của nó, nó có thể có một tên và gói hoàn toàn khác (do đó tên lớp rõ ràng sẽ không khớp) nhưng nó là vẫn thuộc loại C.
  • Đối với cùng một lý do thừa kế Class.isAssignableFrom()không đối xứng :
    obj.getClass().isAssignableFrom(C.class)sẽ trả về falsenếu loại objlà một lớp con của C.

6
Đây là một bản tóm tắt thực sự tuyệt vời của nhiều cạm bẫy trong các phương pháp khác nhau. Cảm ơn cho một viết hoàn chỉnh lên!
Kelsin

32

Bạn có thể dùng:

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

HTH. Nhưng tôi nghĩ rằng hầu hết thời gian không nên sử dụng điều đó cho dòng điều khiển hoặc thứ gì đó tương tự ...


Tôi đã sử dụng nó để tạo logger chung, vì vậy tôi đã gửi đối tượng đến logger và nó ghi nhật ký tùy thuộc vào tên lớp của đối tượng, thay vì đưa ra thẻ log hoặc chuỗi log mỗi lần. cảm ơn bạn
MBH

24

Bất kỳ việc sử dụng bất kỳ phương pháp nào được đề xuất đều được coi là mùi mã dựa trên thiết kế OO xấu.

Nếu thiết kế của bạn tốt, bạn không nên thấy mình cần sử dụng getClass()hay instanceof.

Bất kỳ phương pháp được đề xuất nào cũng sẽ làm, nhưng chỉ cần một cái gì đó để ghi nhớ, thiết kế khôn ngoan.


3
Vâng, có thể tránh được 99% việc sử dụng getClass và instanceof với các lệnh gọi phương thức đa hình.
Bill the Lizard

3
Tôi đồng ý. trong trường hợp này tôi đang làm việc với các đối tượng được tạo từ xml theo lược đồ được thiết kế kém mà tôi không có quyền sở hữu.
hãng

28
Không cần thiết. Đôi khi tách giao diện là tốt. Đôi khi bạn muốn biết A có phải là B không, nhưng bạn không muốn bắt buộc A phải là B, vì chỉ A là bắt buộc đối với hầu hết các chức năng - B có chức năng tùy chọn.
MetroidFan2002

8
Ngoài ra, có những lúc bạn cần đảm bảo rằng đối tượng đó cùng loại mà bạn đang so sánh; chẳng hạn, tôi muốn ghi đè phương thức bằng của Object khi tôi tạo lớp của riêng mình. Tôi luôn xác minh đối tượng đi vào là cùng một lớp.
StackOverflow

58
Ngoài ra, tôi sẽ nói rằng nói với mọi người điều gì đó là xấu mà không giải thích chính xác lý do tại sao hoặc đưa ra một tài liệu tham khảo cho một bài báo, cuốn sách hoặc bất kỳ tài nguyên nào khác mà vấn đề được giải thích được coi là không mang tính xây dựng. Do đó và biết rằng tôi đang ở trong StackOverflow, tôi không biết tại sao mọi người lại nâng cao câu trả lời này đến vậy. Một cái gì đó đang thay đổi ở đây ...
Adrián Pérez

15

Chúng ta có thể sử dụng sự phản chiếu trong trường hợp này

objectName.getClass().getName();

Thí dụ:-

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

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

Trong trường hợp này, bạn sẽ nhận được tên của lớp mà đối tượng chuyển qua HttpServletRequestbiến giới thiệu giao diện.


chính xác. chỉ sử dụng obj.getClass()sẽ trả về className, prefixex bằng từclass
x6iae

request.getClass().getName();in tất cả các gói! cùng với tên lớp
shareef

13

Ngoài ra còn có một .isInstancephương thức trên Classlớp "". nếu bạn nhận được một lớp của đối tượng thông qua myBanana.getClass()bạn có thể xem liệu đối tượng của bạn myApplecó phải là một thể hiện của cùng một lớp như myBananathông qua không

myBanana.getClass().isInstance(myApple)

1

kiểm tra với isinstance()sẽ không đủ nếu bạn muốn biết trong thời gian chạy. sử dụng:

if(someObject.getClass().equals(C.class){
    // do something
}

0

Tôi sử dụng chức năng thổi trong lớp GeneralUtils của mình, kiểm tra xem nó có hữu ích không

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

0

Tôi đã sử dụng các tổng quát Java 8 để lấy cá thể đối tượng trong thời gian chạy thay vì phải sử dụng trường hợp chuyển đổi

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

vượt qua bất kỳ loại dữ liệu nào và phương thức sẽ in loại dữ liệu bạn đã truyền trong khi gọi nó. ví dụ

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

Sau đây là đầu ra

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 []
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.