데이터 엔지니어링 과정/java

[22일차] 추상 클래스 & 인터페이스

오리는짹짹 2023. 1. 20. 16:51
목차
1. 추상클래스
2. 인터페이스
3. 타입 변환과 다형성

1. 추상 클래스

0. 추상 클래스 정의

  • 클래스들의 공통적인 특성을 추출해서 선언한 클래스
  • 추상 클래스와 실체 클래스는 상속의 관계를 가지고 있음
  • 추상 클래스가 부모, 실체 클래스가 자식으로 구현되어,
    실체 클래스는 추상 클래스의 모든 특성을 물려받고, 추가적인 특성을 가질 수 있음

1.  추상 클래스 용도

  • 공통된 필드와 메소드의 이름을 통일할 목적
  • 실체 클래스를 작성할 때 시간 절약

2. 추상 클래스 선언

  • 클래스 선언 시 abstract 키워드 붙여야 함
    ex) public abstract class 클래스{}
  • new 연산자를 이용하여 새로운 객체 만드는 것 불가능
  • 상속을 통해 자식 클래스 만들 수 있음
  • 필드, 생성자, 메소드 선언 가능
    new 연산자로 직접 생성자 호출 불가능
    자식 객체가 생성될 때 super()를 호출해서 추상 클래스 객체를 생성하므로 생성자가 반드시 있어야 함
  • 💻 추상 클래스 Phone, 실체 클래스 SmartPhone, 실행 클래스 PhoneExample  
package sec03.exam01;

public abstract class Phone {
	//필드
	public String owner;
		
	//생성자
	public Phone (String owner) {
		this.owner = owner;
	}
	
	//메소드
	public void turnOn() {
		System.out.println("폰 전원을 켭니다.");
	}
	public void turnOff() {
		System.out.println("폰 전원을 끕니다.");
	}
}
package sec03.exam01;

public class SmartPhone extends Phone {
	//생성자
	public SmartPhone(String owner) {
		super(owner);
	}
	//메소드
	public void interentSearch() {
		System.out.println("인터넷 검색을 합니다.");
	}
}
package sec03.exam01;

public class PhoneExample {
	public static void main(String[] args) {
		//Phone phone = new Phone();
		
		SmartPhone smartPhone = new SmartPhone("홍길동");
		
		smartPhone.turnOn();
		smartPhone.interentSearch();
		smartPhone.turnOff();		
	}
}

>>> 폰 전원을 켭니다.
>>> 인터넷 검색을 합니다.
>>> 폰 전원을 끕니다.

🐰 추상 클래스는 새로운 실체 클래스를 만들기 위해 부모 클래스로만 사용된다. 
➡ extends 뒤에만 올 수 있다!!

3. 추상 메소드와 재정의

  • abstract 키워드와 함께 메소드의 선언부만 있고, 메소드 실행 내용인 중괄호{} 가 없는 메소드
  • 메소드의 선언만 통일하고, 실행 내용은 실체 클래스마다 달라야 하는 경우에 활용
    ➡ 추상 클래스 설계 시 하위 클래스가 반드시 실행 내용을 채우도록 강제하고 싶은 메소드가 있을 경우 해당 메소드를 추상 메소드로 선언
    ➡ 자식 클래스는 반드시 추상 메소드를 재정의해서 실행 내용을 작성해야 함 (그렇지 않으면 컴파일 에러 발생)
  • 💻 추상 메소드 선언한 Animal 클래스, 추상 메소드를 재정의한 Dog&Cat 클래스, 실행 클래스 AnimalExample
package sec03.exam02;

public abstract class Animal {
	public String kind;
	
	public void breathe() {
		System.out.println("숨을 쉽니다.");
	}
	
	public abstract void sound();
}
package sec03.exam02;

public class Dog extends Animal{
	public Dog() {
		this.kind = "포유류";
	}
	
	@Override
	public void sound() {
		System.out.println("멍멍");
	}
}
package sec03.exam02;

public class Cat extends Animal{
	public Cat() {
		this.kind = "포유류";
	}
	
	@Override
	public void sound() {
		System.out.println("야옹");
	}
}
package sec03.exam02;

public class AnimalExample {

	public static void main(String[] args) {
		Dog dog = new Dog();
		Cat cat = new Cat();
		dog.sound();
		cat.sound();
		System.out.println("-----");

		//변수의 자동 타입 변환
		Animal animal = null;
		animal = new Dog();
		animal = new Cat();
		animal.sound();
		System.out.println("-----");
		
		//메소드의 다형성
		animalSound(new Dog());
		animalSound(new Cat());
	}
	
	public static void animalSound(Animal animal) {
		animal.sound();
	}
}

>>> 멍멍
>>> 야옹
>>> -----
>>> 야옹
>>> -----
>>> 멍멍
>>> 야옹

 

2. 인터페이스

0. 인터페이스

  • 객체의 사용 방법을 정의한 타입
  • 데이터 저장 불가
  • 개발 코드와 객체가 서로 통신하는 접점 역할
  • 코드 변경 없이 실행 내용과 리턴값을 다양화할 수 있음

1. 인터페이스 선언

  • class 키워드 대신 interface 키워드 선언
    👀 상수 필드와 추상 메소드만을 구성 멤버로 가짐
    👀 인터페이스를 객체로 생성할 수 없기 때문에 생성자를 가질 수 없음
  • 상수 필드 선언
    • 상수는 인터페이스에 고정된 값으로 실행 시에 데이터 변경 불가
    • 선언과 동시에 초기값 지정해야 함
    • 상수 선언
      : public static final
  • 💻 상수 필드 선언
package sec01.exam02;

public interface RemoteControl {
	public int MAX_VOLUME = 10;
	public int MIN_VOLUME = 0;
}
  • 추상 메소드 선언
    • 인터페이스로 호출된 메소드는 객체에서 실행되므로 추상 메소드 선언
    • 리턴 타입, 메소드 이름, 매개 변수만 기술되고 중괄호 {}를 붙이지 않는 메소드
  • 💻 추상 메소드 선언한 RemoteControl 인터페이스
package sec01.exam03;

public interface RomoteControl {
	//상수
	int MAX_VOLUME = 10;
	int MIN_VOLUME = 0;

	//추상 메소드
	void turnOn();
	void turnOff();
	void setVolume(int volume);	
}

2. 인터페이스 구현

  • 구현 객체와 구현 클래스
    • 구현 객체
      :인터페이스에서 정의된 추상 메소드와 동일한 메소드 이름, 매개 타입, 리턴 타입을 가진 실체 메소드를 가지고 있어야 함
    • 구현 클래스
      : 구현 객체를 생성하는 클래스
  • 구현 클래스
    • 클래스 선언부에 implements 키워드를 추가하고 인터 페이스 이름 명시
    • 인터페이스에 선언된 추상 메소드의 실체 메소드 선언
    • 인터페이스로 구현 객체 사용하려면 인터페이스 변수를 선언하고 구현 객체를 대입해야 함
      👀 인터페이스 변수는 참조 타입이기 때문에, 구현 객체가 대입될 경우 구현 객체의 번지를 저장
  • 💻 구현 클래스 Television과 Audio
package sec01.exam04;

public class Television implements RemoteControl{
	//필드
	private int volume;
	
	//turnOn() 추상 메소드의 실체 메소드
	public void turnOn() {
		System.out.println("TV를 켭니다.");
	}
	//turnOff() 추상 메소드의 실체 메소드
	public void turnOff() {
		System.out.println("TV를 끕니다.");
	}
	//setVolume() 추상 메소드의 실체 메소드
	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);
	}
}
package sec01.exam04;

public class Audio implements RemoteControl{
	//필드
	private int volume;
	
	//turnOn() 추상 메소드의 실체 메소드
	public void turnOn() {
		System.out.println("Audio를 켭니다.");
	}
	//turnOff() 추상 메소드의 실체 메소드
	public void turnOff() {
		System.out.println("Audio를 끕니다.");
	}
	//setVolume() 추상 메소드의 실체 메소드
	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("현재 Audio 볼륨: " + this.volume);
	}	
}
  • 💻 인터페이스 변수에 구현 객체 대입
package sec01.exam04;

public class RemoteControlExample {
	public static void main(String[] args) {
		RemoteControl rc;
		rc = new Television();
		rc = new Audio();
	}
}
  • 다중 인터페이스 구현 클래스
    • 객체는 다수의 인터페이스 타입으로 사용 가능
    • 구현 클래스는 모든 인터페이스의 추상 메소드에 대해 실체 메소드를 작성해야 함
  • 💻 인터넷을 검색할 수 있는 Searchable 인터페이스
package sec01.exam05;

public interface Searchable {
	void search(String url);
}
  • 💻 다중 인터페이스 구현 클래스 & 인터페이스 변수에 구현 객체 대입
package sec01.exam05;

public class SmartTelevision implements RemoteControl, Searchable{
	private int volume;

	public void turnOn() {
		System.out.println("TV를 켭니다.");
	}
	public void turnOff() {
		System.out.println("TV를 끕니다.");
	}
	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 void search(String url) {
		System.out.println(url + "을 검색합니다.");
	}
}
package sec01.exam05;

public class SmartTelevisionExample {
	public static void main(String[] args) {
		SmartTelevision tv = new SmartTelevision();
		
		RemoteControl rc = tv;
		Searchable searchable = tv;
	}
}

3. 💻 인터페이스 사용

package sec01.exam06;

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);
	}
}
package sec01.exam06;

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)----------------");
		
		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());
	}
}

>>> 1)----------------
>>> TV를 켭니다.
>>> 현재 TV 볼륨: 5
>>> 2)----------------
>>> Audio를 켭니다.
>>> 현재 Audio 볼륨: 5
>>> 3)----------------
>>> Audio를 켭니다.
>>> 현재 Audio 볼륨: 5
>>> 4)----------------
>>> TV를 켭니다.
>>> 현재 TV 볼륨: 5

 

3. 타입 변환과 다형성

1. 자동 타입 변환

  • 구현 객체가 인터페이스 타입으로 변환되는 것
  • 프로그램 실행 도중에 자동적으로 타입 변환이 일어남

2. 필드의 다형성

  • 💻 인터페이스
package sec02.exam01;

public interface Tire {
	public void roll();
}
  • 💻 구현 클래스
package sec02.exam01;

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

public class HankookTire implements Tire{
	@Override
	public void roll() {
		System.out.println("한국 타이어가 굴러갑니다.");
	}
}
  • 💻 필드 다형성
package sec02.exam01;

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();	
	}
}
  • 💻 필드 다형성 테스트
package sec02.exam01;

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();
	}
}

>>> 한국 타이어가 굴러갑니다.
>>> 한국 타이어가 굴러갑니다.
>>> 한국 타이어가 굴러갑니다.
>>> 한국 타이어가 굴러갑니다.
>>> 금호 타이어가 굴러갑니다.
>>> 금호 타이어가 굴러갑니다.
>>> 한국 타이어가 굴러갑니다.
>>> 한국 타이어가 굴러갑니다.

3. 매개 변수의 다형성

  • 매개 변수를 인터페이스 타입으로 선언하고 호출할 때에는 구현 객체를 대입
  • 매개 변수의 타입이 인터페이스일 경우,
    어떠한 구현 객체도 매개값으로 사용할 수 있고, 어떤 구현 객체가 제공되느냐에 따라 메소드의 실행결과가 다양해짐
  • 💻 매개 변수의 인터페이스화
package sec02.exam02;

public class Driver {
	public void drive(Vehicle vehicle) {
		vehicle.run();
	}
}
  • 💻 인터페이스
package sec02.exam02;

public interface Vehicle {
	public void run();
}
  • 💻 구현 클래스
package sec02.exam02;

public class Bus implements Vehicle{
	@Override
	public void run() {
		System.out.println("버스가 달립니다.");
	}
}
package sec02.exam02;

public class Taxi implements Vehicle{
	@Override
	public void run() {
		System.out.println("택시가 달립니다.");
	}
}
  • 💻 매개 변수의 다형성 테스트
package sec02.exam02;

public class DriverExample {
	public static void main(String[] args) {
		Driver driver = new Driver();
		
		Bus bus = new Bus();
		Taxi taxi = new Taxi();
		
		driver.drive(bus);
		driver.drive(taxi);
	}
}

>>> 버스가 달립니다.
>>> 택시가 달립니다.

4. 강제 타입 변환

  • 구현 객체가 인터페이스 타입으로 자동 변환하면, 인터페이스에 선언된 메소드만 사용 가능하다.
    경우에 따라서, 구현 클래스에 선언된 필드와 메소드를 사용해야 할 경우가 발생한다.
    • 강제 타입 변환을 해서 다시 구현 클래스 타입으로 변환 ➡ 구현 클래스의 필드와 메소드를 사용 가능
  • 💻 인터페이스
package sec02.exam03;

public interface Vehicle {
	public void run();
}
  • 💻 구현 클래스
package sec02.exam03;

public class Bus implements Vehicle{
	@Override
	public void run() {
		System.out.println("버스가 달립니다.");
	}
	
	public void checkFare () {
		System.out.println("승차요금을 체크합니다.");
	}
}
  • 💻 강제 타입 변환
package sec02.exam03;

public class VehicleExample {
	public static void main(String[] args) {
		Vehicle vehicle = new Bus();
		
		vehicle.run();
		//vehicle.checkFare(); 
		
		Bus bus = (Bus) vehicle;
		
		bus.run();
		bus.checkFare();
	}
}

>>> 버스가 달립니다.
>>> 버스가 달립니다.
>>> 승차요금을 체크합니다.

5. 객체 타입 확인

  • instanceof 연산자 사용
  • 💻 인터페이스
package sec02.exam04;

public interface Vehicle {
	public void run();
}
  • 💻 구현 클래스
package sec02.exam04;

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

public class Taxi implements Vehicle{
	@Override
	public void run() {
		System.out.println("택시가 달립니다.");
	}
}
  • 💻 객체 타입 확인
package sec02.exam04;

public class Driver {
	public void drive(Vehicle vehicle) {
		if (vehicle instanceof Bus) { //vehicle 매개변수가 참조하는 객체가 Bus인지 조사
			Bus bus = (Bus) vehicle;
			bus.checkFare();
		}
		vehicle.run();
	}
}
package sec02.exam04;

public class DriverExample {
	public static void main(String[] args) {
		Driver driver = new Driver();
		
		Bus bus = new Bus();
		Taxi taxi = new Taxi();
		
		driver.drive(bus);
		driver.drive(taxi);
	}
}

>>> 승차요금을 체크합니다.
>>> 버스가 달립니다.
>>> 택시가 달립니다.

6. 인터페이스 상속

  • 클래스와 달리 다중 상속 허용
  • extends 뒤에 상속할 인터페이스 나열
  • 💻 상위 인터페이스
package sex02.exam05;

public interface InterfaceA {
	public void methodA();
}
package sex02.exam05;

public interface InterfaceB {
	public void methodB();
}
  • 💻 하위 인터페이스
package sex02.exam05;

public interface InterfaceC extends InterfaceA,InterfaceB{
	public void methodC();
}
  • 💻 하위 인터페이스 구현
package sex02.exam05;

public class ImplementationC implements InterfaceC {
	public void methodA() {
		System.out.println("ImplementationC-methodA() 실행");
	}
	
	public void methodB() {
		System.out.println("ImplementationC-methodB() 실행");
	}
	
	public void methodC() {
		System.out.println("ImeplementationC-methodC() 실행");
	}
}
  • 💻 호출 가능 메소드
package sex02.exam05;

public class Example {
	public static void main(String[] args) {
		ImplementationC impl = new ImplementationC();
		
		InterfaceA ia =impl;
		ia.methodA();
		System.out.println();
		
		InterfaceB ib =impl;
		ib.methodB();
		System.out.println();
		
		InterfaceC ic =impl;
		ic.methodA();
		ic.methodB();
		ic.methodC();
	}
}

>>> ImplementationC-methodA() 실행
>>> 
>>> ImplementationC-methodB() 실행
>>> 
>>> ImplementationC-methodA() 실행
>>> ImplementationC-methodB() 실행
>>> ImeplementationC-methodC() 실행