혼자 공부하는 자바 - 8장. 인터페이스

youngtae·2023년 3월 27일
0

자바 이론

목록 보기
7/12
post-thumbnail

인터페이스

  • 인터페이스는 개발 코드와 객체가 서로 통신하는 접점 역할을 함
  • 개발 코드를 수정하지 않고 사용하는 객체를 변경할 수 있도록 하기 위해서 중간에 인터페이스를 거침 → 코드 변경 없이 실행 내용과 리턴값을 다양화 할 수 있다.

인터페이스 선언

  • 인터페이스는 ~.java 형태의 소스파일로 작성되고, 컴파일러를 통해 ~.class 형태로 컴파일 되기 때문에 클래스와 같지만
  • public interface 인터페이스이름 {…} 로 선언
  • 상수 필드와 추상 메소드만을 구성 멤버로 가짐
  • 객체로 생성할 수 없기 때문에 생성자 x

상수 필드 선언

  • 인터페이스에 고정된 값으로 실행 시에 바꿀 수 없음
public interface RemoteControl {
	public int MAX_VALUE = 10;
}

추상 메소드 선언

  • 인터페이스로 호출된 메소드는 객체에서 실행되므로 추상 메소드로 선언
public interface RemoteControl {
	
	public int MAX_VALUE = 10;

//추상 메소드
	public void turnOn();
	public void turnOff();
	public void setVolume(int volume);
	// 메소드 선언부만 작성

인터페이스 구현

  • 인터페이스에서 정의된 추상 메소드와 동일한 메소드 이름, 매개타입을 가진 실체 메소드를 가지고 있는 객체를 ‘구현 객체’

  • 보통의 클래스와 동일하고 인터페이스 타입으로 사용할 수 있음을 알려주기 위해 implements 키워드 추가

  • implements 뒤에 여러 인터페이스 추가해서 다중으로도 사용 가능

  • public class 구현클래스이름 implements 인터페이스이름 {…}

public class Television implements RemoteControl {

	private int volume;
	// turnOn() 추상 메소드의 실체 메소드
	public void turnOn() {
		System.out.println("TV를 켭니다");
	}

	public void turnOff() {
		System.out.println("TV를 끕니다");
	}
	
//setVolume 추상메소드의 실체 메소드
	// 인터페이스 상수를 이용해서 volume필드의 값을 제한
	public void setVolume(int volume) {
		if(volume>RemoteControl.MAX_VOLUME) {
			this.volume = RemoteControl.MAX_VOLUME;
		} else if(volume<RemoteControl.MIN_VOLUME) {
			this.volume = RemoteControl.MIN_VOLUME;
		} else {
			this.volume = volume;
		}
		System.out.println("현재 TV 볼륨: " + this.volume);
	}
}
  • 인터페이스로 구현 객체를 사용하려면 인터페이스 변수 선언하고, 구현객체를 대입해야함
  • 인터페이스 변수는 참조 타입이기 때문에 구현객체가 대입될 경우 구현 객체의 번지를 저장
public class RemoteControlExample {
	public static void main(String[] args) {
		RemoteControl rc;
		rc = new Television();
		rc = new Audio();
	}
}

인터페이스 사용

public class MyClass {
	// 1. 인터페이스가 필드 타입으로 사용될 경우, 필드에 구현객체 대입 가능
	RemoteControl rc = new Television();
	
	// 2. 인터페이스가 생성자의 매개 변수 타입으로 사용될 경우,
	// new 연산자로 객체를 생성할 때 구현 객체를 생성자의 매개값으로 대입 가능
	MyClass(RemoteControl rc) { // 생성자의 매개값으로 구현 객체 대입
		
		this.rc = rc;
	}
	
	void methodA() {
		// 3. 인터페이스가 로컬 변수 타입으로 사용될 경우, 변수에 구현 객체를 대입 가능
		RemoteControl rc = new Audio(); 
	}
	
	// 4. 인터페이스가 메소드의 매개 변수 타입으로 사용될 경우, 메소드 호출 시 구현 객체를 매개값으로 대입 가능
	void methodB(RemoteControl rc) { // 생성자의 매개값으로 구현 객체 대입
		
	}
}

1에서 선언된 필드 rc 사용

Myclass myClass = new MyClass();
myClass.rc.turnOn();  // Television의 turnOn()이 실행
myClass.rc.setVolume(5); // Television의 setVolume()이 실행

2에서 생성자 매개변수 타입으로 선언된 rc 사용

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

3에서 로컬 변수로 선언된 rc 사용

void methodA() {
	RemoteControl rc = new Audio();
	rc.turnOn();  // Audio의 turnOn()이 실행
	rc.setVolume(5); // Audio의 setVolume()이 실행
}

4에서 메소드의 매개변수 타입으로 선언된 rc 사용

void methodB(RemoteControl rc) {
	rc.turnOn();
	rc.setVolume(5);
}

타입 변환과 다형성

자동 타입 변환

  • 구현 객체가 인터페이스 타입으로 변환되는 것은 자동 타입 변환
  • 인터페이스 구현 클래스를 상속해서 자식 클래스 만들었다며면 자식 객체도 자동 타입 변환 가능

필드의 다형성

// Tire.java
public interface Tire {
	public void roll();
}

// Hankook.java
public class HankookTire implements Tire {
	@Override
	public void roll() {
		System.out.println("한국 타이어가 굴러갑니다.");
	}
}

// Kumho.java
public class KumhoTire implements Tire {
	@Override
	public void roll() {
		System.out.println("금호 타이어가 굴러갑니다.");
	}
}

// Car.java
public class Car {
// 인터페이스 타입 필드 선언과 초기 구현 객체 대입
	Tire frontLeftTire = new HankookTire();
	Tire frontRightTire = new HankookTire();
	Tire backLeftTire = new HankookTire();
	Tire backRightTire = new HankookTire();
	
	void run() {
		// 인터페이스에서 설명된 roll()메소드 호
		frontLeftTire.roll();
		frontRightTire.roll();
		backLeftTire.roll();
		backRightTire.roll();
	}
}

// example.java
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();
	}
}
// 출력결과
한국 타이어가 굴러갑니다
한국 타이어가 굴러갑니다
한국 타이어가 굴러갑니다
한국 타이어가 굴러갑니다
금호 타이어가 굴러갑니다 // 두개만 타이어 교체 했음
금호 타이어가 굴러갑니다
한국 타이어가 굴러갑니다
한국 타이어가 굴러갑니다

매개 변수의 다형성

  • 이번에는 매개 변수를 인터페이스 타입으로 선언하고 호출할때는 구현 객체를 대입
  • 매개 변수의 타입이 인터페이스일 경우 어떠한 구현 객체도 매개값으로 사용할 수 있고, 어떤 구현 객체가 제공되느냐에 따라 메소드 실행결과는 다양해짐
    //Driver.java
    public class Driver {
    	public void drive(Vehicle vehicle) {
    		vehicle.run();
    	}
    }
    
    //Vehicle.java
    public interface Vehicle {
    	public void run();
    }
    
    //Bus.java
    public class Bus implements Vehicle {
    	@Override
    	public void run() {
    		System.out.println("버스가 달립니다.");
    	}
    }
    
    //Taxi
    public class Taxi implements Vehicle {
    	@Override
    	public void run() {
    		System.out.println("택시가 달립니.");
    	}
    }
    
    //example.java
    public class DriverExample {
    	public static void main(String[] args) {
    		Driver driver = new Driver();
    		
    		Bus bus = new Bus();
    		Taxi taxi = new Taxi();
    		
    		driver.drive(bus);  // 자동 타입 변환: Vehicle vehicle = bus;
    		driver.drive(taxi); // 자동 타입 변환
    	}
    }
    
    //출력결과
    버스가 달립니다.
    택시가 달립니다.

강제 타입 변환

  • 구현 객체가 인터페이스 타입으로 자동 타입 변환하면, 인터페이스에 선언된 메소드만 사용가능해짐
  • 강제 타입 변환으로 다시 구현 클래스 타입으로 변환한 다음, 구현 클래스의 필드와 메소드 사용 가능
//Vehicle.java
public interface Vehicle {
	public void run();
}

//Bus.java
public class Bus implements Vehicle {
	@Override
	public void run() {
		System.out.println("버스가 달립니다.");
	}
	
	public void checkFare() {
		System.out.println("승차요금을 체크합니다.");
	}
}

//example.java
public class VehicleExample {
	public static void main(String[] args) {
		Vehicle vehicle = new Bus();

		vehicle.run();
		//vehicle.checkFare(); (x)  vehicle 인터페이스에는 checkFare()가 없음

		Bus bus = (Bus) vehicle;  //강제 타입 변환

		bus.run();
		bus.checkFare(); // Bus클래스에는 checkFare()가 있음
	}
}

//출력결과
버스가 달립니다.
버스가 달립니다.
승차요금을 체크합니다.

객체 타입 확인

  • 7장 상속에서 사용한것과 동일하게 instanceof 연산자 사용
    public class Driver {
    	public void drive(Vehicle vehicle) {
    		if(vehicle instanceof Bus) { // vehucle 매개변수가 참조하는 객체가 Bus인지 조사
    			Bus bus = (Bus) vehicle; // Bus 객체면 강제타입 변환
    			bus.checkFare(); // 강제 변환해야 하는 이유
    		}
    		vehicle.run();
    	}
    }

인터페이스 상속

  • 인터페이스도 다른 인터페이스 상속 가능, 다중 상속도 허용
  • public interface 하위인터페이스 extends 상위1, 상위2 {…}
  • 하위 인터페이스를 구현하는 클래스는 하위의 메소드뿐만 아니라 상위의 모든 추상 메소드에 대한 실체 메소드를 가지고 있어야한다. 그러므로 구현 클래스로부터 객체 생성 후에 하위 및 상위 타입으로 변환 가
profile
나의 개발기록

0개의 댓글