게으른 개발자의 끄적거림

Java instanceof란?

끄적잉 2024. 5. 30. 23:00
반응형

## Java `instanceof` 연산자

`instanceof` 연산자는 Java에서 객체가 특정 클래스의 인스턴스인지, 또는 특정 클래스나 인터페이스를 구현했는지를 확인하는 데 사용됩니다. 이 연산자는 런타임 시에 객체의 실제 타입을 체크하며, 조건식의 결과는 `boolean` 타입으로 반환됩니다. 즉, 해당 객체가 특정 클래스의 인스턴스이면 `true`, 그렇지 않으면 `false`를 반환합니다.

 


### 기본 문법

`instanceof` 연산자의 기본적인 사용법은 다음과 같습니다:

```java
if (object instanceof ClassName) {
    // object가 ClassName 타입의 인스턴스일 때 실행될 코드
}
```

여기서 `object`는 검사할 객체이고, `ClassName`은 검사 대상 클래스 또는 인터페이스입니다.

 


### 예제 코드

```java
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

public class InstanceofExample {
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal cat = new Cat();

        System.out.println("dog instanceof Animal: " + (dog instanceof Animal)); // true
        System.out.println("dog instanceof Dog: " + (dog instanceof Dog)); // true
        System.out.println("dog instanceof Cat: " + (dog instanceof Cat)); // false

        System.out.println("cat instanceof Animal: " + (cat instanceof Animal)); // true
        System.out.println("cat instanceof Dog: " + (cat instanceof Dog)); // false
        System.out.println("cat instanceof Cat: " + (cat instanceof Cat)); // true
    }
}
```

위 코드에서 `dog` 객체는 `Dog` 클래스의 인스턴스이고, `cat` 객체는 `Cat` 클래스의 인스턴스입니다. `instanceof` 연산자를 사용하여 객체가 특정 클래스나 그 상위 클래스의 인스턴스인지 확인할 수 있습니다.

 

반응형


### 상속 관계에서의 `instanceof`

`instanceof` 연산자는 상속 관계에서도 사용할 수 있습니다. 예를 들어, `Dog` 클래스가 `Animal` 클래스를 상속받고 있을 때, `Dog` 클래스의 인스턴스는 `Animal` 클래스의 인스턴스이기도 합니다.

```java
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

public class InstanceofExample {
    public static void main(String[] args) {
        Dog dog = new Dog();
        System.out.println("dog instanceof Animal: " + (dog instanceof Animal)); // true
    }
}
```

이 예제에서 `Dog` 클래스는 `Animal` 클래스를 상속받으므로, `dog` 객체는 `Animal` 클래스의 인스턴스입니다. 따라서 `dog instanceof Animal`은 `true`를 반환합니다.

 

 


### 인터페이스와의 관계

`instanceof` 연산자는 클래스뿐만 아니라 인터페이스에 대해서도 사용할 수 있습니다. 객체가 특정 인터페이스를 구현하는지 확인할 때 유용합니다.

```java
interface Pet {}
class Dog implements Pet {}
class Cat implements Pet {}

public class InstanceofExample {
    public static void main(String[] args) {
        Pet petDog = new Dog();
        Pet petCat = new Cat();

        System.out.println("petDog instanceof Pet: " + (petDog instanceof Pet)); // true
        System.out.println("petDog instanceof Dog: " + (petDog instanceof Dog)); // true
        System.out.println("petDog instanceof Cat: " + (petDog instanceof Cat)); // false

        System.out.println("petCat instanceof Pet: " + (petCat instanceof Pet)); // true
        System.out.println("petCat instanceof Dog: " + (petCat instanceof Dog)); // false
        System.out.println("petCat instanceof Cat: " + (petCat instanceof Cat)); // true
    }
}
```

위 코드에서 `Dog`와 `Cat` 클래스는 `Pet` 인터페이스를 구현합니다. 따라서 `petDog`와 `petCat` 객체는 모두 `Pet` 타입으로 간주될 수 있습니다.

 

 


### `null` 값과 `instanceof`

`instanceof` 연산자는 `null`에 대해 항상 `false`를 반환합니다. 이는 안전한 타입 체크를 가능하게 합니다.

```java
Dog dog = null;
System.out.println("dog instanceof Dog: " + (dog instanceof Dog)); // false
```

이 경우 `dog` 변수가 `null`이기 때문에 `dog instanceof Dog`는 `false`를 반환합니다.

### 제네릭 타입과 `instanceof`

제네릭 타입을 사용할 때 `instanceof` 연산자를 사용하는 것은 조금 더 복잡할 수 있습니다. 제네릭 타입은 컴파일 시에 타입이 지워지기 때문에, 런타임에는 구체적인 타입 정보를 확인할 수 없습니다. 따라서 제네릭 타입을 `instanceof` 연산자로 직접 검사할 수는 없지만, 와일드카드와 같은 방법을 사용하여 간접적으로 확인할 수 있습니다.

```java
import java.util.ArrayList;
import java.util.List;

public class InstanceofGenericExample {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        List<Integer> intList = new ArrayList<>();

        System.out.println("stringList instanceof List: " + (stringList instanceof List)); // true
        System.out.println("intList instanceof List: " + (intList instanceof List)); // true

        // 제네릭 타입을 직접 확인할 수는 없음
        // System.out.println("stringList instanceof List<String>: " + (stringList instanceof List<String>)); // 컴파일 오류
    }
}
```

위 예제에서 `stringList`와 `intList`는 모두 `List` 타입의 인스턴스이지만, 제네릭 타입 매개변수는 런타임에 존재하지 않기 때문에 `List<String>`이나 `List<Integer>`와 같은 구체적인 타입으로는 확인할 수 없습니다.

 

 


### 고급 사용 예제: 다형성과 캐스팅

`instanceof`는 다형성을 사용할 때 유용합니다. 다형성은 객체 지향 프로그래밍의 중요한 개념으로, 상위 클래스 타입의 참조 변수가 하위 클래스 타입의 객체를 참조할 수 있게 합니다. 이를 통해 보다 유연하고 확장 가능한 코드를 작성할 수 있습니다.

```java
class Animal {
    public void makeSound() {
        System.out.println("Animal sound");
    }
}

class Dog extends Animal {
    public void makeSound() {
        System.out.println("Woof");
    }
    public void fetch() {
        System.out.println("Dog is fetching");
    }
}

class Cat extends Animal {
    public void makeSound() {
        System.out.println("Meow");
    }
}

public class InstanceofPolymorphismExample {
    public static void main(String[] args) {
        Animal animal = new Dog();

        animal.makeSound(); // "Woof"

        if (animal instanceof Dog) {
            Dog dog = (Dog) animal;
            dog.fetch(); // "Dog is fetching"
        }

        if (animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.makeSound();
        } else {
            System.out.println("animal is not an instance of Cat");
        }
    }
}
```

 


위 예제에서 `animal` 변수는 `Animal` 타입이지만 실제로는 `Dog` 클래스의 인스턴스를 참조하고 있습니다. `instanceof`를 사용하여 `animal`이 `Dog` 클래스의 인스턴스인지 확인한 후, 안전하게 `Dog` 타입으로 캐스팅할 수 있습니다. 반면에 `animal`이 `Cat` 클래스의 인스턴스인지 확인할 때는 `false`가 반환되므로 `Cat` 타입으로 캐스팅되지 않습니다.

 

 


### 결론

Java의 `instanceof` 연산자는 객체가 특정 클래스나 인터페이스의 인스턴스인지 확인하는 데 매우 유용한 도구입니다. 이를 통해 런타임 시에 객체의 타입을 안전하게 검사하고 적절한 처리를 할 수 있습니다. 다형성과 캐스팅, 그리고 상속 구조에서의 활용 등 다양한 상황에서 `instanceof` 연산자를 적절히 사용하면 보다 견고하고 유연한 코드를 작성할 수 있습니다.

반응형