Runtime Type Identification(RTTI)은 프로그램 실행 중에 객체의 실제 타입(runtime type)을 확인할 수 있는 메커니즘. 이는 일반적으로 다형성(polymorphism)을 사용하는 객체 지향 프로그래밍 언어에서 중요하며, 컴파일 타임이 아닌 런타임에 타입 정보를 확인하거나 동작을 수행할 때 사용.
instanceof 키워드와 클래스의 getClass() 메서드를 통해 RTTI를 수행
class Base {}
class Derived extends Base {}
public class Main {
public static void main(String[] args) {
Base base = new Derived();
if (base instanceof Derived) {
System.out.println("base는 Derived 타입입니다.");
}
}
}
객체의 실제 타입에 따라 동적으로 동작을 결정할 수 있어 유연성을 제공. 또한 잘못된 타입으로의 캐스팅을 방지 가능.
대신, 실행 중에 타입 정보를 확인하기 때문에 약간의 성능 오버헤드 발생. RTTI를 지나치게 사용하면 객체 지향 설꼐를 잘못 사용하는 결과를 초래 -> 다형성을 활용해 대체할 수 있는 경우에는 RTTI 사용을 피하는것이 좋음.
다형성과 템플릿(Generics)를 사용해 RTTI 사용을 줄일 수 있음.
-> 템플릿의 경우에는 컴파일 타임에 타입을 확정함으로써 RTTI를 사용할 필요 줄임.
RTTI는 다형성에서 자주 사용하는 기능이므로, 다형성을 활용해 객체의 실제 타입에 따라 다른 동작을 수행하는 연습을 해보세요.
실습: instanceof와 다형성 비교
abstract class Animal {
abstract void makeSound();
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Woof");
}
void fetch() {
System.out.println("Fetching the ball!");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Meow");
}
void scratch() {
System.out.println("Scratching the furniture!");
}
}
public class Main {
public static void main(String[] args) {
Animal[] animals = {new Dog(), new Cat()};
for (Animal animal : animals) {
// RTTI를 사용한 타입 확인
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.makeSound();
dog.fetch();
} else if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.makeSound();
cat.scratch();
}
}
}
}
목표:
makeSound() 메서드를 호출하는 것과 instanceof를 사용한 캐스팅의 차이를 이해합니다.instanceof 없이 다형성으로 처리할 수 있는지 고민해 봅니다.Spring에서는 ApplicationContext를 통해 Bean의 타입을 확인하고 특정 Bean을 가져올 수 있습니다. 이를 활용하면 RTTI와 비슷한 동작을 실습할 수 있습니다.
실습: Spring Bean 타입 확인
1. Bean 정의
@Component
public class MyService {}
@Component
public class YourService {}
@SpringBootApplication
public class RttiApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(RttiApplication.class, args);
// 특정 Bean의 실제 타입 확인
Object myService = context.getBean("myService");
System.out.println("Bean 타입: " + myService.getClass().getName());
if (myService instanceof MyService) {
System.out.println("myService는 MyService의 인스턴스입니다.");
}
}
}
목표:
서비스 개발 중 특정 입력 데이터를 처리할 때, 객체의 타입에 따라 다른 비즈니스 로직을 적용해야 할 때가 있습니다. 이를 실습해 볼 수 있습니다.
실습: 입력 타입별로 로직 처리
interface PaymentMethod {}
class CreditCard implements PaymentMethod {
void processPayment() {
System.out.println("Processing credit card payment");
}
}
class PayPal implements PaymentMethod {
void processPayment() {
System.out.println("Processing PayPal payment");
}
}
public class PaymentProcessor {
public void process(PaymentMethod paymentMethod) {
if (paymentMethod instanceof CreditCard) {
((CreditCard) paymentMethod).processPayment();
} else if (paymentMethod instanceof PayPal) {
((PayPal) paymentMethod).processPayment();
} else {
throw new IllegalArgumentException("Unsupported payment method");
}
}
public static void main(String[] args) {
PaymentProcessor processor = new PaymentProcessor();
processor.process(new CreditCard());
processor.process(new PayPal());
}
}
목표:
Java의 Reflection API는 RTTI를 기반으로 동작합니다. 이를 활용해 런타임에 클래스 정보를 확인하거나 메서드를 호출하는 실습을 진행할 수 있습니다.
실습: Reflection으로 런타임 메서드 호출
import java.lang.reflect.Method;
public class ReflectionExample {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java.util.ArrayList");
Object instance = clazz.getDeclaredConstructor().newInstance();
Method addMethod = clazz.getMethod("add", Object.class);
addMethod.invoke(instance, "Hello Reflection");
Method sizeMethod = clazz.getMethod("size");
System.out.println("ArrayList size: " + sizeMethod.invoke(instance));
}
}
목표:
다형성과 인터페이스를 활용하여 RTTI를 줄이고 설계를 개선하는 연습도 중요합니다.
실습: 인터페이스 활용
위의 PaymentMethod 예제를 개선하여 instanceof 없이 다형성으로 문제를 해결해 보세요.
interface PaymentMethod {
void processPayment();
}
class CreditCard implements PaymentMethod {
@Override
public void processPayment() {
System.out.println("Processing credit card payment");
}
}
class PayPal implements PaymentMethod {
@Override
public void processPayment() {
System.out.println("Processing PayPal payment");
}
}
public class PaymentProcessor {
public void process(PaymentMethod paymentMethod) {
paymentMethod.processPayment();
}
public static void main(String[] args) {
PaymentProcessor processor = new PaymentProcessor();
processor.process(new CreditCard());
processor.process(new PayPal());
}
}
이 실습은 단순히 RTTI를 사용하는 것뿐 아니라 객체 지향 설계를 강화하는 데도 도움이 될 것입니다.