JAVA_상속

이혜윤·2024년 1월 22일

JAVA

목록 보기
2/9
post-thumbnail

1. 상속의 정의

어떤 클래스의 특성을 그대로 갖는 새로운 클래스를 정의한 것

상위 클래스 = 부모 클래스 = super class

하위 클래스 = 자식 클래스 = sub class

특성이란?

  • 멤버 변수
  • 메서드

2. 상속의 특징

2.1 확장성, 재사용성

부모의 생성자와 초기화 블록은 상속 X

2.2 클래스 선언 시 extends 키워드를 명시

자바는 다중 상속 허용X, 단일 상속만 지원. 한 번에 하나만 상속받을 수 있다.

2.3 관계

  • 부모(상위,super) 클래스: Person
  • 자식(하위, sub) 클래스: student

2.4 자식 클래스는 부모 클래스의 멤버 변수, 메소드를 자신의 것처럼 사용할 수 있다.

(접근 제한자에 따라 사용 여부 달라진다.)

2.5 object 클래스는 모든 클래스의 조상 클래스

별도의 extends 선언이 없는 클래스는 extends object가 생략

3. super

super를 통해 조상 클래스의 생성자 호출

💡 object가 갖고 있는 속성이 메모리에 맨 처음으로 올라간다

person 는 object의 기본 생성자를 호출

가장 마지막에 student 관련된 major, study 등이 메모리에 올라간다.

메모리에는 조상꺼부터 순차적으로 생성됨

4. 오버라이딩

≠오버 로딩

같은 설계도 안에서 메소드 명은 동일

오버 라이딩

애초에 상속 관계가 있을 때만 발생하는 개념

자식 클래스에서 부모 클래스의 특정 메소드를 재정의

  • 메서드의 이름, 반환형, 매개변수(타입, 개수, 순서) 동일해야 한다. 하나라도 달라지면 재정의(오버라이드)가 아님.

에러 발생 예시

  • 하위 클래스의 접근 제어자 범위(private, (default), protected, public)가 상위 클래스보다 크거나 같아야한다. (ex. 상위-public, 하위-private 는 불가능)
  • 조상보다 더 큰 예외를 던질 수 없다.

@override: annotation. 컴파일러에게 알려주는 주석. 이 메소드는 오버라이드 한 것이다 라고 명시적으로 알려줌

반환형, 매개 변수까지 다 같아야하는데 내가 실수를 했을 때 컴파일러가 내 실수를 잡아줄 수 있도록

5. object 클래스

가장 최상위 클래스로 모든 클래스의 조상

object의 멤버는 모든 클래스의 멤버

5.1 toString 메서드

  • 객체를 문자열로 변경하는 메서드
// student 클래스 내부
@Override
	public String toString() {
		return "Student [major=" + major + ", name=" + name + ", age=" + age + "]";
	}
System.out.println(p.toString()); //test05_object.Person@1c4af82c
System.out.println(st.toString()); //Student [major=computer, name=Yang, age=45]

toString()을 재정의한 student 객체만 바뀐 메소드 호출. person 객체는 object 소속 tostring 호출

5.2 equals 메서드

  • 두 객체가 같은지를 비교하는 메서드
  • 두개의 레퍼런스 변수가 같은 객체를 가르키고 있는가?

객체의 주소 비교: == 활용

객체의 내용 비교: euqals 재정의

5.3 hashCode

객체의 해시 코드: 시스템에서 객체를 구별하기 위해 사용되는 정수 값

Hashset, HashMap 등에서 객체의 동일성을 확인하기 위해 사용

equals 메서드를 재정의할 때는 반드시 hashCode도 재정의할 것

미리 작성된 String 이나 Number 등에서 재정의 된 hashCode 활용 권장

6. final

해당 선언이 최종 상태, 결코 수정될 수 없음

final 클래스: 상속 금지

final 메소드: overriding 금지

final 변수: 더 이상 값을 바꿀 수 없음. 상수화

7. 다형성(Polymorphism)

상속 관계에 있을 때 조상 클래스의 타입으로 자식 클래스 객체를 참조할 수 있다. (거꾸로는 X)

ex. 메모리에 실제로 올라가 있는 건 student 객체라서 student 속성도, person 속성도 있지만, perosn 속성으로만 바라보겠다.

package test07_polymorphism;

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

        
    	// 다형성
    	// 조상 클래스의 타입으로 자식 객체를 참조할 수 있다. 
    	
        Student st = new Student();
        Person p = new Student(); // 실제 메모리에 생성된 객체는 student 이지만, person으로 바라보겠다.
        Object obj = new Student(); //실제 메모리에 생성된 객체는 student 이지만, object로 바라 보겠다.
        
//        st.
//        p. 
//        obj.
        
        
        // person에서 tostring을 오버라이드 했음
        Object o2 = new Object();
        Object o3 = new Person(); // 다형성 
        // object로 바라본다 하더라도! 실제 객체는 사람이다. 
        // 메서드를 실행하면 사람의 행동을 한다.  
        
        
        System.out.println(o2.toString());
        System.out.println(o3.toString());
    }
}

위 → 아래 순으로 생성.

참조 변수의 형 변환 (= 암묵적 형 변환)

자손 타입 → 조상 타입 ( 묵시적 형 변환 )

형 변환 생략 가능

Student st = new Student();
Person p = st; 
Person p = new Person();
Student st =(Student) p;

실제 객체는 사람인데 우리가 학생이라고 생각을 해버림

참조는 할 수 있으나, 실제 메모리에 들어있지 않으면 에러가 난다.

instanceof 연산자

Movie의 자식 SeriesMovie 클래스가 존재할 때,
manager 코드에서 시리즈영화가 아닌 일반 영화만 호출하고자 한다.

	// 일반 영화들만 !!  반환
	public Movie[] getMovies() {
		int cnt=0;
		for(int i=0; i<this.size; i++) {
			if(!(movieList[i] instanceof SeriesMovie)) {
				cnt++;
			}
		}
		
		Movie[] mList = new Movie[cnt];
		
		int idx=0;
		for(int i=0; i<this.size; i++) {
			if(!(movieList[i] instanceof SeriesMovie)) {
				mList[idx++] = (Movie) movieList[i];
			}
		}
		return mList;
	}

참조변수와 인스턴스 멤버의 관계

(추가예정)

동적 바인딩

package test09_binding_test;

class Parent {
    String x = "parent x";
    
    public void method() {
        System.out.println("parent method.");
    }
}

class Child extends Parent{
    String x = "child x";
    
    @Override
    public void method() {
        System.out.println("child method.");
    }
}

public class BindingTest {
    
    public static void main(String[] args) {
        Parent a = new Parent();
        Child b = new Child();
        
        System.out.println(a.x);
        a.method();
        
        System.out.println(b.x); // hiding
        b.method(); // overriding
        
        
        // 다형성 
        Parent c = new Child();
//      실제 객체는 child 이므로 행위는 child의 행위를 하게 됨
//		부모 클래스의 타입으로 참조한다 하더라도 = 부모 클래스로 바라본다 하더라도
//      실제로는 child
        
        c.method(); //child method. // 자식의 행위를 하고 있는데...
        System.out.println(c.x); //parent x  // 부모의 멤버 변수가 튀어나옴 ?
        
        // 동적 바인딩
        // 실제 객체의 행위가 나온다! => 다형성
        // 멤버 메서드는 => 부모의 관점으로 바라보더라도 자식에서 재정의한 행위가 발생한다. 
        // 멤버 변수는 다형성을 따르지 않는다. => 부모의 관점으로 바라보면 
        // 부모의 것을 참조...
        
    }

}

회고

super.toString()

상속받은 필드 포함해서 toString 작성 어케하는지

@Override
	public String toString() {
		return "SeriesMovie"+ super.toString()+", seriesNum=" + seriesNum + ", episode=" + episode + "]";
	}

일반 movie만 조회하는건지, 만약 그렇다면 instanceof가 아닌 다른 메서드를 활용해야하는건지

// 일반 영화들만 !!  반환
	public Movie[] getMovies() {
		int cnt=0;
		for(int i=0; i<this.size; i++) {
			if(!(movieList[i] instanceof SeriesMovie)) {
				cnt++;
			}
		}
		
		Movie[] mList = new Movie[cnt];
		
		int idx=0;
		for(int i=0; i<this.size; i++) {
			if(!(movieList[i] instanceof SeriesMovie)) {
				mList[idx++] = (Movie) movieList[i];
			}
		}
		return mList;
	}

	

	
	// 시리즈 영화들을 반환
	public SeriesMovie[] getSeriesMovies() {
		
		int cnt=0;
		for(int i=0; i<this.size; i++) {
			if(movieList[i] instanceof SeriesMovie) {
				cnt++;
			}
		}
		
		SeriesMovie[] sList = new SeriesMovie[cnt];
		
		int idx=0;
		for(int i=0; i<this.size; i++) {
			if(movieList[i] instanceof SeriesMovie) {
				sList[idx++] = (SeriesMovie) movieList[i];
			}
		}
		return sList;	
	}

자식 클래스는 부모 클래스의 멤버 변수, 메소드를 자신의 것처럼 사용할 수 있다. (접근 제한자에 따라 사용 여부 달라진다.)

부모 클래스에서 private으로 설정한 멤버 변수의 경우, 자식 클래스에서 사용할 수 없다. 메모리에는 올라가있지만, 자식 클래스에서는 사용할 수 없다.

profile
구르미 누나

0개의 댓글