JAVA/이론

[Java] 9. 클래스와 객체 Part.3

katia 2023. 3. 20. 22:04

1. 다형성

(1) 다형성(Polymophism)

  • 여러 형태를 가지는 성질이란 뜻으로, 한 가지 타입이 여러가지 형태의 인스턴스를 가질 수 있다는 의미
  • 같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질
  • 부모 타입 변수에는 모든 자식 인스턴스들이 대입될 수 있음
// 1) 지금까지의 객체 생성 방식
A obj = new A();

/*
2) 부모 클래스 타입의 참조변수로 자식 클래스 타입의 객체를 참조할 때

참조변수 obj 하나로 A타입의 인스턴스를 참조할 수 도, B타입의 인스턴스를 참조할 수도 있음.
*/
A obj = new B();    // 클래스 B가 A를 상속할 때
  • 예시
class A{
    void methodA(){
        System.out.println("methodA");
    }
}

class B extends A{
    void methodB(){
        System.out.println("methodB");
    }
    void methodA(){
        System.out.println("methodA-2");
    }
}

public class Test{
    public static void main(String[] args){
        A obj = new B();
        obj.methodA();

        B obj2 = new B();
        obj2.methodA();
    }
}

(2) 참조변수와 인스턴스 간의 관계

  • 부모 클래스 타입의 참조변수로 자식 인스턴스 참조는 가능, 그 반대는 에러
/*
    <선제 조건>
    Parent 클래스의 메소드는 A,B,C
    Child 클래스는 Parent 클래스를 상속 받고 메소드 D를 추가
*/
// Child 클래스가 부모의 멤버 A,B,C를 상속 
// D 라는 참조 변수를 호출할 수 없음! 
Child i = new Parent();        // 부모의 객체 생성
// Child 클래스 내부에 D라는 멤버를 선언
Parents p = new Child();     // 자식의 객체 생성 

(3) 부모, 자식간의 타입 변환

  • 자동 타입 변환(Promotion): 프로그램 실행 자동으로 타입 변환이 일어나는 것
  • 부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근 가능
  • 예외로, 메소드가 자식 클래스에서 오버라이딩 되었다면 자식 클래스의 메소드가 대신 호출됨
class Animal{

}

class Cat extends Animal{

}

Cat cat = new Cat();
Aniaml animal = cat;
// cat == animal -> true
  • 강제 타입 변환(Casting) : 프로그래머가 강제로 타입 변환을 시키는 것
  • 업캐스팅(Upcasting) : 더 높은 객체로 변환시키는 것(자식에서 부모로)
  • 다운 캐스팅(Dwoncasting) : 더 낮은 객체로 변환시키는 거(부모에서 자식으로)
  • 다운 캐스팅이 가능할 때는, 객체가 자식에서 부모로 업 캐스팅 되어있을 경우만 가능(되돌림만 가능)
  • 따라서, 해당 객체가 다운 캐스팅이 가능한 지 instanceof로 확인 후 캐스팅 시도
  • instanceof : 객체의 타입을 확인하는 명령어
자식 클래스 변수 = (자식 클래스) 부모 클래스 타입;    // 다운 캐스팅
부모 클래스 타입 = 자식 클래스 타입;     // 업 캐스팅
객체 instanceof 타입 // 객체가 해당 타입인지 boolean으로 반환

Parent parent = new Parent();
Child child = (Child) parent; // 불가능!!!!

boolean result = child instanceof Parent; // true

2. 추상 메소드와 추상 클래스

(1) 추상 클래스

  • 추상은 실체 간에 공통되는 특성을 추출한 것을 의미
  • 클래스들의 공통적인 특성을 추출해서 선언한 클래스
  • 추상 메소드를 멤버로 가지는 클래스
  • 추상 메소드를 하나라도 포함하는 클래스를 의미
  • 추상 클래스를 상속받은 자식 클래스는 반드시 추상 메소드를 구현해야 함
  • 추상 메소드와 같이 abstract를 붙여 선언
abstract class 클래스명{
    abstract void 추상 메소드명();
    .....
}

(2) 추상 메소드

  • 선언부만 정의하고 구체적인 내용은 비워 놓은 메소드
  • 추상 메소드를 하위 클래스에서 상속받아 구현
  • '추상적인'의 뜻인 'abstract'를 메소드 앞에 붙여 사용
abstract 반환값 메소드명();

(3) 추상 클래스의 사용

  • 실체 클래스들의 공통된 필드와 메소드의 이름을 통일하기 쉬움
  • 실체 클래스를 작성할 시 시간을 절약할 수 있음
  • 추상 클래스를 상속받은 클래스에게 문법적인 제한을 붐으로서 추상 메소드를 자신의 클래스에 맞게 구현하라는 강제성을 줌
abstract class Cellphone{
    abstract void methodA();
}

class MyPhone extends Cellphone{
    void methodA() {

    }
}
  • 예제
// 추상 클래스 정의
abstract class Pokemon{
    String name;

    abstract void attack();
    abstract void sound();

    public String getName() {
        return this.name;
    }
}

// 추상 클래스를 상속받는 Pikachu클래스
class Pikachu extends Pokemon{
    Pikachu(){
        this.name = "피카츄";
    }
       @Override
    void attack(){
        System.out.println("100만 볼트");
    }
    @Override
    void sound(){
        System.out.println(피카 피카!");
    }
}

3. 인터페이스

(1) 인터페이스(Interface)

  • inter(사이의) + face(마주하다)의 합성어로, 물체들 사이에서 상호작용을 하기 위한 매개 역할을 하는 것을 의미
  • 인터페이스를 바탕으로 클래스를 작성(클래스 : 붕어빵 기계, 인터페이스 : 붕어빵을 만드는 재료나 제적법을 적어놓은 종이)
  • 인터페이스를 사용하면 객체의 내부 구조를 알 필요가 없고 인터페이스의 메소드를 구현하기만 하면 된다는 장점이 있음
  • 변수에는 public static final이 메소드에는 public abstact를 작성하지 않아도 컴파일러가 자동으로 추가
  • '상속'이 아닌 '구현'이라도 표현
  • 자식 클래스는 implements를 사용하여 인터페이스를 구현함

(2) 인터페이스의 구현과 상속

  • 인터페이스를 구현하는 자식 클래스는 상속과 구현이 동시에 가능함
  • 인터페이스 간에도 상속이 가능 => 다수의 인터페이스 구현 가능 => 다중 상속이 가능
interface 인터페이스명{
    public static final 자료형 = 값;
    public abstract 반환타입 메소드명(매개변수);
    default 타입 메소드명(매개변수 ...);
    static 타입 메소드명(매개변수 ...)
}
  • 예제
interface A {
    int a = 4;
    void methodA();
    void methodB();
}

// A를 구현하는 클래스 B
class B implements A{
    public void method A(){
        // methodA 구현
    }
    public void methodB(){
        // methodB 구현
    }
}

// C를 상속 받는 동시에 A를 구현하는 클래스 B
class B extend C implements A{
    /*
        interface A의 멤버가 존재
        부모 클래스 C의 멤버가 존재
    */
}
  • 두개의 인터페이스를 상속받아 사용하는 예제
interface A{
    void methodA();
}
interfaceB{
    void methodB();
}
interface C extends A, B{
    // A와 B를 합친 종합 적인 기능을 다루는 인터페이스
}

(3) 인터페이스와 다형성

  • 특정 인터페이스를 구현한 인스턴스는 해당 인터페이스 타입의 참조변수로 참조가 가능
  • 하나의 객체를 여러가지 타입으로 참조 가능
인터페이스명 참조변수명 =new 클래스명();
  • 예시
interface Camera{
    void photo();
}
interface Call{
    void calling();
}
interface Clock{
    void clock();
}

class MyCellPhone implements Camera, Call, Memo, Clock{
    @Override
    public void clock() {}
    @Override
    public void write() {}
    @Override
    public void calling() {}
    @Override
    public void photo() {}
}

class PhoneUser{
    void call(Call c) {
        System.out.println("전화를 걸었습니다.");
    }
}

public class Test{
    public static void main(String[] args){
        // MyCellPhone 클래스가 Camera, Call, Memo, Clock 4개의 인터페이스를 구현
        MyCellPhone phone1 = new MyCellPhone();
        // MyCellPhone의 인스턴스는 자신 이외에 추가로 4개의 인터페이스 타입을 참조
        Camera phone2 = new MyCellPhone();
        Call phone3 = new MyCellPhone();
        Memo phone4 = new MyCellPhone();
        Clock phone5 = new MyCellPhone();

        PhoneUser user1 = new PhoneUser();
        user1.call(phone3);
        user1.call(phone1);
    }
}

4. 정리

(1) 추상 클래스를 사용하는 경우

  • 관련된 클래스 사이에서 코드를 공유하고 싶을 때
  • 공통적인 필드나 메소드가 많은 경우, 또는 public 이외의 접근 지정자를 사용해야 하는 경우
  • 정적이 아닌 필드나 상수가 아닌 필드를 선언하기를 원할 때
  • 일반적인 필드도 선언할 수 있으며, 일반적인 메소드도 정의 가능

(2) 인터페이스를 사용하는 경우

  • 관련 없는 클래스들이 인터페이스를 구현하기를 원할 때
  • 특정한 자료형의 동작을 지정하고 싶지만 누가 구현하든지 신경 쓸 필요가 없을 때
  • 다중 상속이 필요할 때
  • 모든 메소드가 public, abstract가 되며, 여러 개의 인터페이스를 상속 받아 동시에 구현이 가능

'JAVA > 이론' 카테고리의 다른 글

[Java] 11. 패키지  (0) 2023.03.29
[Java] 10. 예외 처리  (0) 2023.03.27
[Java] 8. 클래스와 객체 Part.2  (0) 2023.03.15
[Java] 7. 클래스와 객체 Part.1  (0) 2023.03.15
[Java] 6. 배열  (0) 2023.03.14