[TIL] 플레이데이터 인공지능 24기 DAY 95

황예빈·2022년 12월 12일
0

플레이데이터 TIL

목록 보기
10/21
post-thumbnail

클래스를 형 변환 해야하는 상황

지난 시간 배웠던 Class 의 상속과 인터페이스 관련 실습을 마친 후 코드를 리뷰하는
시간을 가졌는데, 리뷰를 듣다보니 아직 부모나 자식 객체에 있는 메소드를
사용할 때 정확히 언제 형 변환이 일어나야하는지 헷갈리는 것 같아 정리해보고자 한다.

✅1.부모 클래스 인스턴스를 만들고 참조변수 타입을 부모로 받는 경우
=> 부모 클래스 내의 메서드 및 멤버 변수만 접근 가능하다.
Parent parent = new Parent();

✅2.자식 클래스 인스턴스를 만들고 참조변수 타입을 자식으로 받는 경우
=> 자식클래스와 상속받은 부모 클래스의 메서드, 멤버변수 접근이 가능하다.
Child child = new Child();

✅3.자식 클래스 인스턴스를 만들고 참조변수 타입을 부모로 받는 경우
=> 부모의 객체 구성요소에만 접근이 가능하다. 다만 상속 받은 클래스에서 오버라이딩 했다면, 자식 메소드가 호출된다.
Parent parent = new Child();

=> 바로 이 때가 객체 형 변환을 해야하는 경우 !!
부모 타입으로 자식을 참조해서 메소드를 추가적으로 구현했을 때
부모 객체 구성요소에만 접근이 가능하므로 자식 객체로 형변환을 해주는 것

✅4.부모 클래스 인스턴스를 만들고 참조변수 타입을 자식으로 받는 경우
Child child = new Parent();
=> 컴파일 에러

실습문제 클래스 다이어그램)

public class TVTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 클래스 객체 각각 생성
		TV saletv = new SaleTV(300000,"SALETV-1",40,1);
		TV rentaltv = new RentalTV(100000,"RENTALTV-10",42,1);
		RentalTV rentaltv2 = new RentalTV(100000,"RENTALTV-10",42,1);

		
		// sale tv의 채널을 높임
		saletv.channelUp();
		saletv.channelUp();
		
		// rental tv의 채널을 내림
		rentaltv.channelDown();
		rentaltv.channelDown();
		rentaltv.channelDown();
		
		// 각 객체에 대해 printAllTV() 호출
		TVTest.printAllTV(saletv);
		printAllTV(rentaltv);
		
		// printRentalTV() 호출
		printRentalTV((Rentable)rentaltv);
		printRentalTV((RentalTV)rentaltv);
		printRentalTV(rentaltv2);
	}
	
	static void printAllTV(TV tv) {
		
		if (tv instanceof SaleTV) {
			System.out.println(tv.toString());
			((SaleTV) tv).play();
			((SaleTV) tv).sale();
		}
		else if(tv instanceof RentalTV) {
			System.out.println(((RentalTV)tv).toString());
			((RentalTV) tv).play();
		}
	}
	static void printRentalTV(Rentable tv) {
		tv.rent();
	}

}

📑TV라는 부모 클래스의 타입으로 각각 SaleTV와 RentalTV라는 자식 클래스를 참조하여
각각 객체를 생성해주었다.

📑 channelUp(),channelDown()이라는 메소드는 부모 클래스에 있는 메소드로
객체가 부모타입으로 선언되어 있기 때문에 그냥 쓸 수 있다.

📑 printAllTV(TV tv)라는 메소드는 부모 타입객체로 매개변수를 받아들여서
객체의 인스턴스가 SaleTV일 경우에는 play()와 sale() 메소드를 호출하고,
RentalTV일 경우에는 play() 만 호출한다.

이때 객체 생성 시 부모 타입으로 자식 인스턴스를 형성했기 때문에
자식 메소드에서 추가로 구현한 play()와 sale()을 사용하려면 형변환을 해야하는 것이다.

📑 printRentalTV(Rentable tv)
printRentalTV() 메서드는 은 인터페이스 타입을 객체로 받아들인다.
지금 현재 RentalTV가 TV타입으로 선언되어 있고, 메서드는 Rentable 이라는
인터페이스를 상속 받아 만들어진 객체만 받을 수 있으므로, 형변환을 해야한다.
만약 이때 RentalTV가 RentalTV형으로 선언되어 있었으면 형변환 안하고
그냥 대입하는 것이 가능할 것이다.

📑 toString()
처음엔 tv.toString()을 하면 부모클래스에 있는 toString()이 호출될 것 같아
((SaleTV)tv).toString() 처럼 형변환을 해주었는데
toString 이라는 클래스는 부모 클래스에 존재하기도 하지만 상속 받은 클래스(SaleTV, RentalTV)에서 오버라이딩 해주었기 때문에 굳이 형변환 해주지 않아도 자식 클래스의 toString()이 호출된다!

auto boxing

auto-boxing: 객체가 와야할 자리에 기본형 데이터를 사용하고 싶을 때
이전에는 각 기본형에 맵핑된 wrapper class의 객체를 직접 생성하여
사용해야 했음

Object 형이 와야할 자리에 int --> Integer
double --> Double
char --> Character

직접 객체 생성해서 전달하지 않아도 기본형 데이터로 바뀜

auto unboxing

auto-unboxing : 기본형이 와야할 자리에 객체가 왔을 때 객체를
기본형으로 바꿔서 자동으로 컴파일 해주는 기능

package day10;
public class AutoBoxingUnboxingTest {
	public static void main(String[] args) {
		Integer obj = new Integer(10);
		obj = 100;  // 기본 --> 객체 - 오토박싱, 객체가 와야하는데 기본형이 옴
		int result = obj + 10; // 객체 --> 기본 - 오토언박싱, 기본형이 와야하는데 객체가옴, 사칙연산은 기본형에 대해서만 가능
		System.out.println(result);
	}
}

String Buffer

java.lang- Object(최상위),System,Math,Wrapper Classes(기본형 클래스),
String => read only, 항상 복사본 반환
StringBuffer => 편집 가능

StringBuffer : String 객체는 read only 이다 보니 문자열을 편집할 수 없음
그래서 문자열을 편집할 일이 있을 때 사용

package day10;

public class StringBufferTest {

	public static void main(String[] args) {		
		StringBuffer buffer = new StringBuffer();
		String str = "자바프로그래밍";
     	buffer.append(str);

        System.out.printf("%s\n", buffer);
        buffer.reverse();
        System.out.printf("%s\n", buffer);
        System.out.printf("길이 : %d\n", buffer.length());
        buffer.append(str);
        buffer.append(str);
        buffer.append(str);
        System.out.printf("%s\n", buffer);
	}
}

java.lang.Object에 있는 equals 메서드

One obj1= new One();
One obj2 = new One();

obj1 == obj2 (false)---> 얕은 비교 - obj1의 값과 obj2의 값이 동일한가? => 하나의 객체를 공유하고있는 상태인지를 비교
obj1.equals(obj2) ---> 깊은 비교- 각 변수가 참조하는 객체의 내용을 동일한지 비교한다.

One obj1 = new One();
One obj2 = obj1;

obj1 == obj2 (true)- 같은 하나의 객체를 참조

Object 클래스가 가지고 있는 등가 연산(==)한 것과 동일하다.

package day10;


public class EqualsTest2 {
	public static void main(String[] args) {

		String s1 = "가나다";
		String s2 = "가나다";
		String s3 = new String("가나다");
		String s4 = new String("가나다");
		
		System.out.println(s1 == s2);
		System.out.println(s3 == s4);
		System.out.println(s3.equals(s4));
		
	}
}

s1과 s2는 둘다 같은 "가나다"라는 객체를 참조하고 있기 때문에 == 연산 시 true가 나왔고,
s3와 s4는 각각 다른 문자열 객체를 생성해서 "가나다"를 가리키고 있기 때문에
== 연산 시 false가 나옴

equals는 단순히 그 객체가 참조하고 있는 내용을 비교하는 것이기 때문에
true가 나온다.

예외(Exception) 처리

프로그램실행중 예기치 못한 사건을 예외라고 한다.
예외 상황을 미리 예측하고 처리할 수 있는데, 이렇게 하는 것을 예외 처리라고 한다.

    public class ExceptionExam {
        public static void main(String[] args) {
            int i = 10;
            int j = 5;
            int k = i / j;
            System.out.println(k);
            System.out.println(main 종료!!);
        }
    }

위 코드에서 j를 0으로 바꾸면 Excption 발생

j를 0으로 바꾸면 ArithmeticException이 발생하면서 프로그램이 종료된다.
Java는 정수를 정수로 나눌때 0으로 나누면 안된다.0으로 나누면 오류가 발생하는 것입니다.
예외 처리

프로그래머는 j라는 변수에 0이 들어올지도 모르는 예외 상황을 미리 예측하고 처리할 수 있다.
예외처리하는 문법

오류가 발생할 예상 부분을 try라는 블록으로 감싼 후, 발생할 오류와 관련된 Exception을 catch라는 블록에서 처리한다.

오류가 발생했든 안했든 무조건 실행되는 finally라는 블록을 가질 수 있다.

finally블록은 생략가능하다.

    public class ExceptionExam {
        public static void main(String[] args) {
            int i = 10;
            int j = 0;
            try{
                int k = i / j;
                System.out.println(k);
            }catch(ArithmeticException e){
                System.out.println("0으로 나눌 수 없습니다. : " + e.toString());
            }finally {
                System.out.println("오류가 발생하든 안하든 무조건 실행되는 블록입니다.");
            }
        }
    }

실행결과
0으로 나눌 수 없습니다. : java.lang.ArithmeticException: / by zero
오류가 발생하든 안하든 무조건 실행되는 블록입니다.

참고)Object- public String toString(): 어떤 객체든 문자열로 변환되어야할 때
자동으로 호출됨

Exception 처리하지 않았을때는 프로그램이 강제 종료되었는데 catch라는 블록으로 Exception을 처리하니 강제종료되지 않고 잘 실행되는 것을 알 수 있다.

try블록에서 여러종류의 Exception이 발생한다면 catch라는 블록을 여러개 둘 수 있다.

Exception클래스들은 모두 Exception클래스를 상속받으므로, 예외클래스에 Exception을 두게 되면 어떤 오류가 발생하든지 간에 하나의 catch블록에서 모든 오류를 처리할 수 있다.

profile
Lv. 23

0개의 댓글