객체의 형변환과 배열

haribo·2021년 2월 27일
0

Java

목록 보기
6/17

Why?

좀전에 말했던 게임 개발을 한다고 가정해보자. 육군,공군,해군 캐릭터들이 일시에 공격하는 기능을 구현중인데, 서로 객체가 다르기 때문에 호출을 육군.공격, 공군.공격, 해군.공격 이렇게 다 따로따로 호출을 해야한다. 근데 이러다 또 공격 순서가 바뀔땐 메서드 호출순서를 모든 경우의 수에 따라 if문으로 마련해야할거같다.

똑똑한 프로그래머들은 노가다를 싫어한다. 하나하나 다 입력하는거, 어디서 많이 본거같은데. 데이터 값이 너무 많을때 우리가 쓰던게 있었던거 같은데. 아, 배열. 그리고 배열은 왜 쓴다? 반복문을 잘 돌리기 위해 쓰는거다. 그걸 이제 객체로 해보자는게 요지다.

이 부분을 잘해야 버그를 안만든다. 열심히 배우자.

객체 형변환

  • 자바 기본 유형의 데이터들처럼 객체 참조변수의 경우에도 형변환(casting)이 이루어진다. (여기서 잠깐, 형변환은 암묵적, 명시적으로 분류된다. 데이터형이 작은것에서 큰 것으로 가는 경우엔 암묵적, 큰것에서 작은것으로 가는 경우엔 명시적이라고 한다.)
  • 서로 다른 클래스 유형으로부터 나온 객체 참조변수들 간의 대입에는 일정한 규칙이 있다.
Parent parent = new Child();
  • 위의 대입 연산에서 왼쪽 항과 오른쪽 항의 객체 유형이 서로 다른 경우 두 유형이 서로 상속관계에 있고 왼쪽 객체가 오른쪽 객체의 상위 클래스인 경우에만 암묵적인 형변환이 일어난다.
  • 하위 클래스에서 상위 클래스 유형으로 할당하는 것은 가능하나 그 반대의 경우에는 명시적 형변환을 해야한다. (할당되는 객체의 유형에 따라서 실행 오류가 발생할 수 있다.)

<암묵적 형변환과 메서드 오버라이드>

  • 암묵적 형변환은 부모를 상속받는 자식객체의 기능을 부모에게 물려받은 기능만 사용하도록 제한한다. 부모 클래스의 메서드만 사용가능하다는 의미.
  • 그러므로 암묵적 형변환이 발생하게 되면 오버라이드된 기능만 사용가능하고, 추가적으로 구현한 기능은 사용할 수 없다.
  • 주의할 점은 기능의 제한이지 기능의 변경은 아니라는 것이다. 오버라이드된 기능의 값이 출력된다.
  • 정리 : 객체를 부모형태로 변환하면 클래스의 종류를 구분하지 않고 일관된 기능을 호출할 수 있고, 객체가 상위클래스 형태로 형변환되더라도 오버라이드 된 자신의 기능은 잃지 않는다는 것을 알게되었다. 다만 추가적으로 구현한 기능(확장)을 사용하고 싶을떈 어떻게 해야할지 고민이 된다.

<명시적 객체 형변환>

  • 부모 클래스의 객체를 자식 클래스 형태로 변환하는 것이다.
  • 형변환을 위해서는 다음과 같이 변환할 클래스 이름을 명시적으로 지정해 주어야 한다.
ChildClass child = (ChildClass) parent;
  • 객체가 최초 생성될 떄 자식클래스 형태로 생성되고,
  • 부모 형태로 암묵적 형변환이 된 상태를
  • 다시 원래의 자식클래스 형태로 되돌릴 경우에만 가능하다.
  • 최초 객체 생성이 부모형태로 만들어진 경우 불가하고, 최초 생성된 것과 다른 형식으로 육군→공군 변환하는 것은 불가능하다.

<실습 01> - 객체의 형변환을 해봅시다.

public class Unit {
	private String name;
	
	// 생성자 정의
	public Unit(String name) {
		super();
		this.name = name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return this.name;
	}
	
	// 재정의할 메서드
	public void attack() {
		System.out.println(this.name + " >> 공격준비");
	}
}
public class Army extends Unit {
	public Army(String name) {
		super(name);
	}
	
	@Override
	public void attack() {
		super.attack();
		System.out.println(super.getName() + " >> 지상공격 실행함");
	}
	
	public void tank() {
		System.out.println(super.getName() + " >> 탱크공격");
	}
}
public class Navy extends Unit {
	public Navy(String name) {
		super(name);
	}
	
	@Override
	public void attack() {
		super.attack();
		System.out.println(this.getName() + " >> 어뢰 발사!!");
		System.out.println(this.getName() + " >> 지상 상륙");
	}
	
	public void nucleus() {
		System.out.println(this.getName() + " >> 핵미사일");
	}
}
public class AirForce extends Unit {
	public AirForce(String name) {
		super(name);
	}
	
	@Override
	public void attack() {
		super.attack();
		System.out.println(this.getName() + " >> 이륙");
		System.out.println(this.getName() + " >> 공중공격 실행함");
	}
	
	public void bombing() {
		System.out.println(this.getName() + " >> 폭격");
	}
}
public class Main01 {
	public static void main(String[] args) {
		// 각각의 객체를 생성하고 고유의 기능 호출하기
		// Unit 클래스를 상속받은 후, 각각의 클래스에 추가적으로 구현한
		// 확장 기능을 사용한다.
		
		AirForce af = new AirForce("공군");
		Navy nv = new Navy("해군");
		Army am = new Army("육군");
		
		// 각각의 객체는 자신들의 고유 기능을 사용할 수 있음
		af.bombing();
		nv.nucleus();
		am.tank();
		
		System.out.println("----------------");
		
		// 모든 객체는 자신의 상위 형태로 암묵적 형변환 가능
		Unit temp1 = af;
		Unit temp2 = nv;
		Unit temp3 = am;
		
		// 형변환이 되더라도 상속받거나 재정의한(Override)
		// 자신들의 기본 특성들은 그대로 유지함
		temp1.attack();
		temp2.attack();
		temp3.attack();
		
		System.out.println("----------------");
		
		// 상위 클래스 형태로 형변환이 되면, 자신들의 독립 기능은 사용하지 못함
		// temp1.bombing();
		// temp2.nucleus();
		// temp3.tank();
		
		// 다시 원래의 기능을 되돌리기 위해서는
		// 하위 클래스 형태로 명시적 형변환이 필요함
		AirForce re1 = (AirForce) temp1;
		Navy re2 = (Navy) temp2;
		Army re3 = (Army) temp3;
		
		re1.bombing();
		re2.nucleus();
		re3.tank();

	}
}

객체 배열

Why?

스타크래프트를 하다보면 드래그를 하면 여러 캐릭터를 한번에 선택할 수있고, 일괄적으로 공격하게 할 수 있다. 또한 고유 스킬들도 사용하게 할 수있다. 객체로는 그렇게 안될까? 혼재된 데이터를 한번에 묶을 수 있는 방법을 우린 이미 배웠다. '배열'이다.

정의

  • 일반 데이터 타입의 배열과 동일한 개념으로, 같은 클래스의 객체 여러개를 그룹화 할 수 있다. 자료형의 위치에 클래스 이름을 써주면 된다.
  • 일반 데이터형은 단순히 값을 대입하지만, 객체 배열은 new를 사용하여 객체를 할당해야한다.
  • 배열의 생성이 부모 클래스로 지정되었을 경우, 모든 자식클래스의 객체들은 그 배열에 포함될 수있다. 이 경우 암묵적으로 형변환이 이루어진다.

활용

  • 배열을 만드는 이유는 반복문을 만드는 것이고, 반복문을 만드는 것은 일괄처리가 가능하다는 말이다.
  • 배열의 각 요소를 통해 사용하는 메서드가 오버라이드 되어있을 경우 부모의 메서드가 아니라 자신이 재정의한 기능을 뜻한다.

instanceof 연산자

  • 원기능으로 복귀하는 방법은 명시적 형변환을 통해서 해야하는데, 몇번째 요소가 어떤 클래스에서 최초로 생성되었는지 판단하기 어렵다.
  • 이 경우 instanceof 연산자를 사용하여 어떤 객체에 대한 출처를 판단하여 boolean형으로 결과를 반환할 수 있다.
public class Main02 {
	public static void main(String[] args) {
		/* 부모 클래스에 객체 배열을 생성하고, 
		 * 배열의 요소에 자식 클래스 객체를 할당하면,
		 * 자동으로 암묵적 형변환이 이루어져
		 * 순서나 종류에 상관없이 배열에 저장할 수 있다.
		 */
		
		// 부대 지정
		Unit[] units = new Unit[5];
		
		units[0] = new AirForce("공군1호");
		units[1] = new AirForce("공군2호");
		units[2] = new Navy("해군1호");
		units[3] = new Army("육군1호");
		units[4] = new Army("육군2호");
		
		// 부대 일괄 공격
		for (int i = 0; i < units.length; i++) {
			units[i].attack();
			
			if (units[i] instanceof Army) {
				Army a = (Army) units[i];
				a.tank();
			} else if (units[i] instanceof Navy) {
				Navy n = (Navy) units[i];
				n.nucleus();
			} else {
				AirForce f = (AirForce) units[i];
				f.bombing();
			}
		}
	}
}
이 포스트는 itpaper.co.kr에서 제공되는 강의자료를 바탕으로 작성되었습니다.
profile
그림 그리는 백엔드 개발자

0개의 댓글