본문 바로가기
study_java/java_수강정리(~10.29)

[JAVA]15일차

by developer_j 2020. 5. 31.
728x90
반응형

< 15일차 수업 >

 

15일차에는 상속과, 상속으로 사용할 수 있는 다형성과 오버라이딩까지 배웠다.

 

1. 상속

 

상속은 상위클래스의 멤버(변수, 함수들)를 하위클래스가 물려받아서 사용할 수 있도록 하는 것이다. 상속 여부는 extends 키워드로 표현해준다. 또한, 자바에서는 단일 상속만 할 수 있다. 한번에 한 클래스만 상속할 수 있다는 뜻이다.

class Parent{
	int age;
    
	public void Print(){
    	System.out.println("부모 클래스");
	}
} 

class Child extends Parent{
	String name;
    
	public void ChildPrint(){
    	System.out.println("자식 클래스");
	}
} 

 

Child 클래스는 Parent 클래스를 상속하므로, Child의 인스턴스를 생성하면 다음과 같이 구성된다.

 

 

 

한편, 상속을 하게 되면 상속하는 클래스(자식 클래스)의 생성자를 호출 할 때 상속되는 클래스(부모 클래스)의 생성자가 자동적으로 호출된다. 따라서 만약 부모클래스의 생성자 정의가 어떠한 매개변수를 넘겨받는다면, 자식클래스의 생성자 호출 정의 부분에서 부모클래스 생성자의 매개변수도 같이 받아서 부모 클래스의 생성자를 호출하여 넘겨주어야 한다. 이는 super 키워드로 해준다.

 

 class Parent{
	private int age;
	
    Parent(int age){
		this.age = age;
	}
}
 
class Child extends Parent{
	private String name;

	Child(int age, String name){
		super(age);         //부모 생성자에게 age 매개 변수 넘겨주기
		this.name = name;
	}
}

 

생성자를 두개로 나누어 각각의 클래스에서 정의하는 이유는 생성자의 원래 용도에 맞게 쓰기 위함이다. 생성자의 용도가 무엇인지 기억할 것! 생성자의 용도는 변수의 초기화이며, 변수의 초기화는 해당 클래스에서 이루어져야 한다.

super 키워드는 매개변수로 넘겨받는 값을 만족하는 생성자를 알아서 찾아 호출하거나, super.변수/함수명을 통해 부모 클래스의 멤버에 접근할 수 있도록 한다.

 

+) 비슷한 키워드는 this :

①this.변수명/함수명으로 자신의 변수 및 함수에 접근하거나 호출한다. ②this(매개변수); 로 자신의 생성자를 호출

super 은 반드시 생성자 선언부의 제일 윗부분에 선언되어서 부모클래스의 생성자를 먼저 호출해야 한다. 만약 부모클래스에 생성자가 선언되어 있지 않다면 디폴트 생성자를 호출한다.

 

 +) protected 키워드

protected 키워드는 상속을 했을 경우 자식클래스가 부모클래스의 멤버를 사용할 수 있게 해준다.


2. 다형성

 

상속을 배웠다면, 다형성으로 넘어갈 차례다. 다형성이라 함은 상속관계 안에서, 한 객체를 여러가지의 타입으로 선언해 줄 수 있다는 것을 말한다.

예를들어, Parent pt = new Child(); 가 가능하다는 것이다.

 그러나 다형성으로 자식 객체를 생성하게 되었더라도 참조하는 인스턴스의 모든 멤버를 사용할 수 있는 게 아니다. 위의 코드를 가지고 설명을 하자면, pt는 Parent 타입으로 Child 객체를 참조하겠다고 선언하고 있지만 Parent 타입이기 때문에 Child 객체 중에서도 Parent의 멤버만 사용할 수 있다는 것이다. 아래 그림을 참조한다.

 

발그림2

 

따라서, 클래스형 타입에 따라 참조하는 객체의 멤버 사용 범위가 제한된다.

 

이를 사용하는 이유는 사용가능한 데이터 범위를 제한함으로써, 코드의 안정성을 높히기 위함이라고 한다. 사실 사용 이유는 나도 책을 보면서도 크게 공감을 못한 부분이라, 아직 기초만 배우는 중이니 차차 공부하면 사용 목적에 대해서 이해할 것이라고 생각한다.

 

2-1. 다형성과 형 변환

 

클래스형 타입에 따라 참조하는 객체의 멤버 사용범위를, 형변환으로 늘릴 수 있다.

부모클래스형으로 변수를 선언하고 자식 객체를 참조하게 할 수는 있지만, 반대로 자식클래스형으로 부모 객체를 참조하려면 자바컴파일러는 안정성을 문제로 에러를 발생시킨다.

클래스의 형 변환시에는, 참조변수의 클래스형과 참조하는 인스턴스에 주의해야 한다.

예를 들어, Parent 클래스가 있고 Parent 클래스를 Child 클래스가 상속할 때,

Parent pt1 = new Child();
Child ch1 = (Child) pt1;

Parent pt2 = new Parent();
Child ch2 = (Child) pt2; //에러

이 코드처럼 Parent 형 참조변수 pt1이 자식 클래스를 참조하고 있다면 명시적 형변환이 포함되어 형변환이 가능하지만, Parent 형 참조변수 pt2가 부모클래스인 자신을 참조하고 있다면 자식클래스로 형변환이 불가능하다.

이것은 예전에 배웠던 형변환 처럼 정수형에서 실수형으로 데이터 범위를 확장하는 것은 자동 형변환이 되지만, 실수형에서 정수형으로 데이터 범위를 축소할 때는 우리가 명시적 형변환을 해주어야 했던 것과 같은 원리다. 데이터 범위가 더 큰 자식클래스가, 데이터 범위가 더 작은 부모 클래스를 참조하겠다고 선언하는 것은 명시적으로 형변환을 표시해주어야 한다는 거다. 안해주면 에러가 발생한다.

Parent pt = new Child("j_cum");
Child ch = (Child)pt;           

 

+)반드시 이렇게 대입해주어야 하는 것 같다.  pt를 대입하지 않고 바로 형변환을 시도 했더니, 오류가 발생했다.

해본 코드 : Child ch = (Child) new Parent(); 

 

부모클래스는 자식클래스로 cast를 할 수 없다고 경고한다.

 

+)

더보기

하지만, 큰 것에서 작은 것으로 형변환 할 경우 참조변수가 다룰 수 있는 멤버의 개수를 늘이는 것이므로, 실제 인스턴스의 멤버 개수보다 참조변수가 사용할 수 있는 멤버의 개수가 더 많아지므로 문제가 발생할 가능성이 있다. 그래서 자손타입으로의 형변환은 생략할 수 없으며, 형변환을 수행하기 전에 instanceof 연산자를 사용해서 참조변수가 참조하고 있는 실제 인스턴스의 타입을 확인하는 것이 안전하다.

  참조 변수의 형변환은 참조변수의 타입을 변환하는 것이지 인스턴스를 변환하는 것은 아니기 때문에 참조변수의 형변환은 인스턴스에 아무런 영향을 미치지 않는다.

참조 - https://devbox.tistory.com/entry/Java-다형성 [장인개발자를 꿈꾸는 :: 기록하는 공간]

 


2-2. instanceof 연산자

 

instanceof 연산자는 상속과 관련한 연산자인데, 자동형변환의 가능성을 판단해주는 연산자이다. 자동형변환이 가능하면 true, 가능하지 않으면 false 를 반환한다.

instanceof 연산자는 테스트를 해보면서 이해되지 않는 부분이 있어, 더 공부하고 추가할 것이다.

 


 

3. 오버라이딩

 

오버라이딩은 오버로딩과는 다른 개념이다. 오버로딩이 같은 함수명을 가지고 매개변수 타입 혹은 갯수를 달리하여 정의하는 것이고, 오버라이딩은 함수명과 매개변수 등 모든게 똑같지만 실행 내용만 다른 것을 말한다.

 

오버라이딩된 함수를 호출할 때는, 참조하는 객체의 함수를 호출한다.

 

class GrandParent{
	void Print() {
		System.out.println("GrandParent의 Print 함수");
	}
}

class Parent extends GrandParent{
	void Print() {
		System.out.println("Parent의 Print 함수");
	}
}

class Child extends Parent{
	void Print() {
		System.out.println("Child의 Print 함수");
	}
}

public class Test01 {
		public static void main(String[] args) {
			GrandParent gp = new GrandParent();
				Parent pt = new Parent();
				Child ch = new Child();
				
                gp.Print();
				pt.Print();
				ch.Print();

				System.out.println("\n참조 객체를 달리 했을 때는?");
				GrandParent gp2 = new Child();
				
                gp2.Print();
		}
}
<결과>
GrandParent의 Print 함수
Parent의 Print 함수
Child의 Print 함수
 
참조 객체를 달리 했을 때는?
Child의 Print 함수

 

즉, 참조하는 객체를 기준으로 가장 마지막에 오버라이딩 된 함수를 호출한다!

728x90
반응형

'study_java > java_수강정리(~10.29)' 카테고리의 다른 글

[JAVA]16일차  (0) 2020.06.01
[JAVA]15일차(2)  (0) 2020.05.31
[JAVA]14일차  (1) 2020.05.31
[JAVA]13일차  (0) 2020.05.27
[JAVA]12일차  (0) 2020.05.26