데이터 엔지니어링 과정/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() 실행