ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 15. 추상 클래스와 인터페이스
    개발자 수업/Java 2021. 10. 13. 09:20

    1. abstract -- 추상적인, 미완성의
        1) 클래스 앞에 붙을 때 : 클래스 내에 추상 메서드가 존재하는 클래스임
        2) 메서드 앞에 붙을 때 : 선언부만 존재하고 구현부가 없는 추상 메서드임

    2. 추상 클래스란?
        1) 개념
            - 완성되지 않은 설계도와 같음
            - 인스턴스를 생성할 수 없음
                => 상속을 통해서 자손클래스에서 추상메서드를 다 구현해야 인스턴스를 생성할 수 있음
            - 추상 메서드(선언부만 존재)를 최소 1개 이상 포함하고 있는 클래스임
            - 다른 클래스를 작성하는데 도움을 줄 목적으로 이용됨

    3. 추상 메서드란?
        1) 메서드의 선언부만 있고, 구현부(정의부, 목통)이 없는 메서드를 말함
            public abstract void power(String name);
        2) 자손마다 다르게 구현될 것 이라고 예상될 때 사용함
        3) 추상 클래스를 상속받는 자손 클래스는 조상의 추상 메서드의 구현부를 완성해야 인스턴스를 생성할 수 있음(일부만 구현하는 경우도 있음)

    4. 추상 클래스의 작성
        1) 공통적으로 사용될 것이라고 예상되는 것을 모아서 하나의 추상클래스로 만듦
        2) 코드 중복 제거됨
        3) 한 곳에서 관리됨
        4) 오류가 줄어듦

     

    /*
     * 추상 클래스 : 1개 이상의 추상 메서드를 포함하는 클래스
     * 			  추상클래스는 인스턴스를 절대 생성할 수 없음
     * 추상 메서드 : 선언부만 존재하고 구현부는 없는 메서드임
     */
    public abstract class ContentSender {
    
    	private String title;
    	private String name;
    	
    	public ContentSender(String title, String name) {
    		super();
    		this.title = title;
    		this.name = name;
    	}
    
    	public String getTitle() {
    		return title;
    	}
    
    	public String getName() {
    		return name;
    	}
    	
    	// 추상메서드 => 상속을 통해서 반드시 재정의(오버라이딩) 되어야 비로소 인스턴스를 생성할 수 있음
    	public abstract void sendMessage(String content);
    }
    
    
    
    
    
    
    
    public class KaKaoSender extends ContentSender {
    
    	private String content;
    	
    	public KaKaoSender(String title, String name, String content) {
    		super(title, name);
    		this.content = content;
    	}
    	
    	public String getContent() {
    		return this.content;
    	}
    
    	@Override
    	public void sendMessage(String recipient) {
    		System.out.println("제목 : " + this.getName());
    		System.out.println("이름 : " + this.getName());
    		System.out.println("내용 : " + this.getContent());
    		System.out.println("받는 사람 : " + recipient);
    
    	}
    
    }
    
    
    
    
    
    
    public class SmsSender extends ContentSender{
    
    	private String content;
    	
    	public SmsSender(String title, String name, String content) {
    		super(title, name);
    		this.content = content;
    		
    	}
    	
    	public String getContent() {
    		return this.content;
    	}
    
    	@Override
    	public void sendMessage(String recipient) {
    		System.out.println("제목2 : " + this.getName());
    		System.out.println("이름2 : " + this.getName());
    		System.out.println("내용2 : " + this.getContent());
    		System.out.println("받는 사람2 : " + recipient);
    	}
    
    }
    
    
    
    
    
    
    
    public class SenderTest {
    	
    	public static void main(String[] args) {
    		// 추상 클래스라서 절대 인스턴스 생성할 수 없음
    		// ContentSender contentSender = new ContentSender("","");
    		
    		// 추상 클래스도 조상이니까 필드의 다형성 적용됨
    		ContentSender contentSender = new KaKaoSender("카카오톡", "김원효", "안녕 해피바이러스");
    		contentSender.sendMessage("박지선");
    		System.out.println();
    		
    		ContentSender contentSender2 = new SmsSender("SMS", "박성광", "네 귀하고 씩씩했던 삶");
    		contentSender2.sendMessage("박지선");
    	}
    }

    // 추상 클래스
    public abstract class Phone {
    
    	private int serialNo;
    	private String company;
    	private String owner;
    	
    	public Phone(int serialNo, String company, String owner) {
    		super();
    		this.serialNo = serialNo;
    		this.company = company;
    		this.owner = owner;
    	}
    
    	public int getSerialNo() {
    		return serialNo;
    	}
    
    	public String getCompany() {
    		return company;
    	}
    
    	public String getOwner() {
    		return owner;
    	}
    
    	// 추상 메서드
    	public abstract void turnOn();
    	public abstract void turnOff();
    
    	public void showInfo() {
    		System.out.println("시리얼 넘버 : " + this.getSerialNo());
    		System.out.println("제조회사 : " + this.getCompany());
    		System.out.println("소유자 : " + this.getOwner());
    	}
    }
    public class SmartPhone extends Phone {
    	
    	public SmartPhone(int serialNo, String company, String owner) {
    		super(serialNo, company, owner);
    		
    	}
    
    	@Override
    	public void turnOn() {
    		System.out.println("스마트폰이 켜졌습니다.");		
    	}
    
    	@Override
    	public void turnOff() {
    		System.out.println("스마트폰이 꺼졌습니다.");		
    	}
    	
    	public void internetSearch() {
    		System.out.println("구글 검색을 합니다.");
    	}
    
    }
    public class TripleCameraPhone extends Phone {
    
    	public TripleCameraPhone(int serialNo, String company, String owner) {
    		super(serialNo, company, owner);
    		
    	}
    
    	@Override
    	public void turnOn() {
    		System.out.println("트리플 카메라폰이 켜졌습니다");
    		
    	}
    
    	@Override
    	public void turnOff() {
    		System.out.println("트리플 카메라폰이 꺼졌습니다.");
    		
    	}
    	
    	public void cameraOn() {
    		System.out.println("망원 기능이 사용됩니다.");
    	}
    	
    	public void cameraOff() {
    		System.out.println("망원 기능이 중지됩니다.");
    	}
    
    }
    public class PhoneTest {
    
    	public static void main(String[] args) {
    		// 추상 클래스는 인스턴스 생성할 수 없음
    		// Phone phone = new Phone(1,"","");
    		
    		SmartPhone smartPhone = new SmartPhone(201904, "LG전자", "LG-V50");
    		smartPhone.showInfo();
    		smartPhone.turnOn();
    		smartPhone.turnOff();
    		smartPhone.internetSearch();
    		System.out.println();
    		
    		TripleCameraPhone tCameraPhone = new TripleCameraPhone(202110, "Apple", "iphone13 pro max");
    		tCameraPhone.showInfo();
    		tCameraPhone.turnOn();
    		tCameraPhone.turnOff();
    		tCameraPhone.cameraOn();
    		tCameraPhone.cameraOff();
    		System.out.println();
    		
    		Phone[] phones = new Phone[10];
    		phones[0] = new SmartPhone(202108, "삼성", "갤럭시 Z 폴드3");
    		phones[1] = new TripleCameraPhone(202108, "삼성", "갤럭시 Z 플립3");
    		
    		phones[0].turnOff();
    		phones[0].showInfo();
    		System.out.println();
    		
    		phones[1].turnOff();
    		phones[1].showInfo();  
    	}
    }



    5. 인터페이스(interface)의 개념
        1) 일종의 추상 클래스이긴 하나 멤버의 주류가 추상 메서드임
        2) 객체사용 설명서임
        3) 인터페이스의 멤버
            - 추상 메서드 -- 인터페이스의 본질
            - 상수(static final) -- 부수적 개념
            - static 메서드
            - default 메서드
            - private 메서드
        4) 생성자가 없음 => 인스턴스를 생성할 수 없음
        5) 클래스 작성에 도움을 줌
        6) 표준을 제시하여 그 규칙에 맞게 구현하도록 함

    6. 인터페이스 작성
        1) class 대신 interface를 사용함
            public interface A {
                int a = 10;             // static final 속성 생략됨
                void method();          // abstract 속성 생략됨
            }
        2) 상수는 static final 속성을 지니고 있으며 추상 메서드는 abstract 속성을 지님 (컴파일러가 알아서 추가해주기 때문에 생략 가능)
        3) 인터페이스도 클래스와 동일하게 상속이 가능함 (다중상속 가능)
        4) 다형성 개념이 적용됨
        5) 클래스 상속은 extends를 사용하는데 인터페이스는 implements를 사용함
        6) 구현 클래스는 반드시 인터페이스에 선언되어 있는 추상 메서드를 재정의 해야 함

    // 인터페이스의 본질은 추상 메서드임
    public interface Creature {
    	public void method();		// abstract 키워드 생략 컴파일 시에 컴파일러가 붙여줌
    	int MAX = 10;				// static final 생략 컴파일 시에 컴파일러가 붙여줌
    }
    
    
    
    
    
    public class Member implements Creature{
    
    	@Override
    	public void method() {
    		System.out.println("인터페이스 Creature의 추상메서드인 method() 구현 호출함");
    	}
    
    	public void method1() {
    		System.out.println("Member 클래스의 method1() 호출함");
    	}
    }
    
    
    
    
    
    public class CreatureTest {
    
    	public static void main(String[] args) {
    		
    		Member member = new Member();
    		member.method();
    		member.method1();
    		System.out.println();
    		
    		// 인터페이스도 일종의 조상임 
    		// 그래서 다형성 개념이 적용됨
    		Creature creature = new Member();
    		creature.method();
    		// creature.method1(); 원래 타입을 벗어나지 못하므로 Member 클래스의 method1은 호출 불가능
    		
    		System.out.println(Creature.MAX);	// 상수 접근 시 인터페이스명.상수명 으로 접근
    	}
    }

    public interface RemoteControl {
    
    	// 상수(static final)
    	int MAX_VOLUME = 10;
    	int MIN_VOLUME = 0;
    	
    	// 추상 메서드 3개 선언 (abstract)
    	public void turnOn();
    	public void turnOff();
    	public void setVolume(int volume);
    }
    
    
    
    
    public class Audio implements RemoteControl {
    	
    	private int volume2;
    
    	@Override
    	public void turnOn() {
    		System.out.println("Audio를 켭니다.");
    		
    	}
    
    	@Override
    	public void turnOff() {
    		System.out.println("Audio를 끕니다.");
    		
    	}
    
    	@Override
    	public void setVolume(int volume) {
    		
    		if(volume > RemoteControl.MAX_VOLUME) {
    			System.out.println("Audio 볼륨 최대치 값은 10입니다.");
    			this.volume2 = RemoteControl.MAX_VOLUME;
    		}
    		else if(volume < RemoteControl.MIN_VOLUME) {
    			System.out.println("Audio 볼륨 최소치 값은 0입니다.");
    			this.volume2 = RemoteControl.MIN_VOLUME;
    		}
    		else {
    			this.volume2 = volume;
    		}
    		
    		System.out.println("현재 Audio 볼륨 " + this.volume2);
    		
    	}
    
    }
    
    
    
    
    
    
    public class Television implements RemoteControl{
    	
    	private int volume2;
    
    	@Override
    	public void turnOn() {
    		System.out.println("TV를 켭니다.");
    		
    	}
    
    	@Override
    	public void turnOff() {
    		System.out.println("TV를 끕니다.");
    		
    	}
    
    	@Override
    	public void setVolume(int volume) {
    		if(volume > RemoteControl.MAX_VOLUME) {
    			System.out.println("TV 볼륨 최대치 값은 10입니다.");
    			this.volume2 = MAX_VOLUME;
    		}
    		else if(volume < RemoteControl.MIN_VOLUME) {
    			System.out.println("TV 볼륨 최소치 값은 0입니다.");
    			this.volume2 = MIN_VOLUME;
    		}
    		else {
    			this.volume2 = volume;
    		}
    		
    		System.out.println("현재 TV 볼륨 " + this.volume2);
    	}
    
    }
    
    
    
    
    
    
    public class RemoteTest {
    
    	public static void main(String[] args) {
    		// 인터페이스도 일종의 조상이므로 필드의 다형성이 허용됨
    		RemoteControl rControl = new Television();
    		rControl.turnOn();
    		rControl.setVolume(15);
    		rControl.setVolume(-100);
    		rControl.turnOff();
    		
    		System.out.println();
    		
    		rControl = new Audio();
    		rControl.turnOn();
    		rControl.setVolume(15);
    		rControl.setVolume(-50);
    		rControl.turnOff();
    	}
    }

    7. 인터페이스의 여러가지 요소
        1) 상수
        2) 추상 메서드
        3) 디폴트 메서드 (java 8 이후)
            - 구현을 가지는 메서드
            - default 키워드 사용
            - 구현하는 클래스에서 재정의 할 수 있음
        4) 정적 메서드 (java 8 이후)
            - 인스턴스 생성과 상관없이 인스턴스 타입으로 사용할 수 있는 메서드
        5) private 메서드 (java 9 이후)
            - 인터페이스를 구현한 클래스에서 사용하거나 재정의 할 수 있음
            - 인터페이스 내부에서만 사용하기 위해 구현하는 메서드
            - default 메서드나 static 메서드에서 사용함

    /*
     * 인터페이스의 모든 메서드가 추상 메서드로 선언됨 : public abstract
     * 			모든 변수는 상수로 선언됨 : public static final 
     */
    public interface Calc {
    
    	double PI = 3.14;
    	int ERROR = -999999;
    	
    	int add(int num1, int num2);
    	int substract(int num1, int num2);
    	int times(int num1, int num2);
    	int devide(int num1, int num2);
    	
    	default void description() {
    		System.out.println("계산기를 구현합니다.");
    		myMethod();
    	}
    	
    	static int total(int[] arr) {
    		int total = 0;
    		
    		for(int i : arr) {
    			total += i;
    		}
    		myStaticMethod();
    		return total;
    	}
    	
    	private void myMethod() {
    		System.out.println("private method()");
    	}
    	
    	private static void myStaticMethod() {
    		System.out.println("private static method()");
    	}
    }
    
    
    
    
    
    public abstract class Calculator implements Calc {
    
    	@Override
    	public int add(int num1, int num2) {
    		return num1 + num2;
    	}
    
    	@Override
    	public int substract(int num1, int num2) {
    		return num1 - num2;
    	}
    }
    
    
    
    
    
    public class CompleteCalculator extends Calculator {
    
    	@Override
    	public int times(int num1, int num2) {
    		return num1 * num2;
    	}
    
    	@Override
    	public int devide(int num1, int num2) {
    		if(num2 == 0)
    			return ERROR;
    		else
    			return num1 / num2;
    	}
    	
    //	@Override
    //	public void description() {
    //		System.out.println("재정의한 description");
    //	}
    
    }
    
    
    
    
    
    public class CalcTest {
    
    	public static void main(String[] args) {
    		
    		Calc calc = new CompleteCalculator();
    		int n1 = 10;
    		int n2 = 2;
    		
    		System.out.println(calc.add(n1, n2));
    		System.out.println(calc.substract(n1, n2));
    		System.out.println(calc.times(n1, n2));
    		System.out.println(calc.devide(n1, n2));
    
    		calc.description();
    		
    		int[] arr = {1,2,3,4,5};
    		int sum = Calc.total(arr);
    		System.out.println("sum : " + sum);
    	}
    }

    8. 여러 인터페이스 구현하기, 인터페이스의 상속하기
        1) 여러 인터페이스 구현
            - 자바의 인터페이스는 구현 코드가 없으므로 하나의 클래스가 여러 인터페이스를 구현할 수 있음
            - 디폴트 메서드가 중복되는 경우는 구현하는 클래스에서 재정의 해야 함
            - 여러 인터페이스를 구현한 클래스는 인터페이스 타입으로 형변환 되는 경우 해당 인터페이스에 선언된 메서드만 사용가능함

    public interface Buy {
    
    	void buy();
    	
    	default void order() {
    		System.out.println("구매 주문");
    	}
    }
    
    
    
    
    
    public interface Sell {
    
    	void sell();
    	
    	default void order() {
    		System.out.println("판매 주문");
    	}
    }
    
    
    
    
    
    /*
     * 디폴트 메서드가 중복되는 경우
     * 	- 구현하는 클래스에서 반드시 재정의를 해야 함
     */
    
    public class Customer implements Buy, Sell{
    
    	@Override
    	public void sell() {
    		System.out.println("customer sell()");
    	}
    
    	@Override
    	public void buy() {
    		System.out.println("customer buy()");
    	}
    
    	@Override
    	public void order() {
    		System.out.println("customer order()");
    	}
    	
    	public void sayHi() {
    		System.out.println("customer sayHi()");
    	}
    }
    
    
    
    
    
    public class CustomerTest {
    
    	public static void main(String[] args) {
    		
    		Customer customer = new Customer();
    		customer.buy();
    		customer.sell();
    		customer.order();
    		customer.sayHi();
    		System.out.println();
    	
    		Buy buyer = customer;		// 인터페이스 참조변수 = 구현객체 (UpCasting, 자동 형변환)
    		buyer.buy();
    		buyer.order();
    		System.out.println();
    		
    		Sell seller = customer;
    		seller.sell();
    		seller.order();
    	}
    }


        2) 인터페이스의 상속
            - 인터페이스 사이에도 상속을 사용할 수 있음
            - extends 키워드를 이용
            - 인터페이스는 다중 상속이 가능하고, 구현 코드의 상속이 아니므로 타입 상속이라고 함

    public interface X {
    
    	void x();
    	
    }
    
    
    
    
    public interface Y {
    
    	void y();
    	
    }
    
    
    
    
    public interface MyInterface extends X,Y {
    	
    	void myMethod();
    
    }
    
    
    
    
    public class MyClass implements MyInterface {
    
    	@Override
    	public void x() {
    		
    	}
    
    	@Override
    	public void y() {
    		
    	}
    
    	@Override
    	public void myMethod() {
    		
    	}
    }

        3) 클래스 상속과 인터페이스 구현 함께 사용
            - 프레임워크나 라이브러리 사용하는 경우에는 클래스 상속과 인터페이스 구현을 같이 사용하는 경우가 많음

    import java.util.ArrayList;
    
    public class Shelf {
    
    	protected ArrayList<String> shelf;
    	
    	public Shelf() {
    		shelf = new ArrayList<>();
    	}
    
    	public ArrayList<String> getShelf() {
    		return shelf;
    	}
    	
    	public int getCount() {
    		return shelf.size();
    	}
    }
    
    
    
    
    
    public interface Queue {
    
    	void enQueue(String title);
    	String deQueue();
    }
    
    
    
    
    public class BookShelf extends Shelf implements Queue {
    
    	@Override
    	public void enQueue(String title) {
    		shelf.add(title);
    	}
    
    	@Override
    	public String deQueue() {
    		return shelf.remove(0);
    	}	
    }
    
    
    
    
    public class BookShelfTest {
    
    	public static void main(String[] args) {
    		
    		Queue bookQueue = new BookShelf();
    		bookQueue.enQueue("자바");
    		bookQueue.enQueue("HTML5");
    		bookQueue.enQueue("SQL");
    		
    		System.out.println(bookQueue.deQueue());
    		System.out.println(bookQueue.deQueue());
    		System.out.println(bookQueue.deQueue());
    	}
    }

     

    '개발자 수업 > Java' 카테고리의 다른 글

    16. Object 클래스  (0) 2021.10.13
    과제2 - CarTest  (0) 2021.10.13
    14. 다형성  (0) 2021.10.11
    13. Review  (0) 2021.10.11
    12. 상속과 오버라이딩  (0) 2021.10.08

    댓글