[CODE-STATES-BE] SEC-1[JAVA] 다형성과 추상화 ( 인터페이스 만 )

유형찬·2022년 9월 5일
0

Code States

목록 보기
5/21

다형성

자바에서 다형성이 뭘까?

사전에서 다형성이란 다음과 같이 정의 되어 있다.

  • 나의 객체가 여러 가지 형태를 가질 수 있는 성질

자바에서 다형성은 변수를 통해서 여러 객체를 참조 할 수 있도록 한 것을 말한다.

  • 이는 자바에서 확장성을 극도로 올려주는 기능이다.
  • 필요 할 때 마다 각각의 객체에 맞는 메소드를 만들 필요가 없다.
  • 이전 포스팅의 Hashcode 함수를 보면 이 또한 다형성이 적용 된 것을 알 수 있다.

처음에 잘 이해가 안 갈 수 있다. 열심히 공부 해보자!

참조변수의 타입 변환

이 내용은 책이나 유튜브, 구글 검색 등을 통해서 많이 알 내용이니 간단하게 넘어가자.

  1. 상속 관계만 타입 변환 가능
  2. 하위 → 상위 ( upcasting ) 형변환 연산자 생략 가능 : 묵시적 형변환
  3. 상위 → 하위 ( downcasting ) 시 형변환 연산자 반드시 명시 : 명시적 형변환

1, 2번이야 그렇다고 쳐도 3번은 왜 명시해야 하는지 이유를 생각해 봤다.

예시로 보자

ChildClass child1 = new ChildClass();
ChildChildClass ccClass = new ChildChildClass(); // child class 의 child 
ParentClass parent = child1;		// 암묵적 형변환
ChildClass child2 = (ChildClass)parent;	// 명시적 형변환
ChildClass child3 = ccClass; // 암묵적 형변환

다음과 같이 Child Class 에서 또 자식 객체를 만들었을 경우를 보자

  • ChildChildClass → ChildClass 묵시적 형변환
  • ChildClass → ParentClass 묵시적 형변환

위와 같이 일어나게 되는데

아래와 같을 경우 자손이 부모로 바뀌는지 부모가 자손으로 바뀌는지 확실하게 알 수 없을 뿐더러

( 뇌피셜 ) 자식은 추가 확장 내용 ( Instance 변수 ) 를 버리면 부모가 될 수 있지만

부모는 추가 데이터를 받아오지 않으면 쓰레기 값이 들어오기 때문에 명시적으로 바꿔야 한다고 생각 된다.

  • ChildClass child2 = parent;
  • ChildClass child3 = ccClass;

결론

아마 명확하게 업 캐스팅과 다운 캐스팅을 구분 짓기 위해서 나눈 목적이 아닐 까 생각 된다.

**instanceof 연산자**

캐스팅이 가능한 지 여부를 boolean 타입으로 확인하는 연산자

reference_value_name instanceof 'className'

이전 포스팅에서는 equals 함수 Override 를 할 때 .getClass() 함수를 사용 했었는데

실무에서는 instanceof 연산자를 상당히 많이 쓴다. 확장성에 상당히 열려 있고

getClass 는 그 클래스에 해당하는 값만 가져오기에 상속 하여 캐스팅이 가능 하더라도

equals 내부에서 사용 할 경우 상속 받는 친구들은 사용이 불가능 하다. ㅜ.ㅜ

추상화

추상 클래스

추상 클래스도 있지만 사실 실무에서 아주 많이 사용 하는 건 인터페이스고 추상 클래스 사용 빈도도 상당히 적고 어려운 내용이 아니기에 간단하게 집고 넘어 가도록 하겠다.

  • 기초적인 밑그림
  • naming : abstract class Name
  • Method : abstract Type MethodName()
  • 추상 메서드를 하나 이상 포함한다는 점 외에는 기본적으로 일반 클래스와 동일
    • 따라서 상속 받는 친구들은 하나의 상속 만 받을 수 있다.

인터페이스

인터페이스의 기본 구조

  • class키워드 대신 interface키워드를 사용
접근제어자 interface 인터페이스이름 {

    public static final 타입 상수이름 =;
		final int 변수 = 2; // public static 생략
    static int 변수2 = 3; // public & final 생략
    ...

    public abstract 메소드이름(매개변수목록);
		void 메소드이름2() //public abstract 생략
    ...

}
  • 상수를 정의하는 경우에는 반드시 public static final로 선언
  • public abstract로 메소드 정의
  • BUT 일부 , 전부 생략 가능

인터페이스의 제약 조건

  • 해당 인터페이스에 정의된 모든 추상메서드를 구현 해야함
  • 즉 , 선언된 모든 함수를 Override 해야 함 , 따라서 협업 시 사전 필요 기능을 만들어 놓고 실제 로직이 완성 전에도 각각의 개발자들이 인터페이스를 통해서 개발 할 수 있음 , 매우 큰 장점

인터페이스의 다중 implement

  • 위에서도 말했듯 class 는 하나의 클래스만 상속이 가능
  • 그러나 인터페이스는 무제한으로 여러 인터페이스를 상속 가능

그렇다면 Why 사용하느냐 ?

  • 의존성을 최소화 할 수 있음
    • 이게 무슨 말이냐 코드 변경 사항이 났을 때 상당히 쉽게 바꿀 수 있음
    • Spring FrameWork Project를 예로 들어 설명 하자면 Native Query를 사용 하고 있는데 갑자기 Database를 갈아 치울 때가 생길 수 있다. Mysql → Oracle
      • 이런 경우에 인터페이스를 사용하지 않는다면 이런 Query Class ( 이제 Repo Class 라고 하겠다) 를 의존하는 모든 클래스에 객체를 모두 바꿔 주어야 한다. 변경 가능성에 상당히 닫혀있는 상태라고 할 수 있다.

      • 어디서 사용하는지도 잘 모르겠고 바꾸기도 귀찮은데 Repo Class 내부 함수 쿼리나 바꿔야지 할 수 있다. 이런 경우 상당히 확장 가능성에 닫혀있는 상태라고 할 수 있다. 만약 데이터 베이스를 옮겼는데 또 다시 이런 일이 생긴다면 ? 또 전체 코드를 갈아 엎어야 하는 상태가 올 수 있다.

      • 이를 인터페이스를 통해 간단하게 해결이 가능하다. 모든 의존하는 클래스들을 인터페이스 타입으로 받게 하여 인터페이스를 상속 받는 Impl class 로 만들게 되면 DI 를 하는 class 만 바꿔주면 된다.

        @Bean
        public InterfaceDI DI(InterfaceDI interfaceDI){
        	this.InterfaceDI = interfaceDI;
        }
        
        //extenal
        void main(){
        	DI(**new InterfaceDIImpl()**);
        // 위 부분만 바꿔주면 됨
        }
  • 선언과 구현을 분리시켜 개발시간을 단축
  • 이 말은 독립적인 프로그래밍을 통해 한 클래스의 변경이 다른 클래스에 미치는 영향을 최소화
profile
rocoli에요

0개의 댓글