[Java] 상속

이지원·2025년 2월 4일

Java Study

목록 보기
9/9
  • 상속의 필요성
    내가 생각하는 상속이 가장 필요한 이유는 객체지향의 특징 중 하나인 다형성을 극대화하기 위해서 상속이 필요하다고 생각한다. 하지만, 다형성에 대해 학습은 다음에 예정되어 있기 때문에 다른 이유를 생각해보면 코드의 효율성과 생산성을 높일 수 있기 때문에 상속을 필요하다고 생각한다.

    • 코드의 효율성과 생산성
      위에서 말한 코드의 효율성과 생산성이 대체 뭐지 라고 생각할 수 있다。 간략하게 설명해서 코드의 효율성은 프로그램이 주어진 자원을 얼마나 잘 활용하는지, 코드의 생산성은 명확하며, 재사용이 가능하며, 유지 보수가 좋은지를 설명한다고 알면 되고 상속을 학습하면서 차차 알아보면 좋을 것 같다.

상속 관계

  • 상속이란
    상속이 왜 필요한지, 위에서 알아보았다. 그러면, 상속이 무엇인지 설명을 먼저 하겠다.
    상속은 객체지향 프로그래밍에서의 특징 중 하나로, 기존 클래스를 기반으로 새로운 클래스를 정의하는 것을 말한다.

    • 특징
    1. 부모 클래스의 속성과 메서드를 자식 클래스가 그대로 물려받아 사용할 수 있다.

    2. 자식 클래스는 부모 클래스의 기능을 확장하거나 재정의(오버라이드)하여 새로운 기능을 추가할 수 있다.

    3. 상속을 사용하면 코드의 중복을 줄일 수 있고, 공통된 기능을 부모 클래스에 정의해두어 유지 보수성을 높일 수 있다.

      이러한, 특징이 위에서 말한 코드의 효율성과 생산성을 높이고 상속이 필요한 이유를 설명해준다.

상속 사용법

  • 코드로 상속을 확인

    public class Parent {
    		public void eat() {
    			System.out.println("음식을 먹습니다.");
            }
    }
    public class Child extends Parent {
    	   @Override
           public void eat() {
           		System.out.println("음식을 자식이 먹습니다.");
           }
    }

    먼저, 상속은 extends 키워드를 사용하여 부여할 수 있다. 위의 특징에서 말한 재정의를 통해 Child 클래스에서 부모에서 정의한 eat 메서드를 재정의하여 사용할 수 있다. 메서드 오버라이드는 @Override 애노테이션을 통해 이루어 지며, 메서드 오버라이딩에 대해 뒤에서 설명할 예정이다. 만약, Child 클래스에서 부모 클래스의 메서드를 재정의하지 않는다면 부모 클래스의 메서드를 그대로 불러오게 된다. 자세한 설명은 뒤에서 할 예정이다.

    또한, 상속은 단일 상속만 가능하다.
    위와 같이 Child 클래스가 Dad 클래스와 Mom 클래스를 상속받고 Child가 eat() 메서드를 재정의 하지 않는다면 실행 시, 어느 부모의 eat()을 사용해야 할지 모르기 때문에 상속은 다중 상속이 불가능하다.

상속과 메모리 구조

위에서 메서드를 재정의 하지 않으면 부모의 메서드를 이용한다고 하였다. 말로만 들으면 잘 와닿지 않기 때문에 상속 객체가 메모리에 생성되고 메서드를 불러오는 과정을 그림을 통해 설명하겠다.

  • Child 인스턴스 생성 시 메모리 구조
    위와 같이 Child 인스턴스 생성 시 Child 클래스 정보와 상속받은 Parent 클래스 정보 2개가 한 인스턴스에 생성된다. 위는 Child 클래스에서 부모 메서드를 재정의 하지 않은 것이라고 가정한다면, 메인에서 Child 인스턴스를 통해 eat() 메서드를 호출한다면 먼저 Child 클래스 정보에서 eat 메서드가 재정의 되었는지, 아니면 기능을 추가했는지 확인한 후 없으면 Parent 클래스에서 eat 메서드를 호출하게 된다. 따라서, Child는 부모의 메서드를 인스턴스 내에 Parent 클래스 정보를 가지고 있음으로써 사용할 수 있게 된다.

    다만, 설명을 하는데 있어 담은 타입에 따라 Child를 탐색하는지, Parent를 바로 가는지 달라지게 되는데 이는 다형성을 학습하면서 설명을 할 예정이다.

상속과 메서드오버라이딩

  • 메서드 오버라이딩

    위에서 설명했지만, 다시 설명하자면 상속받은 기능을 자식이 재정의 하는 것을 메서드 오버라이딩이라고 한다.
    또한, 오버라이딩은 컴파일러가 @Override 와 같이 애노테이션을 통해 확인할 수 있기 때문에 오버라이딩을 한다면 앞에 @Override를 달아주어서 컴파일러가 메서드 오버라이딩을 놓치는 실수를 사전에 방지해주어야 한다.

    • 메서드 오버라이딩 조건
      메서드 오버라이딩에는 여러 조건이 있지만, 주요 조건만 알아볼 예정이다.
    1. 접근 제어자 : 오버라이딩 메서드의 접근 제어자는 상위 클래스의 메서드보다 더 제한적이어서는 안된다.
    2. 예외 : 상위 클래스의 메서드보다 더 많은 체크 예외를 throws로 선언할 수 없다.
    3. static, final, private 키워드가 붙은 메서드는 오버라이딩할 수 없다.
      static : 클래스 레벨에서 작동하므로 인스턴스 레벨에서 사용하는 오버라이딩은 의미가 없다.
      final : 메서드는 재정의를 금지한다.
      private : 해당 클래스에서만 접근이 가능하므로, 하위 클래스에서는 보이지 않는다.
    4. 생성자 오버라이딩 : 생성자는 오버라이딩 할 수 없다.

super 참조

  • super 키워드

    부모와 자식의 필드명이 같거나 메서드가 오버라이딩 되어 있다면, 자식에서 부모의 필드나 메서드를 호출할 수 없다. 이때 super 키워드를 사용하면 부모를 참조할 수 있다.

    public class Parent {
    		public String name = "엄마";
       		public void hello() {
       				System.out.println("안녕~");
            }
     }
    public class Child extends Parent {
    		public String name = "자식";
         
         	@Override
            public void hello() {
         		System.out.println("안녕하세요");
    		}
    		
         	public String familyName() {
         		return this.name + " " + super.name;
            }
            
    		public String familyHello() {
     	    	this.hello();
         	    super.hello();
            }
     }

    위와 같이 super 키워드를 생성할 수 있고, 또한 앞에서 설명했던 this() 생성자 호출도 super() 생성자를 통해 부모 타입의 생성자를 호출할 수 있고 자식에서는 필수로 해야 하지만, 파라미터가 없는 경우 생략이 가능하다.

profile
백엔드 개발자취

0개의 댓글