Recent Posts
Recent Comments
Link
11-21 14:38
Today
Total
관리 메뉴

삶 가운데 남긴 기록 AACII.TISTORY.COM

추상 클래스와 인터페이스 본문

DEV&OPS/Java

추상 클래스와 인터페이스

ALEPH.GEM 2022. 3. 31. 17:41

추상 클래스(abstract class)

클래스 이름 앞에 abstract 키워드를 붙은 클래스를 추상 클래스라고 합니다.

추상 클래스는 인스턴스를 생성할 수 없고 상속 후에 오버라이딩을 할 목적으로 생성합니다.

추상화된 클래스를 부모 클래스로 사용함으로써 자손 클래스들의 공통된 필드나 메서드의 이름을 통일시켜서 설계 목적으로 사용합니다.

Abstract.java

public abstract class Abstract {
	public String owner;
	public Abstract(String owner) {
		this.owner = owner;
	}
	public void turnOn() {
		System.out.println("전원 켬");
	}
	public void turnOff() {
		System.out.println("전원 끔");
	}
}

ExClass.java

class ExClass extends Abstract {
	public ExClass(String owner) {
		super(owner);
	}
	public void run() {
		System.out.println("실행");
	}
	
	public static void main(String[] args) {
		ExClass ex = new ExClass("관리자");
		ex.turnOn();
		ex.run();
		ex.turnOff();
	}
}

 

 

추상 메서드

추상 클래스에서는 추상 메서드를 정의 할 수 있습니다.

메서드 이름 앞에 abstract 키워드를 추가한 뒤 데이터 타입과 리턴 타입, 메서드 이름만 정의하면 됩니다.

추상 메서드는 상속 받은 후 반드시 오버라이딩(재정의)을 해야 합니다.

 

 

인터페이스(interface)

추상 클래스는 그 또한 클래스 이기 때문에 확장과 오버라이딩을 위해 extends를 해야하기 때문에 한계가 명확 하지만, 인터페이스는 implements를 통해 확장하므로 유연하게 다형성을 구현할 수 있습니다.

인터페이스는 콤마를 통해  implemetns를 여러개 등록할 수 있습니다.

인터페이스를 통해 객체의 동작을 다양하게 재정의 해서 사용할 수 있습니다.

인터페이스는 메서드의 호출 방법을 고정시켜놓음으로써 이후 상속(구현)하는 모든 객체들에서 메서드 호출 방법을 고정시킬 수 있는 것입니다.

 

RemoteControl.java

public interface RemoteControl {
	int MAX_VOLUME = 10;
	int MIN_VOLUME = 0;
	
	//추상 메서드
	void turnOn();
	void turnOff();
	void setVolume(int volume);
	
	//디폴트 메서드 java8이상
	default void setMute(boolean mute) {
		if(mute) {
			System.out.println("무음");
		}else {
			System.out.println("무음 해제");
		}
	}
	
	//정적 메서드 java8이상
	static void changeBattery() {
		System.out.println("건전지를 교체합니다.");
	}
	
}

 Televison.java

public class Televison implements RemoteControl {
	private int volume;

	@Override
	public void turnOn() {
		// TODO Auto-generated method stub
		System.out.println("TV 켬");
	}

	@Override
	public void turnOff() {
		// TODO Auto-generated method stub
		System.out.println("TV 끔");
	}

	@Override
	public void setVolume(int volume) {
		// TODO Auto-generated method stub
		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;
		}
	}

}

인터페이스 또한 추상 메서드들을 오버라이딩해서 사용해야합니다.

인터페이스는 상수와 메서드만을 가지고 있으며 추상 클래스처럼 인스턴스를 생성할 수 없습니다.

인터페이스는 기본적으로 접근 제한자는 public 입니다.

인터페이스를 구현한 객체에서는 인터페이스의 이름으로 된 참조 변수(인스턴스이름)를 할당 할 수 있습니다.

RemoteControl rc = new Televison();

자바7 이전까지 인터페이스의 메소드는 추상 메서드만 선언이 가능했지만 자바8부터는 일반 메서드와 static 메서드도 선언이 가능합니다.

 

 

익명(구현) 클래스

new 연산자 뒤에는 클래스 이름이 오는 것이 원칙이지만 클래스 대신에 인터페이스가 오는 경우를 익명(구현) 클래스라고 합니다.

RemoteControlExample.java

public class RemoteControlExample {
	public static void main(String[] args) {
		RemoteControl rc = new RemoteControl() {

			@Override
			public void turnOn() {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void turnOff() {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void setVolume(int volume) {
				// TODO Auto-generated method stub
				
			}
			
		};
	}
}

이 파일을 컴파일하면 RemoteControlExample$1.class 파일이 생성되며, 여러개 만들면 $뒤의 숫자가 늘어납니다.

 

RemoteControl rc = new Television();
rc.turnOn();

인터페이스의 turnOn()을 호출하지만 Televison()에서 오버라이딩한 메서드가 실행됩니다.

RemoteControl.setMute(true);	//디폴트 메서드는 인터페이스에서 실행할 수 없고 구현 클래스가 필요
RemoteContro rc = new Televison();
rc.setMute(true);

하지만 static 메서드는 인터페이스 이름으로도 바로 접근이 가능합니다.

RemoteControl.changeBattery();

 

 

자동 타입 변환(Promotion)

인스턴스가 인터페이스 타입으로 변환되는 것은 자동 타입 변환에 해당합니다.

인터페이스를 구현한 클래스를 상속받은 자식 클래스에서도 역시 인터페이스 타입으로 자동 타입을 변환할 수 있습니다.

 

 

매개 변수의 다형성

메서드를 호출 할 때 매개 변수를 전달 할 때에도 인터페이스를 매개 변수로 전달 하면 매개 변수도 다형성을 구현할 수 있습니다.

public interface Vehicle{
    public void run();
}
public class Driver{
    public void drive(Vehicle vehicle){
        vehicle.run();
    }
}
Driver driver = new Driver();
Bus bus = new Bus();
driver.drive(bus);

여기서 Bus 클래스가 Vehicle을 implements 했다면 bus는 인터페이스인 Vehicle 타입으로 자동 형변환이 됩니다.

 

 

형(type) 변환(casting)

기본 데이터 타입인 int 같은 것들을 형 변환 하는 것을 살펴보았었는데, 클래스나 인터페이스 또한 데이터 타입이기 때문에 형변환(type casting)을 할 수 있습니다.

형 변환을 하려면 형변환이 가능한지 여부를 instanceof 로 확인할수 있습니다.

 

public interface Vehicle {
	public void run();
}

 

public class Bus implements Vehicle {

	@Override
	public void run() {
		System.out.println("버스가 운행합니다.");
	}
	
	public void stop() {
		System.out.println("버스가 정지합니다.");
	}

}
public class VehicleExample {
	public static void main(String[] args) {
		Vehicle vehicle = new Bus();
		vehicle.run();
		//vehicle.stop(); //Vehicle 인터페이스는 stop()메서드가 없고 Bus에서 추가 구현한 메서드라서 호출 할 수 없습니다.
		//instanceof : 해당 타입으로 형변환 할수 있는지 확인
		if(vehicle instanceof Bus) {
			Bus bus = (Bus)vehicle;	//강제 형변환
			bus.run();
			bus.stop(); //Bus로 강제 형 변환을 했기 때문에 stop()메서드를 호출 할 수 있습니다.
		}
	}
}

 

인터페이스 상속

인터페이스도 다른 인터페이스를 상속(extends) 할 수 있습니다.

인퍼페이스는 클래스와 다르게 다중 상속을 지원하기 때문에 implements처럼 여러개의 인터페이스를 extends할 수 있습니다.

InterfaceC가 InterfaceA와 InterfaceB를 extends 했을 때 상속관계를 예제를 통해 알아봅시다.

public interface InterfaceA {
	public void methodA();
}
public interface InterfaceB {
	public void methodB();
}
public interface InterfaceC extends InterfaceA, InterfaceB{
	public void methodC();
}
public class InterfaceCImpl implements InterfaceC {

	@Override
	public void methodA() {
		System.out.println("InterfaceC, methodA()");
	}

	@Override
	public void methodB() {
		System.out.println("InterfaceC, methodB()");
	}

	@Override
	public void methodC() {
		System.out.println("InterfaceC, methodC()");
	}

}
public class ExInterface {
	public static void main(String[] args) {
		InterfaceCImpl impl = new InterfaceCImpl();
		InterfaceA ia = impl;
		ia.methodA();	//InterfaceA타입이므로 methodA만 호출가능
		System.out.println();
		InterfaceB ib = impl;
		ib.methodB();	//InterfaceB타입이므로 methodB만 호출가능
		System.out.println();
		InterfaceC ic = impl;	//methodA,B,C 모두 호출가능
		ic.methodA();
		ic.methodB();
		ic.methodC();
	}
}

 

디폴트 메서드

인터페이스에는 추상 메서드만 있는 것이 아니라 default 메서드를 정의 할 수 있습니다.

메서드 이름 앞에 default 를 붙여 디폴트 메서드를 정의 합니다.

default 메서드를 사용하는 이유는 추후 인터페이스에 추가 메서드를 정의하고 싶을 때, 기존 implements 했던 구현 클래스들에게 영향을 끼치지 않고 인터페이스에 기능을 추가하기 위함입니다.

public interface InterfaceA {
	public void methodA();
	public default void defaultMethodA() {
		System.out.println("defaultMethodA 실행");
		//이 default method는 implements(구현)한 클래스에서 반드시 override하지 않아도 됩니다.
	}
}
public class InterfaceAImpl implements InterfaceA {

	@Override
	public void methodA() {
		System.out.println("methodA가 실행");
	}

}

default 메서드를 상속받은 인터페이스는 default 메서드를 그대로 사용해도 되고, 오버라이드해서 변경해도 사용해도 도고, 상속받은 해당 default 메서드를 다시 추상 메서드로 재 선언 할 수 있습니다.

 

 

 

 

 

 

 

 

 

 

 

 

728x90

'DEV&OPS > Java' 카테고리의 다른 글

익명 객체  (0) 2022.04.05
중첩 클래스 중첩 인터페이스  (0) 2022.04.05
자바 클래스와 메서드  (0) 2022.03.28
조건문과 제어문  (0) 2022.03.25
자바 연산자  (0) 2022.03.24