다형성

logY·2023년 1월 21일
0

Java

목록 보기
1/4

abstract class (추상 클래스)

정의

추상 메소드(abstract method)란 자식 클래스에서 반드시 오버라이딩해야만 사용할 수 있는 메소드를 의미이다.

자바에서 추상 메소드를 선언하여 사용하는 목적은 추상 메소드가 포함된 클래스를 상속받는 자식 클래스가 반드시 추상 메소드를 구현하도록 하기 위함이다.

사용이유

💡 구현의 강제를 통해 프로그램의 안정성 향상 즉, 강제로 오류를 발생시킴으로 메서드를 재정의하게 한다.
  • 클래스에서 중복이 발생한다. → 상속으로 해결!!
  • 하지만 의미 없는 클래스가 생기게된다. 즉, 자식 클래스를 포괄하지만 사용하지 않는 클래스가 생긴다.

추상 클래스

위의 그림을 보면 Animal 클래스는 동물의 특성을 가지고 있지만 독립적인 클래스로 기능을 수행하지는 않는다.

때문에 Animal의 클래스에는 추상 메서드를 사용해서 무의미한 구현을 줄이고 상속 받은 클래스에서 작성하도록 한다.

abstract class Animal {
	public abstract void eat();
	public abstract void sleep();
}
class Animal {
	public void eat() {
		System.out.println("냠냠");
	}
	public void sleep() {
		System.out.println("쿨쿨");
	}
}

특징

💡 조상 클래스에서 상속받은 abstract 메서드를 재정의 하지 않은 경우

클래스 내부에 abstract 메서드가 있는 상황이므로 자식 클래스는 abstract 클래스로 선언되어야 한다.

클래스에 구현부가 없는 메서드가 있으므로 객체를 생성할 수 없음

하지만 상위 클래스 타입으로써 자식을 참조할 수는 있다.

interface

서로 다른 두 시스템 장치, 소프트웨어 따위를 서로 이어 주는 부분, 또는 그런 접속 장치

자식 클래스가 여러 부모 클래스를 상속받을 수 있다면, 다양한 동작을 수행할 수 있다는 장점을 가지게 될 것

특징

💡 표준이 존재하기 때문에 유지보수 및 협업에 유리하다.

최고 수준의 추상화 단계이며 인터페이스 내의 일반 메서드는 모두 abstract형태를 가지고 있다.

💡 잠깐!!! JDK 8부터는 default method와 static method가 추가되었다!!!!

형태

맴버 변수는 public static final 이며 생략 가능

모든 메서드는 public abstract 이며 생략 가능

인터페이스 상속

  • 클래스와 마찬가지로 인터페이스도 extends를 이용해 상속이 가능
  • 클래스와 다른 점은 인터페이스는 ****다중 상속****이 가능
💡 다중 상속이 가능한 이유?

헷갈릴 메서드 구현 자체 없기 때문에!

클래스에서 인터페이스 구현

  • implements 키워드를 사용해서 인터페이스를 구현한다.
  • 이때 모든 abstract 메서드를 override해서 구현하거나
  • 구현하지 않을 경우 abstract 클래스로 표시해야한다.
💡 다형성은 조상 클래스 뿐 아니라 조상 인터페이스에도 적용!!

인터페이스의 필요성

  • 구현의 강제로 표준화 처리
    • abstract 메서드를 사용→즉, 구현을 강제화!!
  • 손쉬운 모듈 교체

public static void main(String[] args) {
		PrintClient client = new PrintClient();
		client.setPrinter(new LaserPrinter());
		// TODO: client가 LazerPrinter를 사용하도록 하고 클래스의 변화를 확인하시오.
		client.setPrinter(new LaserPrinter());
		// END:
		client.printThis("myfile");
	}

위의 코드 처럼 인터페이스는 모듈처럼 사용가능하기 때문에 손쉬운 교체가 가능하다!

개발에서 인터페이스 사용의 예

개발 중 DBMS를 바꿔야 할때 driver(모듈, 인터페이스의 역할)를 사용해서 손쉽게 교체 가능

즉, 코드의 교체 없이 인터페이스만 바꾸면 된다. → 인터페이스는 약속된 규격이기 때문

인터페이스를 통해 상속 관계가 없는 클래스에 다형성을 부여

이를 통해 자바의 단일 상속의 한계를 극복할 수 있다!!!

하지만 클래스의 상속처럼 강한 결합이 아닌 느슨한 결합!!!

협업에서의 인터페이스

계산기를 구현하는 두 팀의 작업

A 팀 - 클라이언트를 위한 UI

B 팀 - 계산 로직의 구현

default method

  • 인터페이스에 선언 된 구현부가 있는 일반 메서드
    • 메서드 선언부에 default modifier 추가 후 메서드 구현부 작성
      • 접근 제한자는 public으로 한정됨
  • 필요성 💡 default 메서드는 abstract가 아니므로 반드시 구현해야할 필요는 없다!
  • 기존 interface에 라이브러리를 추가해야한다면?

method의 우선순위

super class의 method 우선

interface간의 충돌

Generic😝 🤪

다양한 타입의 객체를 다루는 메서드, 컬렉션 클래스에서 컴파일 시에 타입 체크

미리 사용할 타입을 명시해서 형 변환을 하지 않아도 됨

표현

  • 클래스 또는 인터페이스 선언 시 <>에 타입 파라미터 표시
public class Class_Name<T>{}
public interface Interface_Name<T>{}

Object 타입 (generic이 없을때)

장점 : 여러 데이터 타입을 하나의 박스로 저장할 수 있다.

단점

  • 특정 용도(데이터 타입)로 사용하기 위한 제한이 어렵다.
  • 원하는 타입이 아닌 데이터가 들어가는 것을 체크할 수 없다….ㅠㅠ
  • 꺼내 쓸 때 입력한 데이터 타입으로 형 변환 해서 사용해야 한다. ← 너무 귀찮아ㅠㅠ

Generic 타입

장점

  • 여러 데이터 타입을 하나의 박스로 저장할 수 있다.
  • 특정 용도(데이터 타입)로 사용하기 위한 제한이 가능
  • 원하는 타입이 아닌 데이터가 들어가는 것을 체크할 수 있다. (컴파일 시점에서 확인 가능)
  • 꺼내 쓸 때 입력한 데이터 타입으로 형변환 하지 않고 사용가능
ObjectGeneric
여러 데이터 타입 저장가능가능
데이터 타입 제한불가능가능
데이터 타입 형 변환필요불필요

사용법

💡 컴파일 시점에 원치 않는 형태가 오는 것을 체크 및 방지 가능!!!!

타입 파라미터이름으로 권장되는 것

  • T : type
  • E : element
  • V : Value
  • K : Key
  • N : Nubmer
Box<String> // String으로 타입을 체크
Box<Integer> // Integer으로 타입을 체크

컴파일 시 제너릭이 타입을 체크

String을 기준으로 타입을 체크하기 때문에 Integer타입을 넣으면 오류 발생

(The method setData(String) in the type Box03<String> is not applicable for the arguments (int))

💡 제너릭을 항상 사용할 수 있는 것은 아님… 😭 - static 선언하는 변수에는 사용 불가능… - 배열 선언 시에 사용 불가능….

멀티 파라미터!? 제너릭 타입을 두개(이상)도 줄 수 있다구 😜

package com.ssafy.day05.box;

class Box04<K, V> {
	private K key;
	private V value;

	Box04(K key, V value) {
		this.key = key;
		this.value = value;
	}
}

public class Box04Test {
	public static void main(String[] args) {
		Box04<String, Integer> box = new Box04<String, Integer>("싸피", 1234);
	}
}

그러나…!!! 이건 매번 쓰기 귀찮잖아… 😡

List<Integer> list = new ArrayList<>();
Iterator<Integer> ite = list.iterator();

그래서!!! JDK 1.5부터는 객체 타입이 자동으로 설정된다~ <>안의 내용을 생략할 수 있쥐~ 😜

List<Integer> list = new ArrayList<>();
Iterator ite = list.iterator();

Type parameter의 제한

💡 근데… 제너릭 편하긴 한데 파라미터의 타입을 마음대로 쓴다면 안좋은 거 아닌가…? 🤔
public class NumberBox<T extends Number> {
	@SuppressWarnings("unchecked")
	public void addSomes(T... ts) { // 가변형 변수
		double sum = 0;
		for (T t : ts) {
			sum += t.doubleValue();
		}
		System.out.printf("총 합은: %f%n", sum);
	}

	private T some;

	public T getSome() {
		return some;
	}

	public void setSome(T some) {
		this.some = some;
	}
}

제너릭은 상속을 사용하여 타입을 제한할 수 있다!

💡 타입을 여러개 제한도 할 수 있나…? → 🥕

클래스와 함께 인터페이스 제약 조건을 이용할 경우 &로 연결하여 사용가능하다!

인터페이스로 제한할 경우도 extends 사용!

제너릭 타입 객체를 할당 받을 때 와일드 카드도 이용 가능하다! (이따 정리합시다!!)

와일드 카드

사용

  • 타입 파라미터가 의미있게 사용되는가? → 놉… → 와일드카드 사용 👍

Generic Method ←너무 어렵…

파라미터와 리턴 타입으로 type parameter를 갖는 메서드

[제한자] <타입_파라미터, [...]> 리턴_타입 메서드_이름(파라미터)

여기서 <>는 생략이 가능하다!! 메서드 호출 시점에 P의 타입 결정

💡 `추가학습` 💯

어노테이션과 리플렉션

해석되나요???🤔→혼자서 설명해보기🥰

profile
백엔드 개발자

0개의 댓글