본문 바로가기
개발/Java

상속

by BellOne4222 2024. 1. 28.

 

 

객체 지향 프로그래밍 설계 하기


상속


 

 

수평적 구조와 수직적 구조의 설계 방법

  • 수평적 구조로 설계 한다면? → 각 클래스마다 DTO, VO를 만들어야한다.
    • 객체를 설계하다 보면 비슷한 클래스의 경우 중복적인 요소가 발생한다.
    • 객체를 수평적인 구조로 설계하면 단점
      1. 코드의 중복이 발생
      2. 새로운 요구사항 발생시 반영이 어렵다(유지보수가 어렵다)
      3. 확장성이 떨어진다.
  • 수직적 구조로 설계한다면?
    • 수직적 구조 = 계층화 = 상속 = 클래스와 클래스의 관계 설계
    • 부모가 확장(상속)(extends) 시켜서 자식이 부모의 정보를 사용가능 하기 때문에 코드의 중복부분을 최소화 할 수 있다.
    • 새로운 요구사항 발생 시 부모 클래스만 수정하면 되기 때문에 유지 보수가 쉽다.
  • 클래스를 계층화 해서 사용할 때의 장점
    • 클래스를 계층화 하는 것을 상속이라고 한다.
    • 코드의 중복을 최소화 할 수 있다.
    • 새로운 요구사항 발생시 반영이 쉽다(유지 보수가 쉽다.) → 부모 클래스만 수정하면되기 때문에
    • 확장성이 좋아진다. → 코드가 복잡해지긴한다.메모리를 통한 상속의 이해
  • 상태정보 재활용
  • 상속은 UML(Unified Modeling Language)를 사용하여 표현
  • super class : 상위 클래스, 부모 클래스
    • 일반화, 추상화, 개념화, 포괄적
  • sub class : 하위 클래스, 자식 클래스, 파생 클래스
    • 구체화(구상화), 세분화
  • protected : 상속관계에서 하위 클래스가 상위 클래스의 접근을 허용하는 접근 권한
    • 같은 패키지 내에 있을 때만 사용 가능
    • 자식 클래스에서 protected 선언한 정보에 접근 가능하기 때문에 정보은닉의 위배된다는 위험이 존재
  • 정보은닉을 위해 private을 사용하면 자식 클래스에서 접근이 불가능 하므로 protected 사용 → 자식은 protected로 선언한 객체에만 접근이 가능하다.
  • super() : 상위 클래스의 생성자를 호출\
  • 상속 관계에서 객체 생성
    • 클래스명 객체 변수 = new 클래스명();
  • 상속을 사용하면 하위 클래스가 상위클래스를 재활용 가능하다.
    • 하위 클래스가 상위클래스르 접근하여 사용 가능
    💡 자식인데 부모의 기억공간은 상속을 해주었기 때문에 가능하다.상속관계에서 객체 생성(중요)
  • 자식이 부모의 상태정보를 마음대로 접근하는 것은 정보 은닉에 위배된다.

  1. 정보 은닉을 적용하기 위해서 자식 클래스에서 객체를 생성해서 직접 데이터를 부모 클래스로 보낸다.
  2. 부모의 생성자를 호출해서 부모 클래스에서 직접 데이터를 초기화 하는 방식이 바람직하다.
  3. 부모 클래스의 상태정보를 protected가 아닌 private로 설정하고, 자식 클래스에서 직접 데이터를 보내서 부모 클래스에서 초기화 하는 방식으로 정보 은닉을 구현
// 부모
public class Employee{ // object 클래스 -> 최상위 클래스 ( extends Object)
	private String name;
	private int age;
	private String phone;
	private String empDate;
	private String dept;
	private boolean marriage;
	
	public Employee(){
		super(); // 상위 클래스의 생성자를 호출 -> new Object()에 의해서 객체가 생성된다.
	}

	public Employee(String name, int age, String phone, String empDate, String dept, boolean marriage) {
		this.name = name;
		this.age = age;
		this.phone = phone;
		this.empDate = empDate;
		this.dept = dept;
		this.marriage = marriage;
	}

// 자식
public class RempVO extends Employee {
	public RempVO(){
		super();
	}

	public RempVO(String name, int age, String phone, String empDate, String dept, boolean marriage){
		// 초기화(자식이 부모의 기억공간에 초기화를 하는 경우)
		super(name,age,phone,empDate,dept,marriage); // 부모의 생성자를 호출

	}

// main
public class EmployeeTest {
	public static void main(String[] args) {
		// [일반사원] 한명의 객체를 생성하고 데이터를 저장후 출력을 하세요.
		RempVO vo = new RempVO("홍길동",35,"010-1111-1111","2022-11-10","기획부",false); // 객체 생성, Employee 상속
		System.out.println(vo.toString());

	}
}

 

상속관계에서 객체 생성 및 Override


동작 측면에서 클래스 설계

  • 수평적 구조 측면
    • 중복이 발생한다.
public class DogCatTest {
    public static void main(String[] args) {
        // Dog [객체를 생성]하고 eat()동작을 구동해보자.
        Dog d = new Dog();
        d.eat();

        //  Cat [객체를 생성]하고 eat(), night() 동작을 구동해보자.
        Cat c = new Cat();
        c.eat();
        c.night();
    }
}

public class Dog {

    public void eat(){
        System.out.println("개처럼 먹다");
    }

}

public class Cat {

    public void eat(){
        System.out.println("고양이처럼 먹다");
    }

    public void night(){
        System.out.println("밤에 눈에서 빛이 난다.");
    }
}
  • 수직적 구조 측면
    • 중복적인 구조를 부모 클래스로 빼서 상속을 하여 사용하여 확장
public class Dog extends Animal{

}

public class Cat extends Animal{

    public void night(){
        System.out.println("밤에 눈에서 빛이 난다.");
    }
}
  • 상속 구조를 왜 사용해야 할까?
    • 클래스 안에 있는 내용을 숨긴다(소스코드를 주면 안되기 때문에)
    • 중간 인터페이스 역할을 할 수 있는 클래스(부모 클래스)를 통해서 자식 클래스의 역할을 알 수 있고 사용 할 수 있게 설계해야 하고 이를 상속으로 할 수 있다.

상속관계에서 객체 생성 방법

  • Upcasting
    • 부모가 자식을 가리키는 객체 생성 방법
    • 부모 클래스를 통해서 자식 클래스를 사용하는 방법
    • 작은 타입이 큰 타입으로 들어간다.
    • Upcasting : Dog의 소스코드를 주지 않고 Dog의 클래스와 상속 관계인 것만 알면 Animal 부모 클래스로 Dog 자식 클래스를 사용하기 위해서 사용
public class DogCatUpcastingTest {
    public static void main(String[] args) {
        // Dog객체를 사용해보자
        // Dog d=new Dog();
        // d.eat();
        // Upcasting(업케스팅)
        // 부모가 자식을 가리킨다.
        Animal ani = new Dog();
        ani.eat(); // 동물처럼먹다 -> 개처럼 먹다

        ani = new Cat();
        ani.eat(); // 동물처럼먹다 -> 고양이처럼 먹다.
    }
}

상속 체이닝과 super

  • 상속체이닝
    • 맨 위 부모클래스 부터 객체가 생성되어 자식까지 연결되는 구조
  • super()
    • 상위 클래스의 생성자를 호출하는 메서드
    • 생성자 메서드에서 가장 첫 문장에 사용해야한다. ( First Statement)
      • 상위 클래스 객체를 먼저 생성하고 수행문을 수행해야한다.
    • 상위 클래스의 기본생성자를 호출하는 super()는 생략되어있다.

메서드의 재정의(Override)가 필요한 이유

  • Override(재정의)
    • 상속관계에서 하위클래스가 상위 클래스의 동작을 재정의 하는 행위(기능 추가, 변경)
    • 동적바인딩
      • 실행시점에서 사용될 메서드가 결정되는 바인딩
        • 컴파일 시점
          • 부모의 시점에서 실행
        • 실행 시점
          • 자식의 시점에서 실행
public class OverrideTest {
    public static void main(String[] args) {

        // Upcasting : Dog의 소스코드를 주지 않고 Dog의 클래스와 상속 관계인 것만 알면 Animal 부모 클래스로 Dog 자식 클래스를 사용하기 위해서 사용
        Animal ani = new Dog(); // 부모 클래스로 Dog 자식 클래스 사용
        ani.eat(); // Animal---(동적바인딩)-->Dog

        ani=new Cat(); // 같은 부모 클래스를 사용하기 때문에 Animal 선언 x
        ani.eat();// Animal---(동적바인딩)-->Cat
    }
}

// 부모가 가진 eat를 재정의(Override)
    public void eat(){
        System.out.println("개처럼먹다");
    }

// 부모가 가진 eat를 재정의(Override)
    public void eat(){
        System.out.println("고양이처럼 먹다");
    }

'개발 > Java' 카테고리의 다른 글

다형성  (0) 2024.01.29
객체 형변환  (0) 2024.01.28
객체 생성과 static 과의 관계  (0) 2024.01.28
JVM이 사용하는 메모리 영역  (0) 2024.01.28
Static  (0) 2024.01.28