My Melody Is Cute JAVA 기초8 객체지향프로그래밍 심화
본문 바로가기

개발공부🌷/JAVA

JAVA 기초8 객체지향프로그래밍 심화

 

상속 

기존의 클래스를 재활용해서 새로운 클래스를 작성하는 자바의 문법요소

서로 상속 관계,상위클래스의 모든멤버를 하위클래스가 상속받음 그래서 하위 클래스의 멤버 개수는 상위클래스의 것보다 같거나 많다

 

상속을 왜 사용할까?

코드를 재사용하여 보다 적은 양의 코드로 새로운 클래스를 작성할 수 있고 코드의 중복을 제거할 수 있다

다형적 표현이 가능 -> 하나의 객체가 여러모양으로 표현가능

ex) 프로그래머는 프로그래머이다 o  프로그래머는 사람이다 o

 

클래스를 상속할 때는 클래스명 다음에 extends 상위 클래스명을 사용하여 정의

class 자식클래스이름 extend 부모클래스이름 { ... }

단일 상속만 허용

자식 클래스에는 부모 클래스의 필드와 메소드만이 상속되며, 생성자와 초기화 블록은 상속되지 않는다.

또한, 부모 클래스의 접근 제어가 private이나 default로 설정된 멤버는 자식 클래스에서 상속받지만 접근할 수는 없다.

생성자가 있는 클래스를 상속 받았다면 그 클래스에 생성자를 만들어 반드시 부모 클래스 생성자를 호출해야 함

 

 

포함관계

상속처럼 클래스를 재사용할 수 있는 방법

클래스의 멤버로 다른 클래스 타입의 참조변수를 선언하는 것

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 e = new Employee(1, "김코딩", address1);
        Employee e2 = new Employee(2, "박해커", address2);

        e.showInfo();
        e2.showInfo();
    }
}

class Address {
    String city, country;

    public Address(String city, String country) {
        this.city = city;
        this.country = country;
    }
}

// 출력값
1 김코딩
서울 한국
2 박해커
도쿄 일본

원래라면 Address 클래스에 포함되어 있는 인스턴스 변수 city와 country를 각각 Employee 클래스의 변수로 정의해주어야 하지만, Address 클래스로 해당 변수들을 묶어준 다음 Employee 클래스 안에 참조변수를 선언하는 방법으로 코드의 중복을 없애고 포함관계로 재사용

상속보다 포함관계를 사용하는 경우가 더 많다

 

상속인지 포함인지 어떻게 판별할까?

클래스 간의 관계가 ‘~은 ~이다(IS-A)’ 관계인지

~은 ~을 가지고 있다(HAS-A) 관계인지

 

ex) Employee는 Address이다.라는 문장은 성립하지 않는 반면,

Employee는 Address를 가지고 있다.는 어색하지 않은 올바른 문장

따라서 이 경우에는 상속보다는 포함관계가 적합

 

Car 클래스와 SportCar라는 클래스가 있다고 할 때,

SportsCars는 Car를 가지고 있다.라는 문장보다

SportsCar는 Car이다.라는 문장이 훨씬 더 자연스럽다.

 따라서 이 경우에는 Car를 상위클래스로 하는 상속 관계

 

 

메서드오버라이딩

상위 클래스로부터 상속받은 메서드와 동일한 이름의 메서드를 재정의

상위클래스에 정의된 메서드를 하위클래스에서 메서드의 동작을 하위클래스에 맞게 변경하고자 할때 사용

 

오버라이딩 vs 오버로딩

overriding 덮어쓰기. 즉, 기존에 부모 class에 존재하는 method를 재정의(change)

overloading 과적. 상속과 관계 x 기존에 존재하는 method와 동일한 이름의 method를 형태만 다르게 사용(new)

public class Main {
    public static void main(String[] args) {
        Bike bike = new Bike();
        Car car = new Car();
        MotorBike motorBike = new MotorBike();
        
        bike.run();
        car.run();
        motorBike.run();
    }
}

class Vehicle {
    void run() {
        System.out.println("Vehicle is running");
    }
}

class Bike extends Vehicle {
    void run() {
        System.out.println("Bike is running");
    }
}

class Car extends Vehicle {
    void run() {
        System.out.println("Car is running");
    }
}

class MotorBike extends Vehicle {
    void run() {
        System.out.println("MotorBike is running");
    }
}

// 출력값
Bike is running
Car is running
MotorBike is running

Vehicle 클래스에 run() 메서드가 정의되어 있으며,

Bike, Car, MotorBike 클래스에서 run() 메서드를 재정의함으로써 Vehicle 클래스의 run() 메서드를 오버라이딩

 

상위클래스 메서드 오버라이딩 세가지조건

1. 메서드의 선언부(메서드 이름, 매개 변수, 반환 타입)가 상위클래스의 그것과 완전히 일치해야 한다.

2. 접근 제어자의 범위가 상위 클래스의 메서드보다 같거나 넓어야 한다.

3. 예외는 상위 클래스의 메서드보다 많이 선언할 수 없다.

 

super 키워드와 super()

 

this는 자기 객체를 가리키는 참조 변수명으로, 메서드 내에서 멤버 변수와 지역 변수의 이름이 같을 때

구분하기 위한 용도로 사용되며, 생략시 컴파일러가 자동으로 추가해준다

반면 this() 메서드는 같은 클래스의 다른 생성자를 호출하는 데 사용되며,

생성자 내에서만 사용 가능하고, 항상 첫 줄에 위치해야 한다

this는 자신의 객체, this() 메서드는 자신의 생성자 호출

 

super 키워드는 상위 클래스의 객체, super()상위 클래스의 생성자호출하는 것 

공통적으로 상위 클래스의 존재를 상정하며 상속 관계를 전제

public class Example {
    public static void main(String[] args) {
        SubClass subClassInstance = new SubClass();
        subClassInstance.callNum();
    }
}

class SuperClass {
    int count = 20; // super.count
}

class SubClass extends SuperClass {
    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 (SubClass의 변수)
this.count = 15 (SubClass의 변수)
super.count = 20 (SuperClass의 변수)

SubClass는 SuperClass로부터 변수 count를 상속받는데,

공교롭게도 자신의 인스턴스 변수 count와 이름이 같아 둘을 구분할 방법이 필요

두 개의 같은 이름의 변수를 구분하기 위한 방법이 바로 super 키워드

super 키워드를 붙이지 않는다면, 자바 컴파일러는 해당 객체는 자신이 속한 인스턴스 객체의 멤버를 먼저 참조

 

상위 클래스의 멤버와 자신의 멤버를 구별하는 데 사용된다는 점을 제외한다면 this와 super는 기본적으로 같은 것

 

super()this() 메서드처럼 생성자를 호출할 때 사용

this()같은 클래스의 다른 생성자를 호출하는 데 사용되지만, super()상위 클래스의 생성자를 호출

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

class Human {
    Human() {
        System.out.println("휴먼 클래스 생성자");
    }
}

class Student extends Human { // Human 클래스로부터 상속
    Student() {    
        super(); // Human 클래스의 생성자 호출
        System.out.println("학생 클래스 생성자");
    }
}

// 출력값
휴먼 클래스 생성자
학생 클래스 생성자

Human 클래스를 확장하여 Student 클래스를 생성하고,

Student 생성자를 통해 상위 클래스 Human 클래스의 생성자를 호출

생성자 안에서만 사용 가능하고, 반드시 첫 줄에 와야 한다.

모든 생성자의 첫 줄에는 반드시 this() 또는 super()가 선언되어야 한다

super()가 없는 경우에는 컴파일러가 생성자의 첫 줄에 자동으로 super()를 삽입

상위 클래스에 기본생성자가 없으면 에러

 

Object 클래스

최상위에 위치한 상위클래스

따라서 자바의 모든 클래스는 Object 클래스로부터 확장된다는 명제는 항상 참

아무런 상속을 받지 않는 클래스에 자동으로 extends Object를 추가하여 Object 클래스를 상속받도록 한다

class ParentEx {  //  컴파일러가 "extends Object" 자동 추가 

}

class ChildEx extends ParentEx {

}

Object 클래스는 자바 클래스의 상속계층도에 가장 위에 위치하기 때문에

Object 클래스의 멤버들을 자동으로 상속받아 사용할 수 있다

 

클래스 계층도의 최상위에 Object 클래스가 있다는 것,

그리고 이에 따라 아래와 같은 메서드들을 따로 정의하지 않고도 사용 가능하다

 

Object클래스의 대표적인 메서드

메서드명 반환타입 주요내용
toString() String 객체 정보를 문자열로 출력
equals(Object obj) boolean 등가 비교 연산(==)과 동일하게 스택 메모리값을 비교
hashCode() int 객체의 위치정보 관련. Hashtable 또는 HashMap에서 동일 객체여부 판단
wait() void 현재 스레드 일시정지
notify() void 일시정지 중인 스레드 재동작

 

상속 (프로그래밍) - 해시넷 (hash.kr)

 

상속 (객체 지향 프로그래밍) - 위키백과, 우리 모두의 백과사전 (wikipedia.org)