다형성이란 "여러 개"를 의미하는 poly와 어떤 ‘형태' 또는 ‘실체’를 의미하는 morphism의 결합어로 하나의 객체가 여러 가지 형태를가질 수 있는 성질을 의미
자바에서 다형성이란?
인스턴스 생성시 상위 타입의 클래스를 타입으로 지정한 경우(참조변수의 타입과 객체 타입이 불일치 하는 경우)
= 상위 클래스를 참조변수의 타입으로 지정했기 때문에 자연스럽게 참조변수가 사용할 수 있는 멤버의 개수는 상위 클래스의 멤버의 수가 된다.
=‘상위 클래스 타입의 참조변수로 하위 클래스의 객체를 참조하는 것’
참조변수의 타입 변환 : 사용할 수 있는 멤버의 개수 조절
참조변수의 타입변환은 서로 상속 관계에 있는 관계에서는 양방향으로 수행될 수 있으나, 상위 클래스로의 타입 변환이냐(괄호 생략 가능) 아니면 하위 클래스로의 타입 변환이냐(괄호 생략 불가)에 따라서 약간의 차이가 있다.
(EX)
car > vehicle (상위 클래스로 변환. 생략 가능)
vehicle > car (하위 클래스로 변환, 생략 불가능)
car > motorBike(상속관계가 아니다. 타입 변환 불가능)
참조변수의 타입 변환, 즉 캐스팅이 가능한 지 여부를 boolean
타입으로 확인할 수 있는 자바의 문법요소.
참조_변수 instanceof 타입
true
가 나오면 참조 변수가 검사한 타입으로 타입 변환이 가능하며, 반대로 false
가 나오는 경우에는 타입 변환이 불가능null
인 경우에는 false
를 반환instanceof
연산자는 형변환 여부를 확인하여 에러를 최소화하는 매우 유용한 수단이 될 수 있다.매번 새로운 타입을 매개변수로 전달해주는 메서드를 추가해야하는 경우 다형성을 통해 해결할 수 있다. > 상위 클래스의 타입을 매개변수로 전달해준다.
abstract
제어자가 내포하고 있는 의미를 이해하고, 어떻게 사용되는 지 설명할 수 있다.final
키워드를 이해하고 설명할 수 있다.추상이란?
자바에서 추상화란?
abstract
는 주로 클래스와 메서드를 형용하는 키워드로 사용되는데, 메서드 앞에 붙은 경우를 ‘추상 메서드(abstract method)’, 클래스 앞에 붙은 경우를 ‘추상 클래스(abstract class)’라 각각 부른다.
abstract class AbstractExample { // 추상 메서드가 최소 하나 이상 포함돼있는 추상 클래스
abstract void start(); // 메서드 바디가 없는 추상메서드
}
마완성 클래스를 만드는 이유?
final
키워드는 필드, 지역 변수, 클래스 앞에 위치할 수 있으며 그 위치에 따라 그 의미가 조금씩 달라지게 된다.
위치 | 의미 |
---|---|
클래스 | 변경 또는 확장 불가능한 클래스, 상속 불가 |
메서드 | 오버라이딩 불가 |
변수 | 값 변경이 불가한 상수 |
final class FinalEx { // 확장/상속 불가능한 클래스
final int x = 1; // 변경되지 않는 상수
final int getNum() { // 오버라이딩 불가한 메서드
final int localVar = x; // 상수
return x;
}
}
두 개의 다른 대상을 연결
클래스 작성과 유사하지만 class 대신 interface 키워드를 사용한다.
public static final
로 정의되고, 앞서 간단하게 언급한 static
과 default
메서드 이외의 모든 메서드가 public abstract
로 정의된다.public static final
로, 메서드를 정의하는 경우에는 public abstract
로 정의해야 일부분 또는 전부 생략 가능. >생략된 부분은 컴파일러가 자동으로 추가.추상클래스 처럼 인터페이스도 그 자체로 인스턴스를 생성할 수 없고, 메서드 바디를 정의하는 클래스를 따로 작성해야 한다.
class 클래스명 implements 인터페이스명 {
... // 인터페이스에 정의된 모든 추상메서드 구현
}
= 하나의 클래스가 여러 개의 인터페이스를 구현할 수 있다.
다만 인터페이스는 인터페이스로부터만 상속이 가능하고, 클래스와 달리 Object 클래스와 같은 최고 조상이 존재하지 않는다.
class ExampleClass implements ExampleInterface1, ExampleInterface2, ExampleInterface3 {
... 생략 ...
}
특정 클래스는 다른 클래스로부터의 상속을 받으면서 동시에 인터페이스를 구현할 수 있다.
일반적인 인터페이스의 기능처럼 역할과 구현을 분리시켜 사용자 입장에서는 복잡한 구현의 내용 또는 변경과 상관없이 해당 기능을 사용할 수 있다는 점이다.
인터페이스를 매개변수로 받게 한다.
>코드의 변경을 최소화하여 효율성을 높일 수 있다.
개발자의 입장에서도 선언과 구현을 분리시켜 개발시간을 단축
할 수 있고, 독립적인 프로그래밍을 통해 한 클래스의 변경이 다른 클래스에 미치는 영향을 최소화할 수 있다
public interface Customer {
// 상수
// 추상 메서드
}
public class CafeCustomerA implements Customer {
}
public class CafeCustomerB implements Customer {
}
public interface Customer {
public abstract String getOrder();
}
public class CafeCustomerA implements Customer {
public String getOrder(){
return "a glass of iced americano";
}
}
public class CafeCustomerB implements Customer {
public String getOrder(){
return "a glass of strawberry latte";
}
}
CafeOwner
클래스를 재정의하여 매개변수로 Customer
타입이 입력될 수 있게끔 만들어주면, 매개변수의 다형성에 의해 Customer
public class CafeOwner {
public void giveItem(Customer customer) {
System.out.println("Item : " + customer.getOrder());
}
}
interface Customer {
String getOrder();
}
class CafeCustomerA implements Customer {
public String getOrder(){
return "a glass of iced americano";
}
}
class CafeCustomerB implements Customer {
public String getOrder(){
return "a glass of strawberry latte";
}
}
class CafeOwner {
public void giveItem(Customer customer) {
System.out.println("Item : " + customer.getOrder());
}
}
public class OrderExample {
public static void main(String[] args) throws Exception {
CafeOwner cafeowner = new CafeOwner();
Customer cafeCustomerA = new CafeCustomerA();
Customer cafeCustomerB = new CafeCustomerB();
cafeowner.giveItem(cafeCustomerA);
cafeowner.giveItem(cafeCustomerB);
}
}
// 출력값
Item : a glass of iced americano
Item : a glass of strawberry latte
= 중요한 점은 메서드의 개수가 줄어든 것 보다 CafeOwner 클래스가 더 이상 손님에게 의존적인 클래스가 아닌 독립적인 기능을 수행하는 클래스가 되었다는 점이다.