본문 바로가기
프로그래밍 언어/Java 프로그래밍

Java Day9 - 객체지향 프로그래밍(다형성, 추상클래스)

by Hyeon_ 2021. 11. 11.

다형성(Polymotphism)

  • 객체의 다형성
  • 하나의 객체가 여러 개의 타입을 가질 수 있는 것을 다형성이라 함
  • 다형성을 나타내는 예제
package Standard_Java;

class Tv{
    boolean power;
    int channel;

    // True or False
    void power(){ power = !power; }
    void channelUp(){ channel++; }
    void channelDown() { channel--; }
}

// 자바는 다중 상속을 지원하지 않음 (여러 개의 클래스를 상속받을 수 없음)
class CaptionTv extends Tv{
    // 자식 클래스에서 새로 추가된 속성
    String text;

    void caption(){ }
}

class Other{

}

// java 파일 하나당 하나의 public 클래스 가질 수 있음
public class PolymorphismTest {
    public static void main(String[] args) {
        // is-a 관계. 즉, 상속 관계에서만 사용 가능
        // CaptrionTv is Tv
        Tv t1 = new Tv();
        Tv t2 = new CaptionTv();

        // 상속되지 않은 Other을 사용하면 오류가 나는 것 확인 가능
        // 참조변수와 객체의 타입이 다르면 안됨
//      Tv t3 = new Other();
        CaptionTv c = new CaptionTv();

        // Tv는 CaptionTv이다는 성립하지 않음
        // 모든 학생은 사람이지만, 모든 사람이 학생일 수는 없다는 의미
//      CaptionTv c2 = new Tv();

        t2.power();
        t2.channelUp();
        // Tv 타입의 참조형 변수는 자식 타입의 속성 까지는 알 수 없음
//      t2.text;
        c.power();
        c.channelDown();
        c.text = "Unknown";

        // Tv 타입만을 원소로 가질 수 있음
        Tv[] arrT = new Tv[10];
    }
}

추상 클래스

  • 추상 메서드를 포함하는 클래스를 추상 클래스라 함
    • 추상 메서드란?
      • 메서드의 내부가 정의되지 않은 메서드
      • 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것
  • 완성되지 않은 클래스
    • 인스터너스화 할 수 없음
    • 객체로 생성될 수 없다는 것을 의미
    • 반드시 상속으로 추상 메서드를 메서드 재정의(오버라이딩)를 통해 메서드 내부를 정의해야만 인스턴스화 할 수 있음
package Standard_Java;

abstract class Abstract{
    // 선언만 되어있고, 내부의 기능이 정의되지 않은 메서드
    abstract void abstractMethod();

    // 정의된 메서드가 있어도 무관함
    void generalMethod() {
        System.out.println("일반 메서드");
    }
}

public class AbstractTest {
    public static void main(String[] args) {

        Abstract obj = new Abstract(); // 인스턴스화 할 수 없다는 오류 발생

    }
}
  • 추상 클래스 수정 후
    • 상속이 계속 이어지더라도, 언젠가는 구현이 되어야 한다.
package Standard_Java;

abstract class Abstract{
    // 선언만 되어있고, 내부의 기능이 정의되지 않은 메서드
    abstract void abstractMethod();

    // 정의된 메서드가 있어도 무관함
    void generalMethod() {
        System.out.println("일반 메서드");
    }
}

class General extends Abstract{

    // 메서드 재정의(오버라이드) 통해서 완성
    void abstractMethod() {
        System.out.println("이제는 완성");
    }
}

public class AbstractTest {
    public static void main(String[] args) {

        Abstract obj = new General(); // 인스턴스화 할 수 없다는 오류 발생

    }
}
package Standard_Java;

abstract class Abstract{
    // 선언만 되어있고, 내부의 기능이 정의되지 않은 메서드
    abstract void abstractMethod();

    // 정의된 메서드가 있어도 무관함
    void generalMethod() {
        System.out.println("일반 메서드");
    }
}

abstract class General extends Abstract{

}

// 언젠가는 구현되어야 함
class Final extends General{
    // 메서드 재정의(오버라이드) 통해서 완성
    void abstractMethod() {
        System.out.println("이제는 완성");
    }
}

public class AbstractTest {
    public static void main(String[] args) {

        Abstract obj = new Final(); // 인스턴스화 할 수 없다는 오류 발생

    }
}

인터페이스

  • 추상 클래스의 종류
  • 추상 메서드만을 가지는 추상 클래스를 인터페이스라고 함
  • 인터페이스 작성의 형태
    • 모든 멤버변수는 public static final 이어야 하며, 생략 가능하다
    • 모든 메서드는 public abstract 이어야 하고, 생략 가능하다
      • 단, static 메서드와 default 메서드는 예외
interface 인터페이스 이름{
    public static final 타입 상쉬름 = 값;
    public abstract 메서드이름(매개변수목록);
}
  • 인터페이스 사용 예제 - 1
package Standard_Java;

interface Interface{
    public abstract void abstractMethod1();
    public abstract void abstractMethod2();
    public abstract void abstractMethod3();
}

// 인터페이스의 상속은 extends가 아닌, implements로 상속이 됨
// 여러 개의 인터페이스 상속 받아서 구현
// 자바는 다중 상속 허용하지 않지만, 하나의 클래스(일반, 추상) 여러개의 인터페이스는 가능
class Sample implements Interface{
    public void abstractMethod3() {};
    public void abstractMethod1() {};
    public void abstractMethod2() {};
}

public class InterfaceTest {
    public static void main(String[] args) {
        Sample s = new Sample();
    }
}

실습

  • 메서드 오버로딩을 통한 다형성 예제 - 2 (동물원)
package Standard_Java;

/*
1. 동물원 클래스 가정
2. 호랑이가 들어오면 닭을 먹이로 주고
3. 원숭이가 들어오면 바나나를 먹이로 주고 ..
 */

// 동물 클래스 정의
class Animal{
    String name;

    public void setName(String name){
        this.name = name;
    }
}

// 호랑이 클래스(동물 클래스 상속)
class Tiger extends Animal{

}
// 원숭이 클래스(동물 클래스 상속)
class Monkey extends Animal{

}

// 동물원 클래스 정의
class Zoo{
    // 메서드 오버로딩
    // 호랑이가 들어오면 닭, 원숭이가 들어오면 바나나
    public void food(Tiger tiger) {
        System.out.println("닭");
    }

    public void food(Monkey monkey){
        System.out.println("바나나");
    }
}

public class ZooProject {
    public static void main(String[] args) {
        Zoo zoo = new Zoo();
        Tiger tiger = new Tiger();
        Monkey monkey = new Monkey();

        zoo.food(tiger);
        zoo.food(monkey);
    }
}
  • 동물이 계속 추가된다면??
    • 인터페이스를 도입해보자
package Standard_Java;

/*
1. 동물원 클래스 가정
2. 호랑이가 들어오면 닭을 먹이로 주고
3. 원숭이가 들어오면 바나나를 먹이로 주고 ..
 */

// 동물 클래스 정의
class Animal{
    String name;

    public void setName(String name){
        this.name = name;
    }
}

// 동물이 계속 추가된다면??
interface Ground{

}

interface Birds {
    // 날지 못하는 새 처리 위함
    public String getAction();
}

// 호랑이 클래스(동물 클래스 상속)
class Tiger extends Animal implements Ground{

}
// 원숭이 클래스(동물 클래스 상속)
class Monkey extends Animal implements Ground{

}

class Lion extends Animal implements Ground{

}

class Eagle extends Animal implements Birds{
    @Override
    public String getAction() {
        return "Fly";
    }
}

class Duck extends Animal implements Birds{
    @Override
    public String getAction() {
        return "Fly";
    }
}

class Penguin extends Animal implements Birds{
    @Override
    public String getAction() {
        return "Walk";
    }
}

// 동물원 클래스 정의
class Zoo{

    public void action(Ground ground){
        System.out.println("Walk");
    }

    public void action(Birds bird){
        System.out.println(bird.getAction());
    }

    public void food(Animal animal){
        // 동물에 따라 먹이 다르게 표현
        if(animal instanceof Tiger) System.out.println("닭");
        else if(animal instanceof Monkey) System.out.println("바나나");
        else if(animal instanceof Lion) System.out.println("소고기");
        else if(animal instanceof Eagle) System.out.println("다람쥐");
    }
}

public class ZooProject {
    public static void main(String[] args) {
        Zoo zoo = new Zoo();
        Tiger tiger = new Tiger();
        Monkey monkey = new Monkey();
        Lion lion = new Lion();
        Eagle eagle = new Eagle();
        Duck duck = new Duck();
        Penguin penguin = new Penguin();

        zoo.action(tiger);
        zoo.action(monkey);
        zoo.action(lion);
        zoo.action(eagle);
        zoo.action(duck);
        zoo.action(penguin);

        zoo.food(tiger);
        zoo.food(monkey);
    }
}
  • 먹이 인터페이스를 넣어 코드를 단편화해보자
package Standard_Java;

/*
1. 동물원 클래스 가정
2. 호랑이가 들어오면 닭을 먹이로 주고
3. 원숭이가 들어오면 바나나를 먹이로 주고 ..
 */

// 동물 클래스 정의
class Animal{
    String name;

    public void setName(String name){
        this.name = name;
    }
}

// 동물이 계속 추가된다면??
interface Ground{

}

interface Birds {
    // 날지 못하는 새 처리 위함
    public String getAction();
}

interface Foodable{
    public void food();
}

// 호랑이 클래스(동물 클래스 상속)
class Tiger extends Animal implements Ground, Foodable{
    public void food() {
        System.out.println("닭");
    }
}
// 원숭이 클래스(동물 클래스 상속)
class Monkey extends Animal implements Ground, Foodable{
    public void food() {
        System.out.println("바나나");
    }
}

class Lion extends Animal implements Ground, Foodable{
    public void food() {
        System.out.println("소고기");
    }
}

class Eagle extends Animal implements Birds, Foodable{
    @Override
    public String getAction() {
        return "Fly";
    }
    public void food() {
        System.out.println("다람쥐");
    }
}

class Duck extends Animal implements Birds, Foodable{
    @Override
    public String getAction() {
        return "Fly";
    }
    public void food() {
        System.out.println("사료");
    }
}

class Penguin extends Animal implements Birds{
    @Override
    public String getAction() {
        return "Walk";
    }
    public void food(){
        System.out.println("물고기");
    }
}

// 동물원 클래스 정의
class Zoo{

    public void action(Ground ground){
        System.out.println("Walk");
    }

    public void action(Birds bird){
        System.out.println(bird.getAction());
    }

    public void food(Foodable animal){
        animal.food();
    }
}

public class ZooProject {
    public static void main(String[] args) {
        Zoo zoo = new Zoo();
        Tiger tiger = new Tiger();
        Monkey monkey = new Monkey();
        Lion lion = new Lion();
        Eagle eagle = new Eagle();
        Duck duck = new Duck();
        Penguin penguin = new Penguin();

        zoo.action(tiger);
        zoo.action(monkey);
        zoo.action(lion);
        zoo.action(eagle);
        zoo.action(duck);
        zoo.action(penguin);

        zoo.food(tiger);
        zoo.food(monkey);
    }
}
  • 추상 클래스를 사용해서 표현하기
package Standard_Java;

/*
1. 동물원 클래스 가정
2. 호랑이가 들어오면 닭을 먹이로 주고
3. 원숭이가 들어오면 바나나를 먹이로 주고 ..
 */

// 동물 클래스 정의
class Animal{
    String name;

    public void setName(String name){
        this.name = name;
    }
}

// 동물이 계속 추가된다면??
interface Ground{

}

//interface Birds {
//    // 날지 못하는 새 처리 위함
//    public String getAction();
//}

abstract class Birds extends Animal{
    public abstract String getAction();

    public void getName() {
        System.out.printf("너의 이름은 %s\n", this.name);
    }
}

interface Foodable{
    public void food();
}

interface GroundFoodable extends Ground, Foodable{

}

// 호랑이 클래스(동물 클래스 상속)
class Tiger extends Animal implements GroundFoodable{
    public void food() {
        System.out.println("닭");
    }
}
// 원숭이 클래스(동물 클래스 상속)
class Monkey extends Animal implements GroundFoodable{
    public void food() {
        System.out.println("바나나");
    }
}

class Lion extends Animal implements GroundFoodable{
    public void food() {
        System.out.println("소고기");
    }
}

class Eagle extends Birds implements Foodable{
    Eagle() { this.name = "독수리"; }
    @Override
    public String getAction() {
        return "Fly";
    }
    public void food() {
        System.out.println("다람쥐");
    }
}

class Duck extends Birds implements Foodable{
    Duck() { this.name = "오리"; }
    @Override
    public String getAction() {
        return "Fly";
    }
    public void food() {
        System.out.println("사료");
    }
}

class Penguin extends Birds implements Foodable{
    Penguin() { this.name = "펭귄"; }
    @Override
    public String getAction() {
        return "Walk";
    }
    public void food(){
        System.out.println("물고기");
    }
}

// 동물원 클래스 정의
class Zoo{

    public void action(Ground ground){
        System.out.println("Walk");
    }

    public void action(Birds bird){
        System.out.println(bird.getAction());
        bird.getName();
    }

    public void food(Foodable animal){
        animal.food();
    }
}

public class ZooProject {
    public static void main(String[] args) {
        Zoo zoo = new Zoo();
        Tiger tiger = new Tiger();
        Monkey monkey = new Monkey();
        Lion lion = new Lion();
        Eagle eagle = new Eagle();
        Duck duck = new Duck();
        Penguin penguin = new Penguin();

        zoo.action(tiger);
        zoo.action(monkey);
        zoo.action(lion);
        zoo.action(eagle);
        zoo.action(duck);
        zoo.action(penguin);

        zoo.food(tiger);
        zoo.food(monkey);
    }
}