상속 & 캡슐화

김준영·2023년 2월 27일
1

Code States

목록 보기
5/33

상속


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

상속을 사용하는 이유?

코드를 재사용하여 보다 적은 양의 코드로 새로운 클래스를 작성할 수 있어 코드의 중복을 제거할 수 있고, 다형적 표현이 가능하다는 장점이 있다.

예제

class Student {
    String name;
    int age;
    
    public Student(String name, int age){
    	this.name = name;
    	this.age = age;
    }

    void learn(){
        System.out.println("교양수업을 듣습니다.");
    };
}

class CsStudent extends Student { // Student 클래스로부터 상속. extends 키워드 사용 
    String companyName;

    void coding(){
        System.out.println("코딩수업을 듣습니다.");
    };
}

class MathStudent extends Student { // Student 클래스로부터 상속
    String mathformula;

    void formula(){
		    System.out.println("근의 공식을 사용합니다.");
		};
}

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

        //Person 객체 생성
        Student s = new Studnet();
        s.name = "학생";
        s.age = 24;
        p.learn();
        System.out.println(s.name);

        //Programmer 객체 생성
        CsStudent cs = new CsStudent();
        cs.name = "박해커";
        cs.age = 26;
        cs.learn(); // Persons 클래스에서 상속받아 사용 가능
        pg.coding(); // Programmer의 개별 기능
        System.out.println(pg.name);

    }
}

//출력값
교양수업을 듣습니다.
학생
교양수업을 듣습니다.
코딩수업을 듣습니다.
박해커

자바의 객체지향 프로그래밍에서는 단일 상속만을 허용한다.

다만 인터페이스라는 문법 요소를 통해 다중 상속과 비슷한 효과를 낼 수 있는 방법이 있다.

포함 관계


상속처럼 클래스를 재사용할 수 있는 방법으로, 클래스의 멤버로 다른 클래스 타입의 참조변수를 선언하는 것을 의미

public class Computer {
    String os;
    Keyboard keyboard;

    public Computer(String os, Keyboard keyboard) {
        this.os = os;
        this.keyboard = keyboard;
    }

    void showInfo() {
        System.out.println("os : " + os);
        System.out.println(keyboard.company+ " " + keyboard.name);
    }

    public static void main(String[] args) {
        Keyboard keyboard1 = new Keyboard("로지텍", "무선 키보드");
        Keyboard keyboard2 = new Keyboard("로지텍", "유선 키보드");

        Computer c = new Computer("window", keyboard1);
        Computer c2 = new Computer("mac os", keyboard2);

        c.showInfo();
        c2.showInfo();
    }
}

class Keyboard {
    String company, name;

    public Address(String company, String name) {
        this.company = company;
        this.name = name;
    }
}

// 출력값
os : window
로지텍 무선 키보드
os : mac os
로지텍 유선 키보드

컴퓨터 클래스 안에 키보드 클래스를 참조변수로 사용한다.

그럼 상속관계, 포함관계 어떤 기준으로 판별해야 하나?

가장 쉬운 방법은 클래스 간의 관계가 ~은 ~이다(IS-A) 혹은 ~은 ~을 가지고 있다(HAS-A) 관계인지 생각해보면 쉽다.

메서드 오버라이딩


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

public class Main {
    public static void main(String[] args) {
        Math math = new Math();
        Korean korean = new Korean();
        English english = new English();
        
        math.learn();
        korean.learn();
        english.learn();
    }
}

class Study {
    void learn() {
        System.out.println("공부를 합니다.");
    }
}

class Math extends Study {
    void learn() {
        System.out.println("수학 공부를 합니다.");
    }
}

class Korean extends Study {
    void learn() {
        System.out.println("국어 공부를 합니다.");
    }
}

class English extends Study {
    void learn() {
        System.out.println("영어 공부를 합니다.");
    }
}

// 출력값
수학 공부를 합니다.
국어 공부를 합니다.
영어 공부를 합니다.

위 예시처럼 Study 클래스를 상속 받은 하위 클래스들은 상위 메서드인 learn 메서드를 자신의 클래스에 맞게 재정의 하였다.

메서드 오버라이딩 세 가지 조건

  • 메서드의 선언부(메서드 이름, 매개변수, 반환타입)이 상위 클래스의 그것과 완전히 일치해야한다.
  • 접근 제어자의 범위가 상위 클래스의 메서드보다 같거나 넓어야 한다.
  • 예외는 상위 클래스의 메서드보다 많이 선언할 수 없다.

super & super()


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

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

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

class SuperClass {
    int count = 20; // super.count
    SuperClass(){
    	System.out.println("상위 클래스 생성자");
    }
}

class SubClass extends SuperClass {
    int count = 15; // this.count
    
    SubClass(){
    	super();
    	System.out.println("하위 클래스 생성자");
    }

    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 = 20

하위 클래스는 상위 클래스의 count를 상속 받는데 인스턴스 변수가 같아 구분할 방법이 필요하다.

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

super() 메서드를 사용하여 상위 클래스 생성자를 호출한다.

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

이때 상위 클래스에 기본 생성자가 없으면 에러가 발생한다.

따라서 클래스를 만들 때 자동으로 기본 생성자를 생성하는 것을 습관화하는 것이 좋다.

Object 클래스


클래스 상속 계층도에서 최상위에 위치한 상위 클래스이다.

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

캡슐화


특정 객체 안에 관련된 속성과 기능을 하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것

  • 데이터 보호
  • 내부적으로 사용하는 데이터의 불필요한 외부 노출 방지

가장 큰 장점은 정보 은닉

패키지


클래스들을 그룹 단위로 묶어 효과적으로 관리하기 위한 목적을 가지고 있다.

패키지로 클래스를 묶는 것의 장점은 클래스의 충돌을 방지해주는 기능

Import문은

다른 패키지 내의 클래스를 사용하기 위해 사용

접근 제어자


제어자

클래스, 필드, 메서드, 생성자 등에 부가적인 의미를 부여하는 키워드

접근 제어자

  • public, protected, (default), private

기타 제어자

  • static, final, abstract, native, transient, synchronized 등

하나의 대상에 대해서 여러 제어자를 사용할 수 있지만, 접근 제어자는 각 대상에 대해 단 한번만 사용할 수 있다.

  • private : 동일 클래스에서만 접근 가능
  • default : 동일 패키지 내에서만 접근 가능
  • protectes : 동일 패키지 + 다른 패키지의 하위 클래스에서 접근 가능
  • public : 접근 제한 없음

접근 제한 범위

public -> protected -> default -> private

getter, setter

setter 메서드를 통해 데이터를 넣고 getter 메서드를 통해 데이터를 읽어온다.

profile
ㅎㅎ

0개의 댓글