다형성(polymorphism)
조상 클래스 타입 참조 변수로 자손 타입 객체를 가리키는 것
실제 생성된 인스턴스가 무엇인지가 가장 중요하다.
public class Test {
public static void main(String[] args) {
Tv tv = new SmartTv();
tv.down();
tv.up();
// tv.search(); 사용 못한다. Tv클래스를 보면 search()없기 때문
//실제 생성된 객체는 SmartTv이기에 타입을 변경하면 호출할 수 있다.
((SmartTv)tv).search();
}
}
class Tv{
void up() {}//채널 업
void down() {}//채널 다운
}
class SmartTv extends Tv{
void search() {}//인터넷 검색기능
}
원래 생성된 객체가 SmartTv니까 문제가 없다. 만약 Tv라면 어떻게 될까?
컴파일러는 오류를 못잡는다. 즉, 런타임 예외가 발생하게 된다. (실행 중 예외)
형변완 예외 발생
이 때문에 형변환 시에 무조건 instanceof 연산자로 형변환가능한 경우만 형변환되도록 하는 것이 중요하다.
위까지가 다형성의 사전 지식
public class Test {
public static void main(String[] args) {
Tv tv = new SmartTv();
tv.down();
tv.up();
}
}
class Tv{
void up() {
System.out.println("일반 TV 채널 업");
}//채널 업
void down() {
System.out.println("일반 TV 채널 다운");
}//채널 다운
}
class SmartTv extends Tv{
void up() {
System.out.println("스마트 TV 채널 업");
}//채널 업
void down() {
System.out.println("스마트 TV 채널 다운");
}//채널 다운
void search() {}//인터넷 검색기능
}
///////////////////////////////////////
스마트 TV 채널 다운
스마트 TV 채널 업
실제 동작은 생성된 객체 구현부로 동작되는 것을 알 수 있다. 이를 통한 다형성 사례
public class Test {
public static void main(String[] args) {
SmartTv tv1 = new LGSmartTv();
SmartTv tv2 = new SamsungSmartTv();
tvTest(tv1);
tvTest(tv2);
}
//앞으로 새로운 스마트 TV가 추가되어도 기존 아래 코드는 수정할 일이 없다.
static void tvTest(SmartTv smartTv) {
smartTv.down();
smartTv.up();
smartTv.search();
}
}
class Tv{
void up() {
System.out.println("일반 TV 채널 업");
}//채널 업
void down() {
System.out.println("일반 TV 채널 다운");
}//채널 다운
}
//객체 생성을 막음
abstract class SmartTv extends Tv{
void up() {
System.out.println("스마트 TV 채널 업");
}//채널 업
void down() {
System.out.println("스마트 TV 채널 다운");
}//채널 다운
void search() {
System.out.println("스마트한 검색");
}//인터넷 검색기능
}
class LGSmartTv extends SmartTv{
void up() {
System.out.print("LG");
super.up();
}
void down() {
System.out.print("LG");
super.down();
}
void search() {
System.out.print("LG의 ");
super.search();
}
}
class SamsungSmartTv extends SmartTv{
void up() {
System.out.print("삼성");
super.up();
}
void down() {
System.out.print("삼성");
super.down();
}
void search() {
System.out.print("삼성의 ");
super.search();
}
}
////////////////////////////////
LG스마트 TV 채널 다운
LG스마트 TV 채널 업
LG의 스마트한 검색
삼성스마트 TV 채널 다운
삼성스마트 TV 채널 업
삼성의 스마트한 검색
객체지향 원칙 캡슐화, 추상화, 상속, 다형성을 기반으로 다양한 디자인 패턴들이 존재한다.
인터페이스(interface)
일종의 추상클래스
추상클래스 처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높다
개발 코드가 객체에 종속되지 않게 하여 객체를 교체할 수 있도록 한다. (OCP, 변경엔 닫혀있고, 확장엔 열려있어야한다)
객체 간 느슨한 결합을 위한 핵심
객체지향 원칙에 구현보다는 인터페이스에 맞춰서 프로그래밍한다는 원칙도 있다.
인터페이스 모든 멤버변수는 public static final이다. 그렇기에 생략해도 컴파일러가 일괄적으로 붙여준다.
모든 메서드는 public abstract다.
인터페이스 간 상속도 당연히 된다. expands 키워드, 인터페이스를 클래스가 구현하면 implements
느슨한 결합 예시
public class Test {
public static void main(String[] args) {
LgTv lgTv = new LgTv();
tvTest(lgTv);
}
//지금 구조에서 기존 코드(tvTest)를 절대 건드리지 말고 SamSungTv로 바꿔 동작하게 할 수 있나?
public static void tvTest(LgTv lgTv) {
lgTv.volDown();
lgTv.volUp();
}
}
class LgTv{
void volUp() {}
void volDown() {}
}
class SamSungTv{
void volUp() {}
void volDown() {}
}
절대 불가능하다.
public class Test {
public static void main(String[] args) {
LgTv lgTv = new LgTv();
SamSungTv samSungTv = new SamSungTv();
//자동 형변환된다.
tvTest(lgTv);
tvTest(samSungTv);
}
//지금 구조에서 기존 코드(tvTest)를 절대 건드리지 말고 SamSungTv로 바꿔 동작하게 할 수 있나?
public static void tvTest(Tv tv) {
tv.volDown();
tv.volUp();
}
}
interface Tv{
void volUp();
/*public abstract*/void volDown();
}
class LgTv implements Tv{
public void volUp() {}
public void volDown() {}
}
class SamSungTv implements Tv{
public void volUp() {}
public void volDown() {}
}
객체지향을 시작으로 다양한 디자인 원칙, 더 나아가 디자인 패턴에서 중요한 핵심은 기존코드를 수정하지 않고 새로운 기능을 손쉽게 추가하는 것이다.
익명 클래스(anonymous class)
이름 없는 클래스, 이유는 선언과 객체 생성을 동시에 하기 때문이다.
일회용으로 쓰거나, 오직 하나의 객체만을 생성한다.
public class Test {
public static void main(String[] args) {
new AnonymousTest();
}
}
class AnonymousTest {
public AnonymousTest() {
System.out.println("객체 선언과 동시에 생성");
}
}
////////////////////
객체 선언과 동시에 생성
public class Test {
public static void main(String[] args) {
Runnable runnable = ()->Test.call("1");
Thread thread = new Thread(runnable);
thread.start();
call("0");
}
static void call(String msg) {
for(int i = 0; i< 10000 ; i++) {
System.out.print(msg);
}
}
}
람다식은 익명 구현 객체이다.
'개발 > 자바(JAVA)' 카테고리의 다른 글
컴포지트 패턴 연습 - 1 (0) | 2023.04.13 |
---|---|
기본형 배열 List로 변환하기 (0) | 2023.03.10 |
객체 지향 - 5 (0) | 2023.02.01 |
객체 지향 - 4 (0) | 2023.01.31 |
객체 지향 - 3 (0) | 2023.01.29 |