220609_인터넷 강의_다운 캐스팅, 추상 클래스

창고·2022년 10월 20일
0

티스토리에 저장했던 글을 옮겼습니다.
https://mrcocoball.tistory.com/81

1. 다운 캐스팅 (Down Casting) 과 instanceof

(1) 다운 캐스팅

  • 업 캐스팅된 클래스를 다시 원래 타입으로 형 변환
  • 이유 : 업 캐스팅된 하위 클래스의 객체는 상위 클래스에 포함된 메소드만 사용할 수 있기 때문에
    하위 클래스만의 멤버를 사용하기 위해선 다운 캐스팅이 필요
Customer customer = new VIPCustomer(); // 묵시적, 업 캐스팅 진행
VIPCustomer vipCustomer = (VIPCustomer) customer; // 명시적, 다운 캐스팅 진행
  • 다운 캐스팅은 업 캐스팅된 클래스에만 적용이 가능하므로 처음부터 상위 클래스로 생성된 객체에는 적용 안됨
Customer customer = new Customer(); // 처음부터 상위 클래스로 생성
VIPCustomer vipCustomer = (VIPCustomer) customer; // 다운 캐스팅 불가

(2) instanceof를 이용, 인스턴스의 형 체크

  • 어느 객체가 어느 클래스의 인스턴스인지 확인
좌변객체 instanceof 우변타입

boolean result = customer instanceof VIPCustomer
// customer 객체가 VIPCustomer 클래스의 인스턴스인지, 즉 업 캐스팅이 진행이 되었는지
  • 좌변 객체가 우변 타입의 인스턴스일 경우 true, 아니면 false를 반환
  • 예제 코드
public class IdolTest {
	

	public static void main(String[] args) {
		
		Idol rIdol = new Rico(); // 형변환
		Idol mIdol = new Mari(); // 형변환
		Idol yIdol = new Yoshiko(); // 형변환
				
		ArrayList<Idol> idolList = new ArrayList<>();
		idolList.add(rIdol);
		idolList.add(mIdol);
		idolList.add(yIdol);
		
		IdolTest test = new IdolTest();
		
		for(Idol idol : idolList) {
			idol.call();
		}
		
		test.testDownCasting(idolList);
		
		
	}
	
	
	public void testDownCasting(ArrayList<Idol> list) {
		
		for (int i = 0; i<list.size(); i++) {
			
			Idol idol = list.get(i);
			
			if (idol instanceof Rico) {
				
				Rico rIdol = (Rico) idol;
				rIdol.raser();
			}			
			else if (idol instanceof Yoshiko) {
				
				Yoshiko yIdol = (Yoshiko) idol;
				yIdol.fallen();
			}			
			else if (idol instanceof Mari) {
				
				Mari mIdol = (Mari) idol;
				mIdol.money();
			}
			else {
				System.out.println("error");
			}
		}
		
	}
	
}

2. 추상 클래스 (abstract class) 구현하기

(1) 추상 클래스란?

  • 구현 코드 없이 메소드의 선언만 있는 추상 메소드(abstract method) 를 포함한 클래스
  • 메소드 선언 : 반환 타입, 메소드 이름, 매개변수로 구성
  • 추상 클래스는 new 할 수 없음 (인스턴스화 할 수 없음)
  • 선언과 정의의 차이
int add(int x, int y); // 선언
int add(int x, int y){} // 정의, 구현부가 있으므로 추상 메소드가 아니며 정의

(2) 추상 클래스 구현

  • 메소드에 구현 코드가 없으면 abstract로 선언 (추상 메소드)
  • abstract로 선언된 메소드를 가진 클래스는 abstract로 선언 (추상 클래스)
  • 모든 메소드가 구현된 클래스라도 abstract로 선언되면 추상 클래스로 인스턴스화(new로 생성) 할 수 없음
  • 추상 클래스의 추상 메소드는 하위 클래스가 상속하여 구현
  • 추상 클래스 내의 추상 메소드 : 하위 클래스가 구현해야 하는 메소드
  • 추상 클래스 내의 구현된 메소드 : 하위 클래스가 공통으로 사용하는 메소드 (필요에 따라 하위 클래스에서 재정의)
  • [추상 클래스] : SchoolIdol
    • 자기소개하다 introduce()
    • 구호를 외치다 call()
    • 춤추다 dancing()
    • 노래하다 singing()
public abstract class SchoolIdol {   
	
	// constructor 생략 (기본 생성자)

	// method

	abstract void introduce(); // 추상 메소드
	abstract void call(); // 추상 메소드
	abstract void dancing(); // 추상 메소드
	abstract void singing(); // 추상 메소드

}
  • [실체 클래스 1] → [추상 클래스] : Aqours
    • 자기소개하다 introduce()
    • 구호를 외치다 call()
    • 춤추다 dancing()
    • 노래하다 singing()
public class Aqours extends SchoolIdol {
	
	   // constructor 생략 (기본 생성자)

	   // method

	   @Override
	   public void introduce() {
	      System.out.println("안녕하세요 저희는 Aqours 입니다!");
	   }

	   @Override
	   public void call() {
	      System.out.println("0부터 1에 아쿠아 선샤인!");
	   }

	   @Override
	   public void dancing() {
	      System.out.println("Aqours가 춤을 춥니다.");
	   }

	   @Override
	   public void singing() {
	      System.out.println("Aqours가 노래합니다.");
	   }      	

}
  • [실체 클래스 2] → [실체 클래스 1] : Idol
    • 자기소개하다 introduce()
    • 구호를 외치다 call()
    • 콜리스를 하다 callRes()
    • 춤추다 dancing()
    • 노래하다 singing()
public class Idol extends Aqours {
	
	   // constructor 생략 (기본 생성자)

	   // method

	   @Override
	   public void introduce() {
	      System.out.println("안녕하세요 아이돌입니다");
	   }

	   @Override
	   public void call() {
	      System.out.println("열심히 할게요!");
	   }

	   @Override
	   public void dancing() {
	      System.out.println("아이돌이 춤을 춥니다.");
	   }

	   @Override
	   public void singing() {
	      System.out.println("아이돌이 노래를 합니다.");
	   }

	   public void callRes() { // 업캐스팅 진행 시 사용 불가능하므로 다운캐스팅 필요
	      System.out.println("아이돌이 콜 앤 리스폰스를 합니다.");
	   }

}
  • 실행
public class IdolTest {

	public static void main(String[] args) {
		// Aqours 클래스의 메소드 사용
		System.out.println("====Aqours의 자기소개, 구호, 춤추기, 노래하기====");
		SchoolIdol schoolIdol = new Aqours(); // 업캐스팅, Aqours > SchoolIdol
		schoolIdol.introduce();
		schoolIdol.call();
		schoolIdol.dancing();
		schoolIdol.singing();

		// Idol 클래스의 메소드 사용
		System.out.println("====아이돌의 자기소개, 구호, 춤추기, 노래하기====");
		Aqours aqours = new Idol(); // 업캐스팅, Idol > Aqours
		aqours.introduce();
		aqours.call();
		aqours.dancing();
		aqours.singing();

		// Idol 클래스에만 있는 메소드 사용
		boolean result = aqours instanceof Idol; // instanceof 결과값

		// 인스턴스 형태 확인
		if (result) {
		   Idol idol = (Idol) aqours; // 업캐스팅이 된 상태라면 다운캐스팅 진행
		   idol.callRes(); // Idol 클래스에만 있고 상위 클래스에는 없는 callRes() 메소드 실행
		}

	}

}

3. 추상 클래스의 응용 - 템플릿 메소드 패턴

(1) 템플릿 메소드

  • 추상 메소드나 구현된 실체 메소드를 활용, 코드의 흐름(시나리오)를 정의하는 메소드
  • final로 선언하여 하위 클래스에서 재정의 할 수 없게 함
  • 프레임워크에서 많이 사용되는 패턴
  • 추상 클래스로 선언된 상위 클래스에서 템플릿 메소드를 활용, 전체적인 흐름을 정의하고
    하위 클래스에서 다르게 구현되어야 하는 부분은 추상 메소드로 선언, 하위 클래스에서 구현하도록 함

(2) 템플릿 메소드 예제

  • [추상 클래스] Car
    • startCar()
    • drive()
    • stop()
    • turnOff()
    • run()
public abstract class Car {
	
	   public abstract void drive(); // 추상 메소드
	   public abstract void stop(); // 추상 메소드

	   public void startCar() {
	      System.out.println("시동을 켭니다.");
	   }

	   public void turnOff() {
	      System.out.println("시동을 끕니다.");
	   }


	   // 템플릿 메소드
	   final public void run() {
	      startCar();
	      drive();
	      stop();
	      turnOff();
	   }
}
  • [실체 클래스 1] → [추상 클래스] Alcar
public class AICar extends Car {

	   @Override // 추상 메소드 재정의
	   public void drive() {
	      System.out.println("자율 주행합니다.");
	      System.out.println("자동차가 스스로 방향을 바꿉니다.");
	   }

	   @Override // 추상 메소드 재정의
	    public void stop() {
	      System.out.println("스스로 멈춥니다.");
	   }
	   
}
  • [실체 클래스 2] → [추상 클래스] ManualCar
public class ManualCar extends Car {
	
	   @Override // 추상 메소드 재정의
	   public void drive() {
	      System.out.println("사람이 운전합니다.");
	      System.out.println("사람이 핸들을 조작합니다.");
	   }

	   @Override // 추상 메소드 재정의
	    public void stop() {
	      System.out.println("브레이크를 밟아 정지합니다.");
	   }

}
  • 실행
public class CarTest {

	public static void main(String[] args) {
		
		Car aiCar = new AICar(); // 업캐스팅 진행 AICar > Car
		aiCar.run(); // 템플릿 메소드 실행

		System.out.println("===============");

		Car manualCar = new ManualCar(); // 업캐스팅 진행 ManualCar > Car
		manualCar.run(); // 템플릿 메소드 실행

	}

}

(3) final 예약어

  • final 변수 : 값이 변경될 수 없는 상수로 만듬
public static fianl double PI = 3.14;
  • final 메소드 : 하위 클래스에서 재정의 할 수 없는 메소드
  • final 클래스 : 상속할 수 없는 클래스

(4) 여러 자바 파일에서 사용하는 상수 값 정의

  • 예제
public class Define {
	
	   public static final int MIN = 1;
	   public static final int MAX = 999999;
	   public static final double PI = 3.14;
	   public static final String GREETING = "안녕하십니까 니꼴라스 입니다";
	   public static final int AQOURS_CODE = 1001;
	   public static final int LIELLA_CODE = 1002;

}
public class DefineTest {

	public static void main(String[] args) {
		
		   System.out.println("인사말 : " + Define.GREETING);
		   System.out.println("최소값 : " + Define.MIN);
		   System.out.println("최대값 : " + Define.MAX);
		   System.out.println("Aqours의 코드 : " + Define.AQOURS_CODE );
		   System.out.println("Liella의 코드 : " + Define.LIELLA_CODE);
		   System.out.println("원주율 : " + Define.PI);

	}

}

profile
공부했던 내용들을 모아둔 창고입니다.

0개의 댓글