본문 바로가기

Java

Java - 상속성

내가 알아두고 싶어서 정리해본 내용

출처-https://developingman.tistory.com/10 (너무 감사합니다)

 

상속성 캡슐화 다형성 추상화

이 4가지 개념을 최대한으로 활용하여 객체(인스턴스)지향 프로그램을 만듬


1. 상속이란?

제일 단순한 형태는 상위클래스(부모)의 멤버(필드, 메서드, 이너클래스)를 하위클래스(자식)와
공유하는 형태
하위 클래스는 상위 클래스가 가진 '모든' 멤버를 상속받음
즉, 하위 클래스의 멤버개수>=상위클래스의 멤버개수
상속관계를 설정할땐 "자식 extends 부모" 식으로 extends키워드 사용

사용하는이유: 공통적으로 가지고 있는 특성(인간으로 치면 이름이나 나이 같은 특성, 
먹다,자다같은 기능)을 반복적으로 사용하지 않고 상속을 통해 코드 중복을 제거

예1)
사람클래스, 프로그래머클래스, 댄서클래스 가 있다고 가정
사람클래스는 프로그래머,댄서클래스의 상위클래스(부모)

class 프로그래머 extends 사람 //부모로부터 상속받음

Main 클래스 내에서 사람 클래스를 이용하여 인스턴스를 생성할때
Person man = new Person(); 이런식으로 생성하면, man이라는 인스턴스는 생성자 Person()
으로부터 초기화되며 사람의기본특성(이름나이) 행위(먹다,자다)를 받음

 

하지만
Programmer man2 = new Programmer();로 생성된 man2라는 인스턴스는
이름 나이 자다 먹다의 속성이 Programmer클래스에 정의되어 있지않지만
사람클래스(부모)로부터 상속 받았기 때문에 사용이 가능하고, Programmer라는
특성에 맞게, 코딩을 한다는 자식 고유의 속성을 가지고도 있다.

 

2. 포함관계?

상속의 개념중엔 포함관계가 있다.
포함(composite)은 상속처럼 클래스를 재사용 할 수 있는 방법.
"클래스의 맴버로, 다른 클래스 타입의 참조변수를 선언하는 것"(아래 예시엔 Address address;)
예)

public class Employee {
int id;
    String name;
    Address address;
    
public Employee(int id, String name, Address address){
   this.id = id;
        this.name = name;
        this.address = address;
    }
    
    void showInfo() {
     System.out.println(id + " " + name);
        System.out.println(address.city + " " + address.country);
    }
    
    public static void main(String[] args) {
     Address address1 = new Address("서울","한국");
     Address address2 = new Address("도쿄","일본");
        
        Employee e1 = new Employee(1, "이놈", address1);
        Employee e2 = new Employee(2, "저놈", address2);
        
        e1.showInfo();
        2e.showInfo();
    }
}
class Address {
String city, country;
    
    public Address(String city, String country) {
     this.city = city;
        this.country = country;
    }
}
// 출력 결과
1. 이놈
서울 한국
2. 저놈
도쿄 일본


밑에는 Address라는 클래스가 있고, 여기서 city,country가 문자열타입으로 선언된 뒤,
생성자를 만들어서 외부에서 자기 스스로에게 값을 넣어 초기화하며 사용할 수 있게 했다.
그리고 
Employee 라는 클래스의 멤버변수로 Employee가 사는 Address 타입의 변수가 선언되어 있음.
이렇게 하지 않았으면 Address 클래스의 인스턴스 변수 city, country를 Employee 클래스의 변수로
정의 했어야 했다. 하지만, Address 클래스로 변수들을 묶어준 후, Employee 클래스 안에서
참조변수를 선언하는 방법으로(Address address) 코드 중복없애고 사용했다. 이것이 포함관계
상속관계와 포함관계의 차이
상속관계를 쓸지, 포함관계를 쓸지 어떻게 정할까?


각 클래스간의 관계를 '~은 ~이다=a is b' 인지, '~은 ~을가지고있다= a has b'인지 생각해보면됨
Employee는 Address이다 = 이상함
Employee는 Address를 가지고 있다= 안이상함
위의 예시에선 포함관계가 적절한 것을 알 수 있음

 

3. 매서드 오버라이딩?

상위 클래스(부모)로 부터 상속받은 메서드와 동일한 이름의 메서드를 '재정의' 하는 것

예)
Person ()이라는 클래스에 run("Person is running")이라는 메서드가 정의되어 있음
Programmer 클래스는 Programmer extends Person ()
으로 Person이라는 부모로부터 상속받은 상태이고
Programmer 클래스에선 그 상속받은 클래스에 있는 동일한 이름의 run()을 재정의하여
run("Programmer is running") 이렇게 사용하면 이것을 매서드 오버라이딩이라고 함

메서드 오버라이딩은 상위클래스(부모)에 정의된 메서드를 하위클래스에 맞게 
동작을 변경하고자 할 때 사용함
메서드 오버라이딩시 반드시 지켜야하는 조건 3가지
1. 메서드 선언부(메서드 이름, 매개변수, 반환타입)가 상위 클래스 메서드와 '완전히 일치'
2. 접근 제어자(private, public 등)의 범위가 상위클래스의 메서드보다 같거나 넓어야함
3. 예외는 상위 클래스의 메서드보다 많이 선언할 수 없음

 

4. super? super()?

super 키워드: 상위 클래스의 객체를 호출
super() 키워드: 상위 클래스의 생성자를 호출

예) super 키워드

public class Example {
pubic static void main(String[] args){
     Son s = new Son();
        s.callNum();
    }
}

class Parents {
int count = 10;  //super.count
}

class Son extends Parents {
int count = 15; // this.count
    
    void callNum() {
     System.out.println("count = " + count);
        System.out.println("this.count = " + this.count);
        System.out.println("super.count =" + super.count);
}

//출력 결과
count = 15
count = 15
count = 10


위의 상황은 자식클래스가 부모클래스 count 변수를 상속받음. 근데 자신의 인스턴스 변수 count랑
이름이 같아서 둘을 구분해야됨.


이런 경우, 두 개의 같은 이름의 변수를 구분하기 위한 방법이 super키워드
super를 붙이지 않으면, 자바의 컴파일러는 해당 객체의 자신이 속한 인스턴스 객체를 먼저 참조함
반면 경우에 따라 상위 클래스의 변수를 참조해야 할 경우가 있는데 그때 super를 씀
super를 사용하면 상위 객체의 멤버값을 참조 가능
위의 예제의 main클래스에서 자식을 인스턴스화 한 s 로 s.callNum()메서드를 불러 결과를 보면 
15, 15, 10 인데, 자기 스스로의 각 행을 보면 this 를 사용한 행은 callNum() 메서드가 불릴때
자신의 값을 보내고, super를 사용한 행은 자신의 부모클래스의 값을 가져옴

예) super() 키워드

public class Test {
public static void main(String[] args){
     Programmer p = new Programmer();
    }
}

class Person {
Person() {
     System.out.println("Person class constructor");
    }
}

class Programmer extends Person { //Inheritance by Person class
Programmer() {
     super(); //Call constructor of Person class  
     System.out.println("Programmer class constructor");
    }
}

//output

Person class constructor
Programmer class constructor



Person 클래스를 상속받은 Programmer 클래스 안에 Programmer 생성자를 만드는데
Person 클래스의 생성자를 호출하고 있음. super()메서드도 this()와 마찬가지로 
'생성자 안에서만 사용가능, 반드시 첫 줄에 와야함'
만약 super()가 없는 경우 컴파일러가 생성자의 첫줄에 자동으로 super()를 삽입
이때, 부모에 기본 생성자가 없으면 에러가 발생
결론적으로, 클래스를 만들때는 자동으로 기본생성자를 생성하는것을 습관화 하여야함!


5. Object 클래스

자바의 상속계층도에서 최상위에 위치한 상위클래스
자바 컴파일러는, 컴파일 과정에서 다른 클래스로부터 아무런 상속을 받지 않는 클래스에
자동으로 extends Object 를 추가하여 Object 클래스를 상속받도록 함
Object 클래스의 대표적인 메서드(우리눈에 안보이지만 이미 오브젝트에서 다음의 메서드가
생성되어 있음)


1. toString(): 반환타입 String. 객체의 정보를 문자열로 출력
2. equals(Object obj): 반환타입 Boolean. 등가 비교연산(==)과 동일하게 스텍 메모리값 비교
3. hashCode(): 반환타입 int. 객체의 위치정보 관련. hashtable 또는 hashMap에서 동일객체여부판단
4. wait(): 반환타입 void. 현재 쓰레드 일시정지
5. notify(): 반환타입 void. 일시정지중인 쓰레드 재 동작

 

728x90
반응형

'Java' 카테고리의 다른 글

Java - 추상화  (2) 2024.09.23
Java - 다형성  (6) 2024.09.22
Java - Stream  (2) 2024.09.21
Java - 캡슐화  (1) 2024.09.13