Toán tử 'instanceof' được sử dụng trong Java là gì?


163

Những gì được các instanceofnhà khai thác sử dụng cho? Tôi đã thấy những thứ như

if (source instanceof Button) {
    //...
} else {
    //...
}

Nhưng không ai trong số đó có ý nghĩa với tôi. Tôi đã thực hiện nghiên cứu của mình, nhưng chỉ đưa ra các ví dụ mà không có bất kỳ lời giải thích nào.


38
Không có gì sai khi đặt câu hỏi ở đây, nhưng nếu bạn đang học Java, bạn có thể muốn lấy một cuốn sách. Bất kỳ cuốn sách Java tử tế nào cũng sẽ có câu trả lời cho câu hỏi này và 1000 cuốn tiếp theo bạn sẽ có.
Tổng thống James K. Polk

Một toán tử như vậy có nhiều cách sử dụng cụ thể. Đây sẽ là một câu hỏi cụ thể nếu nó yêu cầu giải thích về một trong những ví dụ không có ý nghĩa với bạn.
Raedwald

2
Các câu trả lời dưới đây là chính xác, tuy nhiên lưu ý rằng instanceof là toán tử được sử dụng quá mức 9 lần trong số 10 câu có thể được thay thế bằng cách sử dụng đa hình đúng cách (không phải luôn luôn, nhưng thường xuyên)
Richard Tingle

Tôi sẽ đi xa hơn Richard: Tôi chưa bao giờ thấy việc sử dụng thể hiện hợp lệ. Nó chỉ hữu ích cho việc hack nhanh trên đầu mã được thiết kế kém. Nếu bạn không thích OOP, hãy viết bằng ngôn ngữ khác (có rất nhiều). Chỉ cần nói, "không" với ví dụ!
Scott Biggie

5
@ScottBiggs Có cách nào tốt hơn instanceofkhi ghi đè equalskhông?
Ben Aaronson

Câu trả lời:


228

instanceoftừ khóa là một toán tử nhị phân được sử dụng để kiểm tra nếu một đối tượng (thể hiện) là một kiểu con của Loại đã cho.

Hãy tưởng tượng:

interface Domestic {}
class Animal {}
class Dog extends Animal implements Domestic {}
class Cat extends Animal implements Domestic {}

Hãy tưởng tượng một dog đối tượng , được tạo bằng Object dog = new Dog(), sau đó:

dog instanceof Domestic // true - Dog implements Domestic
dog instanceof Animal   // true - Dog extends Animal
dog instanceof Dog      // true - Dog is Dog
dog instanceof Object   // true - Object is the parent type of all objects

Tuy nhiên, với Object animal = new Animal();,

animal instanceof Dog // false

bởi vì Animallà một siêu kiểu Dogvà có thể ít "tinh chế" hơn.

Và,

dog instanceof Cat // does not even compile!

Đây là vì Dog không phải là một kiểu con cũng không phải là siêu kiểu Cat, và nó cũng không thực hiện nó.

Lưu ý rằng biến được sử dụng dogở trên là loại Object. Điều này là để hiển thị instanceoflà một hoạt động thời gian chạy và đưa chúng ta đến một / trường hợp sử dụng: để phản ứng khác nhau dựa trên một loại đối tượng trong thời gian chạy .

Điều cần lưu ý: expressionThatIsNull instanceof Tlà sai cho tất cả các loại T.

Chúc mừng mã hóa.


14
Tôi vừa thử - Object dog = new Dog(); System.out.println(dog instanceof Cat);. Điều này biên dịch tốt và in false. Trình biên dịch không được phép xác định tại thời điểm biên dịch dogkhông thể là Cat (theo các quy tắc trong JLS)
Erwin Bolwidt

@ErwinBolwidt Bạn đã mắc lỗi khi thử nó. Đối với bất cứ ai tự hỏi: JLS Mục 15.20.2 là một trong những bạn đang tìm kiếm. Đối với một ví dụ không hoạt động tối thiểu:boolean b = "foo" instanceof Integer;
Felix S

3
@FelixS Bạn cần đọc lại câu trả lời. Câu trả lời là về Object indirect = ...; if (indirect instanceof Something). Nó không if (literal instanceof Something)giống như bạn đang giả định.
Erwin Bolwidt

1
@ErwinBolwidt Ồ, phải, tôi đã bỏ qua Object dogphần này. Lỗi của tôi!
Felix S

dog instanceof Cat // does not even compile!(vì nó là một lớp học). Nếu Catlà một giao diện thì nó sẽ biên dịch.
Hamza Belmellouki

44

Đó là một toán tử trả về true nếu phía bên trái của biểu thức là một thể hiện của tên lớp ở phía bên phải.

Hãy suy nghĩ về nó theo cách này. Nói rằng tất cả các ngôi nhà trên khối của bạn được xây dựng từ cùng một bản thiết kế. Mười ngôi nhà (đối tượng), một bộ đồ án (định nghĩa lớp).

instanceoflà một công cụ hữu ích khi bạn có một bộ sưu tập các đối tượng và bạn không chắc chúng là gì. Giả sử bạn đã có một bộ sưu tập các điều khiển trên một biểu mẫu. Bạn muốn đọc trạng thái đã kiểm tra của bất kỳ hộp kiểm nào ở đó, nhưng bạn không thể yêu cầu một đối tượng cũ đơn giản cho trạng thái được kiểm tra. Thay vào đó, bạn sẽ thấy nếu mỗi đối tượng là một hộp kiểm và nếu có, hãy đặt nó vào một hộp kiểm tra và kiểm tra các thuộc tính của nó.

if (obj instanceof Checkbox)
{
    Checkbox cb = (Checkbox)obj;
    boolean state = cb.getState();
}

15
Đó là để nói, sử dụng instanceofcó thể làm cho nó an toàn để downcast.
Raedwald

29

Theo mô tả trên trang web này :

Các instanceofnhà điều hành có thể được sử dụng để kiểm tra nếu một đối tượng là một loại hình cụ thể ...

if (objectReference instanceof type)

Một ví dụ nhanh:

String s = "Hello World!"
return s instanceof String;
//result --> true

Tuy nhiên, áp dụng instanceoftrên một biến / biểu thức tham chiếu null trả về false.

String s = null;
return s instanceof String;
//result --> false

Vì một lớp con là một 'loại' của siêu lớp của nó, bạn có thể sử dụng instanceofđể xác minh điều này ...

class Parent {
    public Parent() {}
}

class Child extends Parent {
    public Child() {
        super();
    }
}

public class Main {
    public static void main(String[] args) {
        Child child = new Child();
        System.out.println( child instanceof Parent );
    }
}
//result --> true

Tôi hi vọng cái này giúp được!


15

Toán tử này cho phép bạn xác định loại đối tượng. Nó trả về mộtboolean giá trị.

Ví dụ

package test;

import java.util.Date;
import java.util.Map;
import java.util.HashMap;

public class instanceoftest
{
    public static void main(String args[])
    {
        Map m=new HashMap();
        System.out.println("Returns a boolean value "+(m instanceof Map));
        System.out.println("Returns a boolean value "+(m instanceof HashMap));
        System.out.println("Returns a boolean value "+(m instanceof Object));
        System.out.println("Returns a boolean value "+(m instanceof Date));
    }
} 

đầu ra là:

Returns a boolean value true
Returns a boolean value true
Returns a boolean value true
Returns a boolean value false

14

Nếu sourcelà một objectbiến, instanceoflà một cách kiểm tra xem nó có phải là một Buttonhay không.


4

Như đã đề cập trong các câu trả lời khác, cách sử dụng điển hình chính instanceoflà để kiểm tra xem một định danh có liên quan đến một loại cụ thể hơn không. Thí dụ:

Object someobject = ... some code which gets something that might be a button ...
if (someobject instanceof Button) {
    // then if someobject is in fact a button this block gets executed
} else {
    // otherwise execute this block
}

Tuy nhiên, lưu ý rằng loại biểu thức bên trái phải là loại cha của biểu thức bên tay phải (xem JLS 15.20.2Java Puzzlers, # 50, tr114 ). Ví dụ, sau đây sẽ không biên dịch:

public class Test {
    public static void main(String [] args) {
        System.out.println(new Test() instanceof String); // will fail to compile
    }
}

Điều này không thể biên dịch với thông báo:

Test.java:6: error: inconvertible types
        System.out.println(t instanceof String);
                       ^
  required: String
  found:    Test
1 error

Như Testkhông phải là một lớp cha mẹ của String. OTOH, điều này biên dịch hoàn hảo và in falsenhư mong đợi:

public class Test {
    public static void main(String [] args) {
        Object t = new Test();
        // compiles fine since Object is a parent class to String
        System.out.println(t instanceof String); 
    }
}

Cảm ơn đã liên kết đến thông số kỹ thuật!
jpaugh

1
public class Animal{ float age; }

public class Lion extends Animal { int claws;}

public class Jungle {
    public static void main(String args[]) {

        Animal animal = new Animal(); 
        Animal animal2 = new Lion(); 
        Lion lion = new Lion(); 
        Animal animal3 = new Animal(); 
        Lion lion2 = new Animal();   //won't compile (can't reference super class object with sub class reference variable) 

        if(animal instanceof Lion)  //false

        if(animal2 instanceof Lion)  //true

        if(lion insanceof Lion) //true

        if(animal3 instanceof Animal) //true 

    }
}

1

Có thể được sử dụng như một tốc ký trong kiểm tra bình đẳng.

Mã này

if(ob != null && this.getClass() == ob.getClass) {
}

Có thể được viết như

if(ob instanceOf ClassA) {
}

1

Hầu hết mọi người đã giải thích chính xác "Cái gì" của câu hỏi này nhưng không ai giải thích chính xác "Làm thế nào".

Vì vậy, đây là một minh họa đơn giản:

String s = new String("Hello");
if (s instanceof String) System.out.println("s is instance of String"); // True
if (s instanceof Object) System.out.println("s is instance of Object"); // True
//if (s instanceof StringBuffer) System.out.println("s is instance of StringBuffer"); // Compile error
Object o = (Object)s;
if (o instanceof StringBuffer) System.out.println("o is instance of StringBuffer"); //No error, returns False
else System.out.println("Not an instance of StringBuffer"); // 
if (o instanceof String) System.out.println("o is instance of String"); //True

Đầu ra:

s is instance of String
s is instance of Object
Not an instance of StringBuffer
o is instance of String

Lý do lỗi trình biên dịch khi so sánh svới StringBuffer được giải thích rõ trong các tài liệu :

Bạn có thể sử dụng nó để kiểm tra xem một đối tượng là một thể hiện của một lớp, một thể hiện của một lớp con hay một thể hiện của một lớp thực hiện một giao diện cụ thể.

trong đó ngụ ý LHS phải là một thể hiện của RHS hoặc của một Lớp thực hiện RHS hoặc mở rộng RHS.

Làm thế nào để sử dụng sử dụng instanceof sau đó?
Vì mỗi Lớp mở rộng Đối tượng, nên LHS truyền kiểu cho đối tượng sẽ luôn hoạt động theo ý bạn:

String s = new String("Hello");
if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //No compiler error now :)
else System.out.println("Not an instance of StringBuffer");

Đầu ra:

Not an instance of StringBuffer

Trong ví dụ cuối cùng, tại sao nó lại trả về "Không phải là phiên bản của StringBuffer"? Vì bạn đã đánh máy s thành Object trên LHS và kiểm tra xem đó có phải là một RHS không if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //shouldn't this be true, vì chúng ta đang đánh máy s cho Object?
sofs1

Vì s là tham chiếu đến đối tượng String (Java sử dụng đa hình động không giống như C ++) và String không phải là lớp con của StringBuffer.
sziraqui


0

Sơ thẩm của từ khóa là hữu ích khi bạn muốn biết thể hiện của đối tượng cụ thể.

Giả sử bạn ném ngoại lệ và khi bạn bắt được thì thực hiện thao tác tùy chỉnh tổng và sau đó tiếp tục theo logic của bạn (ném hoặc ghi nhật ký, v.v.)

Ví dụ: 1) Người dùng tạo ngoại lệ tùy chỉnh "UnlimitedExtensionsException" và ném nó theo logic

2) Bây giờ trong phần bắt khối (Exception e) {thực hiện logic tổng nếu loại ngoại lệ là "UnlimitedExtensionsException"

InvalidExtensionsException InvalidException =(InvalidExtensionsException)e;

3) Nếu bạn không kiểm tra thể hiện và loại ngoại lệ là ngoại lệ con trỏ Null, mã của bạn sẽ bị hỏng.

Vì vậy, logic của bạn phải nằm trong thể hiện của if (e instanceof UnlimitedExtensionsException) {UnlimitedExtensionsException UnlimitedException = (UnlimitedExtensionsException) e; }

Ví dụ trên là thực hành mã hóa sai Tuy nhiên ví dụ này giúp bạn hiểu cách sử dụng thể hiện của nó.


0

Giải thích tốt nhất là jls . Luôn luôn cố gắng kiểm tra những gì nguồn nói. Ở đó bạn sẽ nhận được câu trả lời tốt nhất cộng với nhiều hơn nữa. Tái sản xuất một số phần ở đây:

Loại toán hạng RelationalExpression của toán tử instanceof phải là loại tham chiếu hoặc loại null; mặt khác, một lỗi thời gian biên dịch xảy ra.

Đó là lỗi thời gian biên dịch nếu ReferenceType được đề cập sau toán tử instanceof không biểu thị loại tham chiếu có thể xác định lại (§4.7).

Nếu việc truyền (§15.16) của RelationalExpression sang ReferenceType sẽ bị từ chối là lỗi thời gian biên dịch, thì biểu thức quan hệ của thể hiện tương tự cũng tạo ra lỗi thời gian biên dịch. Trong tình huống như vậy, kết quả của biểu thức instanceof không bao giờ có thể đúng.


0

Java instanceofToán tử được sử dụng để kiểm tra xem đối tượng có phải là một thể hiện của loại được chỉ định (lớp hoặc lớp con hoặc giao diện) hay không.

Ví dụ trong java còn được gọi là kiểu comparison operatorvì nó so sánh thể hiện với kiểu. Nó trả về truehoặc false. Nếu chúng ta áp dụng instanceoftoán tử với bất kỳ biến nào có nullgiá trị, nó sẽ trả vềfalse .

Từ JDK 14+, bao gồm JEP 305 chúng tôi cũng có thể thực hiện "Kết hợp mẫu" choinstanceof

Các mẫu về cơ bản kiểm tra rằng một giá trị có một loại nhất định và có thể trích xuất thông tin từ giá trị khi nó có loại phù hợp. Kết hợp mẫu cho phép biểu hiện logic rõ ràng và hiệu quả hơn trong một hệ thống, cụ thể là loại bỏ các thành phần có điều kiện khỏi các đối tượng.

Trước Java 14

if (obj instanceof String) {
    String str = (String) obj; // need to declare and cast again the object
    .. str.contains(..) ..
}else{
     str = ....
}

Cải tiến Java 14

if (!(obj instanceof String str)) {
    .. str.contains(..) .. // no need to declare str object again with casting
} else {
    .. str....
}

Chúng tôi cũng có thể kết hợp kiểm tra loại và các điều kiện khác với nhau

if (obj instanceof String str && str.length() > 4) {.. str.contains(..) ..}

Việc sử dụng khớp mẫu trong instanceofsẽ làm giảm tổng số phôi rõ ràng trong các chương trình Java.

PS : instanceOfsẽ chỉ khớp khi đối tượng không null, sau đó chỉ có thể gán nó str.


-1
class Test48{
public static void main (String args[]){
Object Obj=new Hello();
//Hello obj=new Hello;
System.out.println(Obj instanceof String);
System.out.println(Obj instanceof Hello);
System.out.println(Obj instanceof Object);
Hello h=null;
System.out.println(h instanceof Hello);
System.out.println(h instanceof Object);
}
}  

1
Không đăng mã chỉ trả lời trên StackOverflow. Hãy đi trước và thêm một lời giải thích.
L. Guthardt

-2

Ví dụ mã rất đơn giản:

If (object1 instanceof Class1) {
   // do something
} else if (object1 instanceof Class2) {
   // do something different
}

Hãy cẩn thận ở đây. Trong ví dụ trên, nếu Class1 là Object, so sánh đầu tiên sẽ luôn đúng. Vì vậy, giống như với các ngoại lệ, vấn đề thứ tự phân cấp!


-2

Bạn có thể sử dụng Bản đồ để thực hiện trừu tượng hóa cao hơn trong trường hợp

private final Map<Class, Consumer<String>> actions = new HashMap<>();

Sau đó, có bản đồ như vậy thêm một số hành động cho nó:

actions.put(String.class, new Consumer<String>() {
        @Override
        public void accept(String s) {
           System.out.println("action for String");       
        }
    };

Sau đó, có một Đối tượng không biết loại, bạn có thể nhận được hành động cụ thể từ bản đồ đó:

actions.get(someObject).accept(someObject)

-2

Toán tử instanceof được sử dụng để kiểm tra xem đối tượng có phải là một thể hiện của kiểu đã chỉ định hay không. (lớp hoặc lớp con hoặc giao diện).

Ví dụ này còn được gọi là toán tử so sánh kiểu vì nó so sánh thể hiện với kiểu. Nó trả về đúng hoặc sai.

class Simple1 {  
public static void main(String args[]) {  
Simple1 s=new Simple1();  
System.out.println(s instanceof Simple1); //true  
}  
}  

Nếu chúng ta áp dụng toán tử instanceof với bất kỳ biến nào có giá trị null, nó sẽ trả về false.

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.