14일차 09/07 2022

SangYu Lee·2022년 9월 7일
0

codestates backend

목록 보기
15/30

keyword - 다형성, 추상화

1. 다형성

  자바에서는 하나의 객체를 여러가지의 참조변수 타입으로 선언하고 참조할 수 있는 것을 다형성이라고 한다. 하위클래스를 상위클래스 타입의 참조변수로 선언할 수 있는 것이다. 궁극적인 목적은 편의성을 위해서인데, 상위클래스라는 리모컨으로 하위클래스들을 묶어서 편하게 조정하기 위해서라고 생각하면 된다.
 어떤 블로그에서 본 비유인데, 짱구, 훈이, 철수, 유리, 맹구가 운동장에서 놀고있을 때, 각각 한 명씩 부르면서 집으로 들어가라고 하는 것보다, 떡잎유치원 어린이들 집으로 들어가~ 라고 하면 더 편한 것이다.

메서드 오버로드와 오버라이딩도 맥락상 다형성을 추구하는 것이다. 타입 변환이라는 것도 다형성을 추구한다고 볼 수 있다.

타입 변환

Upcasting

저번 글의 메서드 오버라이딩에서 본 것처럼 하위클래스의 객체를 상위클래스 타입으로 선언하는게 가능한데 이것을 upcasting이라고 한다. 당연하게도 상속 관계에 있기 때문에 가능하며 묵시적으로 형 변환이 이루어진다.

Person syu = (Person) (new Korean("Brown")); //(Person) 생략가능

업캐스팅이 가능한 이유가 뭘까?
우리가 어떤 변수의 타입을 선언할 때는, 그 타입이 요구하는 조건을 모두 할당시켜줘야한다.

int num = (int)true;

위 표현이 오류가 나는 이유도 true라는 boolean형 데이터는 int형 데이터의 변수에 맞춰서 들어갈 수 없기 때문이다. Car, Motorcycle, Truck 클래스는 모두 Vehicle을 상속받았기 때문에 Vehicle의 멤버를 모두 가지고 있다. 그렇기 때문에 상위클래스인 Vehicle로 선언을 할 수 있는 것이다.

★ 중요한점은 stack에 Vehicle 형으로 참조변수가 들어있기 때문에 Vehicle을 벗어나는 범위에는 접근하지 못한다는 것이다. 예를들어 car라는 변수가 horn()이라는 메서드를 만들었다고 하면, 객체는 horn()이라는 메서드의 주소를 담고 있지만, Vehicle 형 변수인 car를 가지고는 horn()에 접근할 수 없다.
참고 : https://ddulgi.tistory.com/41

class Person{
	String name;
	Person(String name){
		this.name = name;
	}
}
class Student extends Person{
	String check;
	Student(String name){
		super(name);
	}
}
public class Practices {
	public static void main(String[] args) {
		Student stu = new Student("홍길동");
		Person per = stu;
		per.name = "이름입니다";
		
		per.check = "이름입니다."; //컴파일 타임 에러가 난다.
		}
}

Downcasting

상속관계에서 하위클래스의 참조변수로 상위클래스의 객체를 참조하는 것인데, 전제조건이 먼저 업캐스팅이 발생했다는 것이다. 멤버 변수가 더 많은 하위클래스의 객체를 멤버변수가 더 적은 상위 클래스의 참조변수로 참조하는 것이기 때문에 오류가 발생하기도 하며, 가능할 경우에는 명시적으로 형 변환을 해주어야 한다.

Korean syu = (Korean) (new Person("Brown")); //(Korean) 생략불가

정리하면

  1. 서로 상속관계에 있는 상위 클래스 - 하위 클래스 사이에만 타입 변환이 가능하다
  2. 업캐스팅은 형변환 연산자(괄호)를 생략할 수 있다.
  3. 다운캐스팅은 형변환 연산자(괄호)를 반드시 명시해야 한다.

Instanceof

타입 변환이 가능한지를 확인하여 boolean타입으로 리턴해주는 메서드이다.

참조_변수 instanceof 타입

if(syu instanceof Person) {
	Person syu = (Person)syu;
}

참조변수가 null인 경우에는 false를 반환한다.


2. 추상화

기존 하위클래스에서 공통점을 모아 상위클래스로 만들거나, 상위클래스에서 공통적인 속성과 기능을 정의하고 하위클래스에서 구현하는 것. 상위클래스에서 구현되어있지 않다는 점이 상속과 다르다. 추상화에는 주로 abstract class와 interface가 사용된다.

abstract

말그대로 추상적이다는 뜻이며 기타제어자에 속한다. abstract 제어자는 클래스와 메서드에 붙는데, 클래스에 하나 이상의 abstract 메서드가 있다면 구현되어있는 메서드를 포함할지라도 무조건 abstract 클래스이다.

abstract class Person{
	public abstract void resist();
}

class Korean extends Person{
	public void resist() {
    	System.out.println("나는 자기 싫다");
    }
}

abstract 클래스를 상속받은 클래스들은 abstract 메서드를 오버라이딩으로 모두 구현해야한다. 이렇게 각각의 클래스의 상황에 맞게 메서드를 구현하는 것은 유연하고 독립적인 코드 변경이 가능하게 해준다.

final 키워드

final 키워드는 위치에 따라 여러 의미를 가지고 있다.

final 클래스 - 변경 또는 확장 불가능한 클래스. 상속 불가
final 메서드 - 오버라이딩 불가
final 변수 - 값 변경이 불가한 상수

interface

abstract 클래스처럼 추상화를 구현하는 데 사용된다. 그러나 abstract 클래스는 구현되어 있는 메서드가 있을 수도 있지만, interface는 구현되지 않은 추상 메서드와 '상수'(final)만을 멤버로 가져야 한다.

  • abstract 클래스 : abstract 메서드가 존재. 구현된 다른 메서드가 있어도 됨.
  • interface : abstract 메서드만, 상수만 존재해야 함. 내부의 모든 필드가 public static final로 정의되고, static과 default 메서드 이외의 모든 메서드가 public abstract로 정의된다.
public interface InterfaceExample {
    public static final int num =  5; // 인터페이스 인스턴스 변수 정의
    final int eyes = 2; // public static 생략
    static int legs = 3; // public & final 생략

    public abstract String getDescription();
		void describe() //public abstract 생략 
}

 interface의 구현

class 클래스명 implements 인터페이스명 {
		... // 인터페이스에 정의된 모든 추상메서드 구현
}

구현할 인터페이스에 정의된 모든 것을 구현해야 한다. 강제적이기 때문에 무조건 해야한다.

★ 인터페이스는 다중 구현이 가능하다.

class Korean implements Person, Mamals, Creature, Material{};

클래스에서 다중 상속이 안되는 이유는 상위클래스에서 멤버를 미리 구현하는 것이 가능하기 때문에 하위클래스에서 사용할 때 충돌이 발생하기 때문이었다. 그러나 인터페이스에서는 같은 이름의 메서드나 필드가 두 인터페이스에 선언되어 있어도 구현하면 같은 메서드고 같은 멤버가 되는 것이기 때문에 별 상관이 없다.

인터페이스의 장점은 역할과 구현을 분리시켜 사용자 입장에서 복잡한 구현의 내용 또는 변경과 상관없이 해당 기능을 사용할 수 있다는 점이다.

profile
아이스커피

0개의 댓글