2021. 04. 06(화) TIL

Dylan·2021년 4월 6일
0

Java

클래스 형변환

  • 기본자료형타입의 변수처럼 참조형변수도 형변환이 가능하다.
    • 기본자료형타입의 형변환은 정밀도가 높은 타입으로, 사이즈가 더 큰 타입으로의 형변환은 자동으로 처리된다.
  • 클래스의 형변환은 서로 상속관계에 있는 객체 사이에서만 형변환이 가능하다.
    • 하위클래스타입 객체를 상위클래스 타입의 참조변수에 저장하는 것이 가능하다. (자동으로 처리된다)
    • 상위클래스타입 객체를 하위클래스 타입의 참조변수에 저장하는 것이 가능하다. (형변환 연산자 필요)
    • 형변환할 때 바로 위 상위타입이나 바로 아래 상위타입이 아니어도 상관없다.

클래스 형변환 예제

  • 상위클래스와 하위클래스를 정의한다.
  • 상위객체와 하위객체를 생성해서 각각 상위객체는 상위클래스 타입의 참조변수, 하위타입객체는 하위클래스 타입의 참조변수에 대입한다.
  • 하위타입객체를 다시 생성해서, 상위클래스 타입의 참조변수에 대입해본다.(클래스 형변환)

상속관계를 가진 클래스 정의하기

  public class Phone {
    String tel;
    void call() { ... }
    void disconnect() { ... }
  }
  
  publc class FeaturePhone extends Phone {
    void mp3() { ... }
  }
  
  public class SmartPhone extends Phone {
    String ip;
    String mailAddress;
    void web() { ... }
    void email() { ... }
  }
  
  public class Iphone extends SmartPhone {
    void faceId() { ... }
  }

클래스 형변환 활용하기

  public static void main(String[] args) {
    // 형변환없이 해당 타입의 변수에 담기
    Phone p1 = new Phone();                 // 성공
    FeaturePhone p2 = new FeaturePhone();   // 성공
    SmartPhone p3 = new SmartPhone();       // 성공
    Iphone p4 = new Iphone();               // 성공
    
    // Phone타입의 변수에 객체 담기
    Phone p11 = new Phone();                // 성공 자식객체를 상위타입 참조변수에 대입
    Phone p12 = new FeaturePhone();         // 성공 자식객체를 상위타입 참조변수에 대입
    Phone p13 = new SmartPhone();           // 성공 자식객체를 상위타입 참조변수에 대입
    Phone p14 = new Ihone();                // 성공 자식객체를 상위타입 참조변수에 대입
    
    // FeaturePhone타입의 변수에 객체 담기
    FeaturePhone p21 = new Phone();         // 오류 상위타입 객체를 대입할 수 없음
    FeaturePhone p22 = new FeaturePhone();  // 성공 참조변수 타입과 동일한 개체 타입이라서 가능 
    FeaturePhone p23 = new SmartPhone();    // 오류 서로 상속관계가 아님
    FeaturePhone p24 = new Iphone();        // 오류 서로 상속관계가 아님
    
    // SmartPhone타입의 변수에 객체 담기
    SmartPhone p31 = new Phone();           // 오류 상위타입 객체를 대입할 수 없음
    SmartPhone p32 = new FeaturePhone();    // 오류 서로 상속관계 아님
    SmartPhone p33 = new SmartPhone();      // 성공 참조변수 타입과 동일한 개체 타입이라서 가능 
    SmartPhone p34 = new Iphone();          // 성공 자식객체를 상위타입 참조변수에 대입
    
    // Iphone타입의 변수에 객체 담기
    Iphone p41 = new Phone();               // 오류
    Iphone p42 = new FeaturePhone();        // 오류
    Iphone p43 = new SmartPhone();          // 오류
    Iphone p44 = new Iphone();              // 성공
  }

package day2;

public class ClassCastingApp {

	public static void main(String[] args) {
		
		Panzer car1 = new Panzer();
		PoliceCar car2 = new Panzer();
		Car car3 = new Panzer();
		
		System.out.println("### Panzer 타입의 참조변수로 Panzer 객체 참조하기");
		// Panzer 객체의 메소드 사용가능
		car1.setWeapon("기관총");
		car1.fireWeapon();
		
		// PoliceCar 객체의 메소드 사용가능 <-- Panzer의 상위 클래스임
		car1.patrol();
		
		// Car 객체의 메소드 사용가능 <-- PoliceCar의 상위 클래스임
		car1.setColor("검정색");
		car1.drive();
		car1.stop();
		
		System.out.println("### PoliceCar 타입의 참조변수로 Panzer 객체 참조하기");
		// Panzer 객체의 메소드 사용가능
		// car2.setWeapon("기관총");	// 오류 - 사용불가
		// car2.fireWeapon();		// 오류 - 사용불가
		
		// PoliceCar 객체의 메소드 사용가능 <-- Panzer의 상위 클래스임
		car2.patrol();
		
		// Car 객체의 메소드 사용가능 <-- PoliceCar의 상위 클래스임
		car2.setColor("파랑색");
		car2.drive();
		car2.stop();
		
		System.out.println("### Car 타입의 참조변수로 Panzer 객체 참조하기"); 
		// Panzer 객체의 메소드 사용가능
		// car3.setWeapon("기관총");	// 오류 - 사용불가
		// car3.fireWeapon();		// 오류 - 사용불가
		
		// PoliceCar 객체의 메소드 사용가능 <-- Panzer의 상위 클래스임
		// car3.patrol();		// 오류 - 사용불가
		
		// Car 객체의 메소드 사용가능 <-- PoliceCar의 상위 클래스임
		car3.setColor("하얀색");
		car3.drive();
		car3.stop();
	}
}

package day2;

public class ClassCastingApp2 {

	public static void main(String[] args) {
		
		Car car1 = new Car();
		Car car2 = new PoliceCar();
		Car car3 = new Panzer();
		
		System.out.println("### Car타입의 참조변수로  Car객체 참조하기");
		car1.drive();	// Car객체의 기능 사용하기
		car1.stop();	// Car객체의 기능 사용하기
		// PoliceCar car12 = (PoliceCar) car1;		// 실행 오류, car1이 참조하는 객체에는 PoliceCar가 없음
		// car12.patrol();
		// String car13 = (String) car1;			// 컴파일 오류, car1이 참조하는 객체와  String은 상속관계가 아님.
		
		System.out.println("### Car타입의 참조변수로  PoliceCar객체 참조하기");
		car2.drive();	// Car객체의 기능 사용하기
		car2.stop();	// Car객체의 기능 사용하기
		
		PoliceCar car22 = (PoliceCar) car2;		// car2로 참조되는 객체에서 PoliceCar 객체로 옮겨가기
		car22.patrol();	// PoliceCar객체의 기능 사용하기
		((PoliceCar) car2).patrol();			// PoliceCar객체로 옮겨서 순찰기능 실행
		
		
		System.out.println("### Car타입의 참조변수로  Panzer객체 참조하기");
		car3.drive();	// Car객체의 기능 사용하기
		car3.stop();	// Car객체의 기능 사용하기
				
		PoliceCar car32 = (PoliceCar) car3;		// car3로 참조되는 객체에서 PoliceCar 객체로 옮겨가기
		car32.patrol();	// PoliceCar객체의 기능 사용하기
		
		Panzer car33 = (Panzer) car3;			// car3로 참조되는 객체에서 Panzer 객체로 옮겨가기
		car33.fireWeapon();	// Panzer객체의 기능 사용하기
	}
}

package day2;

public class ClassCastingApp3 {

	public static void main(String[] args) {
		Car[] carList = new Car[5];
		
		carList[0] = new Car();
		carList[1] = new Panzer();
		carList[2] = new FireTruck();
		carList[3] = new PoliceCar();
		carList[4] = new Panzer();
		
		// instansOf
		// 향샹된 for문을 사용해서 배열에 저장된 다양한 Car객체를 순서대로 조회해서
		// Car객체면 운전기능, 정지기능 실행해보기
		// PoliceCar객체면 운전기능, 정지기능, 순찰기능 실행해보기
		// FireTruck객체면 운전기능 ,정지기능, 화재진압기능 실행해보기
		// Panzer객체면 운전기능, 정지기능, 순찰기능, 무기발사기능 실행해보기
		
		for (Car car : carList) {
			System.out.println("### car참조변수가 참조하는 객체 주요 기능 확인");
			car.drive();
			car.stop();
			
			if (car instanceof FireTruck) {
				FireTruck x = (FireTruck) car;
				x.suppressFire();
			}
			
			if (car instanceof PoliceCar) {
				PoliceCar x = (PoliceCar) car;
				x.patrol();
			}
			
			if (car instanceof Panzer) {
				Panzer x = (Panzer) car;
				x.fireWeapon();
			}
			
			System.out.println();
		}
		
	}
}

다형성

  • 메소드 중복정의
    + 하나의 클래스에 안에 동일한 이름의 메소드를 여러 개 정의하는 것
    + 접근제한자, 반환타입의 상관없다.
    + 메소드이름이 동일하고, 매개변수의 타입, 갯수가 다르기만 하면 된다.
    + 목적
    * 하나의 클래스안에 매개변수만 다르고 수행하는 작업은 비슷한 경우 일관성있고 동일한 메소드 이름으로 실행하게 한다.

  • 메소드 재정의

    • 상속/구현관계에 있는 클래스의 자식 클래스에서 부모로부터 물려받은 메소드를 재정의하는 것이다.
      + 방법
      반환타입, 메소드이름, 매개변수의 갯수와 타입이 모두 일치하고, 구현내용(수행문의 내용)만 재정의하는 것
      접근제한자는 부모측의 접근제한자와 동일하거나 더 느슨하게 정의해야 한다.
      + 내용
      동일한 업무지만 자식클래스들 마다 세부 업무내용이 다른 경우 구체적인 구현을 자식클래스들이 부모의 메소드를 재정의해서 구현하도록 하는 것이다.
      + 목적
      부모의 메소드와 자식의 메소드가 메소드 재정의 관계를 형성하게 되면 부모객체를 참조하고 있어도 자식에 재정의된 메소드를 실행할 수 있게 할 수 있다.
    • 필드의 다형성, 매개변수의 다형성을 획득할 수 있다.
  • 다형성
    + 실행방법은 동일하지만 사용하는 객체가 달라지면
    다른 결과가 발현되는 것
    + 객체지향 프로그래밍의 주요한 특징이다
    + 메소드 재정의, 추상화, 인터페이스 등의 기술을 활용해서 다양하게 활용할 수 있다.

package day2.game;


public class GameApp2 {

	public static void main(String[] args) {
		Unit[] units = new Unit[4];
		
		units[0] = new Marine();
		units[1] = new Firebat();
		units[2] = new Ghost();
		units[3] = new BattleCruiser();
		
		for (Unit unit : units) {
			// - unit 참조변수는 다양한 종류의 Unit류 객체를 참조한다.
			// - unit 참조변수가 참조하는 Unit류 객체는 모두 Unit클래스의 하위클래스고,
			//	 클래스의 목적에 맞게 move()나 attack()을 재정의하고 있다.
			// - unit 참조변수가 참조하는 객체의 종류에 상관없이 unit.move(); unit.attack();를
			//	 실행하면 객체의 목적에 맞게 재정의된 move()나 attack()가 실행된다.
			// - 결론
			//	* Marine, Firebat, Ghost, BattleCruiser객체에 재정의된 move()나 attack()를
			//	  실행하기 위해서 해당 객체 타입으로 형변환이 필요없어진다.
			//	* Unit클래스의 하위 클래스가 나중에 추가되더라도 이동기능, 공격기능을 실행하는 방법은
			//	  변하지 않는다.
			//	* 프로그램의 확장성이 높아진다.
			
			unit.move();
			unit.attack();
			System.out.println();
		}
		
	}
}

0개의 댓글