프로그래밍 및 기타/Java, Spring Boot

[java] instanceof, 인터페이스, 구현 클래스

기록자_Recordian 2025. 4. 8. 11:56
728x90
반응형
이전 내용
 

[java] 추상 클래스, 추상 메소드

이전 내용 [java] 클래스의 타입 변환, 다형성이전 내용 [java] 접근 제한자, 클래스 상속이전 내용 [java] 정적 멤버와 Static, 싱글톤이전 내용 [java] java 예제 (메소드 오버로딩)이전 내용 [java] 메

puppy-foot-it.tistory.com


instanceof

 

instanceof: 자바에서 사용되는 연산자. 객체가 특정 클래스의 인스턴스인지 확인하는 데 사용되며, 이를 통해 안전하게 타입 캐스팅을 진행할 수 있도록 도와준다.

instanceof 연산자는 왼쪽에 있는 객체가 오른쪽에 있는 클래스의 인스턴스인지 확인한다.

boolean result = 좌항(객체) instanceof 우항(타입)

좌항의 객체가 우항의 인스턴스이면, (우항의 타입으로 객체가 생성되었다면) true, 그렇지 않으면 false 리턴

 

※ 타입 캐스팅: 프로그래밍에서 한 데이터 타입을 다른 데이터 타입으로 변환하는 과정.

1. 자동 캐스팅:  하위 타입(자식 클래스)의 객체를 상위 타입(부모 클래스)으로 변환하는 경우 ▶ 이 경우에는 손실없는 변환이 가능하므로 별도의 연산자를 사용하지 않아도 된다.

 

2. 수동 캐스팅: 상위 타입의 객체를 하위 타입으로 변환하는 과정 ▶ 이 경우에는 부모 클래스의 객체를 자식 클래스의 객체로 변환하기 때문에, instanceof를 사용하여 안전성을 확보한 후 캐스팅을 해야 오류를 방지할 수 있다.

만약 타입을 확인하지 않고 강제 타입 변환 시도 시에는 ClassCastException이 발생할 수 있다.


인터페이스
(feat. 구현 클래스)

 

인터페이스: 인터페이스는 객체의 사용 방법을 정의한 타입으로, 인터페이스를 통해 다양한 객체를 동일한 사용 방법으로 이용할 수 있다. 개발 코드가 인터페이스의 메소드를 호출하면 인터페이스는 객체의 메소드를 호출시킨다. 인터페이스는 하나의 객체가 아니라 여러 객체들과 사용 가능하므로 어떤 객체를 사용하느냐에 따라서 실행 내용과 리턴값이 다를 수 있다.

▶ 개발 코드 측면에서는 코드 변경 없이 실행 냉요과 리턴값을 다양화할 수 있다는 장점을 가지게 된다.

 

[인터페이스 특징]

  • 인터페이스는 실행 시 데이터를 저장할 수 있는 인스턴스 또는 정적 필드를 선언할 수 없다.
  • 상수 필드는 선언 가능하나, 인터페이스에 고정된 값으로 실행 시에 데이터를 바꿀 수 없다. (상수는 대문자로 작성하며, 단어 사이는 언더바로 연결)
  • 인터페이스를 통해 호출된 메소드는 최종적으로 객체에서 실행되므로, 인터페이스의 메소드는 실행 블록이 없는 추상 메소드로 선언. (추상 메소드는 모두 public abstract 특성을 가지므로, public abstract 생략 가능)

[구현 클래스]

개발 코드가 인터페이스 메소드 호출 시, 인터페이스는 객체의 메소드를 호출하는데, 객체는 인터페이스에서 정의된 추상 메소드와 동일한 메소드 이름, 매개 타입, 리턴 타입을 가진 실체 메소드를 가지고 있어야 한다. 이러한 객체를 인터페이스의 구현 객체라고 하고, 구현 객체를 생성하는 클래스를 구현 클래스라고 한다.

 

 

◆ 이클립스에서 인터페이스 생성

[생성하려는 패키지에서 오른쪽 마우스] - [New] - [Interface]

 

 

◆ 구현 클래스 만들기

[New] - [Class] 에서 Interfaces에서 [Add] 클릭하고, 연결하려는 인터페이스를 선택하고 [OK] 클릭

 

자동으로 클래스가 생성되며 implements 인터페이스 를 하며,

인터페이스의 추상 메소드도 오버라이딩 된다.


다중 인터페이스 구현 클래스

 

자바에서 다중상속은 인터페이스만 가능하다.

다중 인터페이스를 구현할 경우, 구현 클래스는 모든 인터페이스의 추상 메소드에 대해 실체 메소드를 작성해야 한다.

public class 구현클래스 implements 인터페이스1, 인터페이스2
    // 인터페이스1에 선언된 추상 메소드의 실체 메소드 선언
    // 인터페이스2에 선언된 추상 메소드의 실체 메소드 선언

예제1

 

Q. 동물이 소리를 내는 행동을 나타내는 AnimalSound 인터페이스 정의

1. makeSound() 라는 추상메소드 가짐

2. 이를 구현하는 Dog와 Cat 클래스 작성: 각 동물은 고유한 소리를 내야 함

3. 실행 클래스 AnimalTest에서 두 동물을 배열에 담아 소리 출력

 

[AnimalSound 인터페이스]

public interface AnimalSound {
	public String kind = "";

	// 추상 메소드
	public void makeSound();
}

▶ 인터페이스는 추상 메소드만 가질 수 있고, 필드는 상수만 가질 수 있다.

 

[구현 클래스 Dog]

public class Dog implements AnimalSound {
	public String kind = "강아지";

	public void makeSound() {
		System.out.println("멍멍!");
	}
}

▶ 구현 클래스인 Dog에서는 추상 메소드 makeSound()를 실체 메소드로 재정의

 

[구현 클래스 Cat]

public class Cat implements AnimalSound {
	public String kind = "Cat";

	public void makeSound() {
		System.out.println("야옹!");
	}
}

 

[메인 클래스 AnimalTest]

public class AnimalTest {

	public static void main(String[] args) {
		AnimalSound[] animals = { new Dog(), new Cat() };

		for (AnimalSound animal : animals) {
			animal.makeSound();
		}
	}
}

▶ AnimalSound 타입의 animals 라는 배열을 만들고 그 안에 Dog와 Cat 인스턴스를 넣어 준다.

그리고 enhanced For문을 사용하여 각 인스턴스의 makeSound() 함수를 호출하면 된다.


예제2

 

Q. Vehicle 인터페이스를 작성하고, start()와 stop() 메서드 포함

1. 이를 구현하는 Car와 Bicycle 클래스를 만들고, Car에는 연료 잔량을 확인하는 추가 메서드 checkFuel() 포함

2. 실행 클래스 VehicleTest에서 다형성을 활용해 Car와 Bicycle을 작동시키고, Car 객체만 연료 확인(instanceof 사용)

 

[Vehicle 인터페이스]

public interface Vehicle {
	public String type = null;

	public void start();

	public void stop();
}

 

[구현 클래스 Car]

public class Car implements Vehicle {
	public String type = "자동차";
	public int fuel = 0;

	public void start() {
		System.out.println(type + "가 출발합니다.");
	}

	public void stop() {
		System.out.println(type + "가 멈춥니다.");
	}

	public void checkFuel(int fuel) {
		this.fuel = fuel;
		System.out.println("남은 연료: " + fuel + "%");
	}
}

▶ 필드에 연료량을 받을 수 있는 정수형 타입의 fuel 멤버 변수를 추가하고, 해당 변수를 매개변수로 받아 남은 연료량을 출력하는 checkFuel() 메소드를 생성한다.

 

[구현 클래스 Bicycle]

public class Bicycle implements Vehicle {
	public String type = "자전거";

	public void start() {
		System.out.println(type + "가 출발합니다.");
	}

	public void stop() {
		System.out.println(type + "가 멈춥니다.");
	}
}

 

[메인 클래스 VehicleTest]

public class VehicleTest {

	public static void main(String[] args) {
		Vehicle[] vehicles = { new Car(), new Bicycle() };

		for (Vehicle vehicle : vehicles) {
			vehicle.start();
			vehicle.stop();
			if (vehicle instanceof Car) {
				((Car) vehicle).checkFuel(100);
			}
		}
	}
}

▶ Vehicle 타입의 vehicles 배열을 만들고, 배열 안에 Car와 Bicycle 인스턴스를 생성한다.

그리고, enhanced for문으로 해당 배열을 반복문으로 돌리면서 공통의 메소드인 start()와 stop() 메소드를 실행 시키되,

조건문을 사용하여 vehicle이 Car 타입이라면, checkFuel() 메소드가 호출되어 연료를 체크하는 작업이 수행 된다. 반대로, vehicle이 Car 타입이 아닐 경우에는 해당 메소드가 호출되지 않는다.

 


예제3

 

Q. Shape 인터페이스를 정의하고, calculateArea()와 describe() 메서드 포함

1. 이를 구현하는 Circle과 Rectangle 클래스를 작성하고, 각 도형의 넓이를 계산(calculateArea())하며 설명(describe()) 출력

2. Resizable 인터페이스를 만들어 resize(double factor) 메서드를 정의하고, Rectangle 클래스에만 이를 구현 (가로 세로에 각각 factor 곱함)

3,. 실행 클래스 ShapeTest 에서 다형성을 활용해 배열에 도형을 넣고 꺼내어 도형을 출력, 크기 조절이 가능한 도형만 크기 변형

 

[Shape 인스턴스]

public interface Shape {
	String type = null;

	// 추상 메소드
	double calculateArea();

	void describe();
}

▶ Circle 클래스와 Rectangle 클래스에 공통으로 들어가야 하는 두 개의 추상 메소드 선언

 

[Resizable 인스턴스] - 사각형(Rectangle 클래스 너비 조절용)

public interface Resizable {
	void resize(double factor);
}

▶ 실수형의 factor 변수를 인자로 받는 resize() 추상 메소드 선언

 

[Circle 구현 클래스] - Shape 인스턴스 구현

public class Circle implements Shape {
	String type = "원";
	double radius = 0.0;
	double size = 0.0;

	// 생성자
	Circle(double radius) {
		this.radius = radius;
	}

	// 추상메소드의 실체 메소드
	@Override
	public double calculateArea() {
		this.size = (radius * radius) * Math.PI;
		return size;
	}

	@Override
	public void describe() {
		System.out.println("이것은 반지름" + radius + "인 " + type + "입니다.");
		System.out.println("넓이: " + size);
	}
}

▶ Circle 클래스는 Shape 인스턴스의 구현 클래스 이므로, implements Shape 인스턴스

- 필드에는 추가로 반지름을 나타내는 실수형 타입의 radius, 면적을 나타내는 실수형 타입의 size 선언 및 초기화

- 생성자에 인자로 반지름을 받도록 만들고

- 인스턴스의 추상 메소드들을 실체 메소드로 재정의

  • calculateArea() 메소드: size는 radius를 제곱 후 PI를 곱해주고 return
  • describe() 메소드: 반지름, type, size 가 각각의 출력문과 융합되어 출력

 

[Rectangle 구현 클래스]  - 다중 인스턴스 구현: Shape 인스턴스, Resizable 인스턴스 

public class Rectangle implements Shape, Resizable {
	String type = "사각형";
	double width = 0.0;
	double length = 0.0;
	double size = 0.0;
	double factor = 0.0;
	double afterFactor = 0.0;

	// 생성자
	Rectangle(double width, double length) {
		this.width = width;
		this.length = length;
	}

	@Override
	public double calculateArea() {
		this.size = width * length;
		return size;
	}

	@Override
	public void describe() {
		System.out.println("이것은 가로: " + width + ", 세로: " + length + "인 " + type + "입니다.");
		System.out.println("넓이: " + size);
	}

	@Override
	public void resize(double factor) {
		this.factor = factor;
		afterFactor = (width * factor) * (length * factor);
		System.out.println(type + "크기가 " + factor + "배로 조절되었습니다.");
		System.out.println("이것은 가로: " + (width * factor) + ", 세로: " + (length * factor) + "인 " + type + "입니다.");
		System.out.println("조절 후 넓이: " + afterFactor);
	}
}

▶ Rectangle 클래스는 다중 인스턴스(Shape, Resizable)를 구현하는 클래스

- 필드에는 모두 실수형의 width(가로), length(세로), size(면적), factor(배수), afterFactor(변환 후 사이즈) 선언 및 초기화

- 생성자에는 가로와 세로 크기를 입력받도록 하고

- 3개의 추상 메소드를 실체 메소드로 재정의

  • calculateArea(): size는 가로와 세로를 곱한 값이 저장 및 반환
  • describe(): width, length, type, size 반환
  • resize(): 배수를 의미하는 factor 인자를 받아 각각 세로와 가로에 곱해주고, afterFactor 변수에 저장. 그리고 그에 관한 정보들이 출력되도록 함. 

 

[ShapeTest 클래스] - 메인 클래스

public class ShapeTest {

	public static void main(String[] args) {
		Shape[] shapes = new Shape[2];
		shapes[0] = new Circle(5);
		shapes[1] = new Rectangle(4.0, 3.0);

		for (Shape s : shapes) {
			s.calculateArea();
			s.describe();
			if (s instanceof Rectangle) {
				((Rectangle) s).resize(2.0);
			}
		}
	}
}

▶ 먼저 Shape 타입의 배열 shapes를 선언하고, 각 배열에는 2개의 인자를 넣어줌.

- 각 배열에는 반지름 값을 인자로 하는 Circle 인스턴스, 가로와 세로 크기를 인자로 하는 Rectangle 인스턴스를 넣어줌.

- enhanced for 반복문으로 shapes 배열을 순회하며, 각각의 인스턴스에서 calculateArea() 메소드와 describe() 메소드를 호출한다.

- 또한, instanceof를 사용하여 shape 객체가 Rectangle 일 경우 resize() 메소드를 호출하도록 하였다.

 


[참고]

혼자 공부하는 자바

 


다음 내용

 

[java] 인터페이스 상속, 중첩 클래스, 중첩 인터페이스

이전 내용 [java] instanceof, 인터페이스, 구현 클래스이전 내용 [java] 추상 클래스, 추상 메소드이전 내용 [java] 클래스의 타입 변환, 다형성이전 내용 [java] 접근 제한자, 클래스 상속이전 내용 [ja

puppy-foot-it.tistory.com

 

 

 

728x90
반응형