[혼공자바] 5주차 공부 기록

Say·2025년 8월 12일
0

인터페이스

  • 개발 코드와 객체가 서로 통신하는 접점 역할
  • 인터페이스의 메소드 호출 → 객체의 메소드 호출
  • 객체 사용 방법을 정의한 것

🤔 인터페이스를 왜 사용해야할까?

하나의 객체가 아니라 여러 객체들과 사용이 가능하므로 어떤 객체를 사용하느냐에 따라서 실행 내용과 리턴값이 달라질 수 있어서! ➡️ 다양화

인터페이스 선언

public interface 인터페이스이름 { }
  • 🚨주의
    • 상수 필드, 추상 메소드를 가짐
    • 객체로 생성 할 수 없음

✅ 상수 필드 선언

  • 실행 시 데이터를 저장할 수 있는 인스턴스 또는 정적 필드 선언 불가
  • 상수 필드는 선언 가능 → 고정. 변경 불가!!
  • 인터페이스에 선언된 필드는 모두 public static final특성 가짐

✅ 추상 메소드 선언

  • 인터페이스를 통해 호출된 메소드 → 객체에서 실행
  • 실행 블록이 필요 없는 추상 메소드로 선언
    • 사실 우리가 작성하지 않아도 컴파일 시 자동으로 public abstract가 자동으로 붙음
public interface RemoteControl {
	//상수
	int MAX_VOLUME = 10;
	int MIN_VOLUME = 0;
	
	//추상 메소드
	void turnOn();
	void turnOff();
	void setVolume(int volume);
}

인터페이스 구현

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

✅ 구현 클래스

  • 인터페이스 타입을 사용할 수 있음을 알려주기 위한 키워드
    • implements
      public class 구현클래스이름 implements 인터페이스이름 {
      	// 인터페이스에서 선언했던 추상 메소드, 실제 메소드 선언
      }

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

  • 다수의 인터페이스 타입으로 객체를 구현할 수 있다.
    public class 구현클래스이름 implements 인터페이스이름_1, 인터페이스이름_2 {
    	// 인터페이스_1 에서 선언했던 추상 메소드, 실제 메소드 선언
    	// 인터페이스_2 에서 선언했던 추상 메소드, 실제 메소드 선언
    }

인터페이스 사용

  • 구현 객체는 인터페이스 변수에 대입할 수 있다.
public interface RemoteControl {
	//상수
	int MAX_VOLUME = 10;
	int MIN_VOLUME = 0;
	
	//추상 메소드
	void turnOn();
	void turnOff();
	void setVolume(int volume);
}
public class MyClass {
	// 필드
	RemoteControl rc = new Television();

	// 생성자
	MyClass() {
	}

	MyClass(RemoteControl rc) {
		this.rc = rc;
		rc.turnOn();
		rc.setVolume(5);
	}

	// 메소드
	void methodA() {
		RemoteControl rc = new Audio();
		rc.turnOn();
		rc.setVolume(5);
	}

	void methodB(RemoteControl rc) {
		rc.turnOn();
		rc.setVolume(5);
	}
}
public class MyClassExample {
	public static void main(String[] args) {
		System.out.println("1)----------------");
		
		MyClass myClass1 = new MyClass();
		myClass1.rc.turnOn();
		myClass1.rc.setVolume(5);
		
		System.out.println("2)----------------");
		
		/* ⭐️ 인터페이스 변수에 객체 대입하기!!
		* RemoteControl를 implements한 Audio 클래스
		* MyClass의 생성자를 살펴보면 
		MyClass(RemoteControl rc) {
		this.rc = rc;
		rc.turnOn();
		rc.setVolume(5);
	} 라는 생성자가 존재하는데 Audio를 인터페이스 변수에 대입하며,
			Audio 클래스에서 작성했던 함수를 사용할 수 있다. 
			 -> 원하는 클래스를 넣으면서 값의 다양화가 가능해진다 
		*/
		MyClass myClass2 = new MyClass(new Audio());
		
		System.out.println("3)----------------");
		
		MyClass myClass3 = new MyClass();
		myClass3.methodA();
		
		System.out.println("4)----------------");
		
		MyClass myClass4 = new MyClass();
		myClass4.methodB(new Television());
	}
}

타입 변환과 다형성

인터페이스 다형성

  • 소스 코드는 변함이 없는데 구현 객체를 교체함으로써 프로그램의 실행결과가 다양해짐.
  • 클래스만 교체하면 프로그램을 문제없게 재실행할 수 있다.

자동 타입 변환

  • 구현 객체가 인터페이스 타입으로 변환되는 것
  • 인터페이스 변수 = 구현 객체; ➡️ 구현 객체가 인터페이스 변수로 자동 타입 변환!

🤔 자동 타입 변환이 필요한 이유가 무엇일까?

필드의 다형성과 매개 변수의 다형성을 구현할 수 있다.

필드의 다형성

  • 필드 타입으로 인터페이스를 선언하면 필드값으로 여러가지 객체를 대입할 수 있다.
    public class Car {
    	// 인터페이스 타입 필드 선언과 초기 구현 객체 대입
    	Tire frontLeftTire = new HankookTire();
    	Tire frontRightTire = new HankookTire();
    	Tire backLeftTire = new HankookTire();
    	Tire backRightTire = new HankookTire();
    	
    	void run() {
    		frontLeftTire.roll();
    		frontRightTire.roll();
    		backLeftTire.roll();
    		backRightTire.roll();
    	}
    }
    
    public class CarExample {
    	public static void main(String[] args) {
    		Car myCar = new Car();
    		
    		myCar.run();
    		
    		myCar.frontLeftTire = new KumhoTire();
    		myCar.frontRightTire = new KumhoTire();
    		
    		myCar.run();
    	}
    }

매개 변수의 다형성

  • 자동 타입 변환 → 필드의 값을 대입할 때에 발생하지만, 주로 메소드를 호출할 때 많이 발생.
  • 매개 변수를 인터페이스 타입으로 선언하고 호출할 때에는 구현 객체를 대입
    public interface Vehicle {
    	public void run();
    }
    
    public class Driver {
    	public void drive(Vehicle vehicle) {
    		vehicle.run();
    	}
    }
    여기서 Bus() 라는 구현 클래스가 있다고 하자.
    Driver driver = new Driver();
    
    Bus bus = new Bus();
    
    driver.drive(bus); // -> 자동 타입 변환 발생!!
    매개 변수의 타입 → 인터페이스일 경우 어떠한 구현 객체도 매개값으로 사용 O

강제 타입 변환

  • 구현 객체 → 인터페이스 타입으로 자동 변환한다면,
    • 인터페이스에 선언된 메소드만 사용 가능
    • 근데 구현 클래스에 선언된 필드와 메소드를 사용해야할 경우도 발생한다.
    • 이럴 때는 어떻게? ➡️ 강제 타입 변환

객체 타입 확인

  • 강제 변환 타입 → 구현 객체가 인터페이스 타입으로 변환되어 있는 상태에서 가능
  • ClassCaseException → 무작정 강제 타입 변환할 경우 생기는 예외 처리
  • instanceof 연산자로 확인하고 안전하게 강제 타입 변환 진행

추가 숙제

중첩 클래스 구조를 이용하기!

public class Car {
    class Tire { } // 인스턴스 멤버 클래스
    static class Engine { } // 정적 멤버 클래스

}
public class NestedClassExample {
    public static void main(String[] arg) {
        Car myCar = new Car();
        Car.Tire tire = myCar.new Tire(); // 여기 채우기!
        Car.Engine engine = new Car.Engine(); // 여기 채우기!

    }
}

class Tire인스턴스 멤버 클래스

  • static이 붙지 않음
  • Car 객체에 종속 ➡️ Tire 객체를 만들기 전에 반드시 Car 객체가 먼저 있어야 한다!!
  • 만약, new Tire()만 쓰면? ➡️ Car 인스턴스를 지정하지 않았기 때문에 컴파일 에러 발생!!

static class Engine정적 멤버 클래스

  • static이 붙음
  • Car 객체와 독립적으로 존재 가능
  • Car 인스턴스를 만들 필요 ❌
  • 인스턴스 멤버 클래스 ➡️ 반드시 myCar가 있어야만 객체 생성 가능
  • 정적 멤버 클래스 ➡️ 클래스 이름만으로 바로 생성 가능
profile
Say Hi!

0개의 댓글