▶객체 형변환
java 기본유형의 데이터들은 작은 데이터타입(int) 큰 데이터타입(long)으로 이동을 할 경우 형변환이 이루어진다.
이처럼 클래스같은 경우에도 형변환(casting)이 이루어진다.
상속관계이 있는 두 유형은 왼쪽항(부모,Parent)과 오른쪽 항(자식, Child)으로 객체 유형이 서로 다르며 부모 클래스가 자식 클래스를 가르키고 있는 상황이다.
여기서보면 부모클래스(왼쪽 객체)가 자식클래스(오른쪽 객체)의 상위클래스 임을 알 수 있는데 상위클래스가 하위클래스를 생성할 경우엔 암묵적인 형 변환이 일어난다.
암묵적 형변환은 부모를 상속받는 자식객체의 기능을 부모에게 물려받은 기능만 사용하도록 제한하는 것이다. 실제로 생성된 것은 자식 클래스이지만 자식 클래스의 고유한 기능(메서드)는 사용을 하지 못하고 부모에게서 상속받은 기능(오버라이드된기능)만 parent.()로 기능을 불러올 수 있다.
주의할것은 기능의 제한인 것이지 기능의 변경은 아니라는 것이다.
밑의 예시를 보고 좀 더 구체적으로 이해해보자
▶암묵적 형변환의 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class Main01 {
//army
Army am = new Army("육군");
//navy
Navy nv = new Navy("해군");
//AriForce
AirForce af = new AirForce("공군");
//army 고유의 기능
am.tank();
nv.nucleus();
af.bombing();
}
|
cs |
육군과 해군, 공군은 모두 Unit이라는 부모 클래스를 가지고 있으며 각자의 고유의 기능 tank, nucleus,bombing도 가지고있다.
부모클래스가 자식클래스를 가르키지 않을 경우에는 위의 예시처럼 일반적으로 객체를 생성하면 된다.
그런데 부모클래스에는 attck() 공격이라는 공통 메소드가 있는데 이걸 불러내고 싶다면?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package boxing;
public class Main01 {
//army
Army am = new Army("육군");
//navy
Navy nv = new Navy("해군");
//AriForce
AirForce af = new AirForce("공군");
//고유의 기능
/*am.tank();
nv.nucleus();
af.bombing();*/
}
Unit temp1 = am;
Unit temp2 = nv;
Unit temp3 = af;
temp1.attack();
temp2.attck();
temp3.attck();
|
cs |
생성되어있는 am,nv,af라는 객체에 temp1이라는 객체를 또다시 생성해주어 Unit이라는 부모클래스와 연결을 해주고 그 객체를 통해 attck()이란 기능을 불러낸다.
이는 상위객체형태로 암묵적 형변환 한 것으로 고유의 기능이 아닌 재정의 되지 않은 Override된 부모의 기능만 사용 가능하기때문에 여기서 고유의 기능 tank(),nuclenu(),bombing()을 호출하면 오류가 난다.
비록 재정의되어 Override되었다하더라도 암묵적 형변화는 부모의 기능만 사용을 할 수 있기에 원본의 기능을 다시 살려 가지고 온다.
모든 객체는 자신의 상위 형태로 암묵적 형변환이 가능하다고 보면 된다.
왜 굳이 암묵적형변환으로 부모기능을 가지고 오는걸까?
이는 상속관계의 객체를 부모형태로 변환하면, 클래스 종류를 구분하지 않고 일괄된 기능을 호출할 수 있다는 장점이 있기 때문이다.
하지만, 추가적으로 구현한 자식의 기능은 사용할 수 없음으로 원래의 기능으로 다시 사용할 수 있는 방법이 필요해졌다. 이때 필요한 것이 명시적 형변환이다.
▶명시적 형변환
부모 클래스의 객체를 자식 클래스 형태로 변환하는 것
형변환을 위해서는 다음과 같이 변환할 클래스 이름을 명시적으로 지정해주어야한다.
▶명시적 형변환의 조건
객체가 최초로 생성될 때 자식 클래스 형태로 생성되고, 부모 형태로 암묵적 형변환이 된 상태를 다시 원래의 자식 클래스 형태로 되돌릴 경우에만 가능해진다.
[가능한경우]
Army army1 = new Army();
Unit u = army1;
-------------------------------
Army army2 = (Army)u;
-------------------------------
Unit u = new Navy();
Navy navy= (Navy)u;
[불가능한경우]
Unit u = new Unit();
Army army = (Army)u;
최초 객체 생성이 부모 형태로 만들어진 경우 불가능하다.
-------------------------------
Army army = new Army();
Unit u = army;
Navy navy = (Navy)u;
최초 생성된 것과 다른 형식으로 변환하는 것을 불가능하다.
▶명시적 형변환 예시
1
2
3
|
Army re1 = (Army)temp1;
Navy re2 = (Navy)temp2;
AirForce re3 = (AirForce)temp3;
|
cs |
암묵적 형변환의 예시를 이어서 봐보자.
추가적으로 구현한 자식의 기능(메서드)를 사용하기 위해 암묵적 형변환이 된 걸 명시적 형변환으로 다시 되돌린 것으로 저렇게 되면 re1.tank(); re2.nucleus(); re3.bombing();으로 고유의 기능을 다시 호출 할 수 있다.
▶객체배열선언
객체 배열이란 부모클래스라는 배열에 자식클래스를 담는 것을 의미한다.
일반 데이터형의 배열의 경우
int [] data = new int [3];
객체배열의 경우
Unit [] data = new Unit[3];
일반 데이터형은 값을 넘는 배열이 만들어진 것이지만 객체 배열의 경우 Unit은 클래스의 이름으로 Unit 타입이라는 클래스 배열을 생성을 하여(new) data라는 변수에 할당을 할 것이고 그 변수에 수용할 수 있는 최대값은 3이라는 의미이다.
일반 데이터형의 배열의 경우
data[0] = 10;
data[1] = 20;
data[2] = 30;
객체배열의 경우
Unit [] data = new Unit[3];
data[0] = new Army("육군");
data[1] = new Navy("해군");
data[2] = new AirForce("공군");
위의 Army, Navy, AirForce는 Unit의 자식 클래스들이다. Unit이 0번째, 1번째, 2번째 방에 각각 자식 클래스들을 자신의 배열저장공간에 저장을 한 것이다.
▶객체배열의 장점
예를들어 Unit이라는 클래스에
display(){ syso(name) }
이런 함수가 있어 Army, Navy, AirForce가 모두 이 함수를 상속받았다. 그리고 Main 함수에 data[0].display();를 입력을 해서 육군,해군,공군이라는 단어를 모두 출력한다고 가정을 했을 때 이를 위해 우리는 data[0].display(); / data[1].display(); / data[2] .display(); 를 하나씩 모두 생성해주어야한다.
위와 같이 데이터가 3개 밖에 없으면 상관 없지만 만약 입력해야할 데이터가 100개, 1000개라면?
Unit클래스의 display()를 하나하나 수기로 입력 하는 것은 불가능 하다고 할 수 있다.
이 때 사용되는 것이 for문이다.
for(int i = 0; i < data.length; i++){
data[i].display();
}
로 for문을 생성한다면 data의 길이만큼 for문이 돌아갈 것이고 display 역시 그 수만큼 실행이 될 것이니 육군, 해군, 공군이 순서대로 쉽게 출력이 될 것 이다.
▶원래의 기능으로 복귀하기
근데 위의 문제는 Army, Navy, AirForce들은 각각의 지상작전, 해상작전, 공중작전 등의 본인들만의 개개인의 특성이 있을 것인데 저 배열에선 Unit에 상속받은 data라는 메서드밖에는 불러올 수 없다.
그래서 배열 속의 자식메서드의 고유의 메서드를 불러오기 위해서는 원래의 클래스 형태로 명시적 형변환이 이루어 져야 한다.
그러나 위의 배열처럼 단순 3개정도의 배열이라면 하나씩 다 명시적 형변환을 하는것이 가능하다. 그러나 만약 데이터가 100,000개라면? 우리는 30번째 저장공간에 어떤 데이터가 있는지 for문으로 반복적으로 처리되는 과정에서 정확한 데이터를 파악하는것은 쉽지 않다.
이때 사용하는 것이 instanceof 연산자이다.
▶instanceof 연산자
instanceof연산자는 어떤 객체에 대한 출처를 판단하여 boolean형으로 결과를 반환하여준다.
이 말은!
if(Units[0] instanceof Army){
Army temp 1 = (Army)units[0];
temp1.tank();
}
Units라고 하는 배열의 0번째 저장공간에 저장되어있는 객체가 혹시 Army니? 라고 물어보는 것이고 만약 맞으면 true 안에있는 if문 안으로 들어가서 if안에 있는 내용을 실행시킬 것 이다.
if문안의 구현부에는 Units의 고유의 기능 tank라는 메서드에 접근하기 위해 units[0]만 명시적 형변환을 시켜놓은 것을 확인할 수 있다.
즉, istanceof는 일반데이터값을 서로 비교해주는 equals 와 동일한 기능을 한다고 생각을 하면 되며 equals와 다른 점은 일반 데이터값이 아닌 객체를 비교해준다는 부분이다.
'국비필기노트 > Java' 카테고리의 다른 글
자바(java)_this와 this() (0) | 2022.03.22 |
---|---|
자바(java)_Getter & Setter (0) | 2022.03.22 |
자바(java)_오버로드(Overload)&오버라이드(Override) (0) | 2022.03.21 |
객체지향 프로그래밍(인스턴스, 자바빈즈, 클래스의 분리, 상속) (0) | 2022.03.17 |
java_메서드,클래스,생성자 선언 방법 정리 (0) | 2022.03.15 |