Inheritance(상속성)

1c2·2024년 1월 17일
0

JAVA

목록 보기
5/13

상속

  • 기존 클래스의 자산을 자식 클래스에서 재사용하기 위한 것

    • 상위 클래스의 생성자와 초기화 블록은 상속하지 않는다.
  • 상위 클래스의 멤버를 물려 받기 때문에 코드의 절감
    • 상위 클래스의 코드를 변셩하면 모든 하위 클래스에게도 적용 -> 유지 보수성 향상
  • 상속의 적용

    • extends 키워드 사용

    • 별도의 extends 선언이 없는 클래스들은 extends Object 가 생략됨

    • 따라서 모든 클래스에는 Object 클래스에 정의된 메서드가 있음

      // extends Object가 생략됨
      public class Person{
          String name;
      
          void eat(){
              System.out.println("냠");
          }
          void jump(){
              System.out.println("폴짝");
          }
      }
      
      public class SpiderMan extends Person{
          boolean isSpider;
          void fireWeb(){}
      }

다양한 상속관계

  • 상속의 관계는 is a(kind of) 관계라고 함
    • Person is a Object, Spider is a Person, Employee is a Person

단일 상속 (Single Inheritance)

  • 다중 상속의 경우 여러 클래스이 기능을 물려받을 수 있으나 관계가 매우 복잡해짐
    • 동일한 이름의 메서드가 두 상위 클래스에게 모두 있다면 하위 클래스는 어떤 메서드를 쓸 것인가?
    • 고로 Java에서는 단일 상속만 지원
    • 대신 interface와 포함 관계 (has a)로 단점 극복

포함 관계

SpiderMan이 아래 Spider 클래스의 거미줄(fireWeb)을 사용할 수 있게 하자

public class Spider {
	void jump() {
		System.out.println("깡총거미");
		
	}
	void fireWeb() {
		System.out.println("슉슉~");
		
	}
}
  • 상속 이외에 클래스를 재활용 하는 방법
    • 2개 이상의 클래스에서 특성을 가져올 때 하나는 상속, 나머지는 멤버 변수로 처리
public class SpiderMan extends Person{
    boolean isSpider;
    //has a 관계
    Spider spider; //reference type => null이 초기값
    public SpiderMan() {
    	this.spider = new Spider();
    }
    void fireWeb(){
    	if(isSpider) {
    		spider.fireWeb();
    	}else {
    		System.out.println("지금은 안됨");
    	}
    }
}

메서드 오버라이딩

  • 조상 클래스에 정의된 메서드를 자식 클래스에서 적합하게 수정하는 것

스파이더맨은 Person을 상속받지만 Spider의 jump()를 사용하고 싶다.

 public class Person{
 	void jump(){
    	System.out.println("인간 점프");
    }
 }
 
 public class Spider {
	void jump() {
		System.out.println("깡총거미");
	}
}

public class SpiderMan extends Person{
    boolean isSpider;
    //has a 관계
    Spider spider; 
    public SpiderMan() {
    	this.spider = new Spider();
    }
    void fireWeb(){ ... }
    void jump(){
    	if(isSpider){
        	spider.jump();
        } else{
        	System.out.println("인간 점프~")
        }
    
    }
}

SpiderMan이 jump를 사용하면 Person의jump()를 하는 게 아닌 SpiderMan의 jump()를 사용한다.
=> override

오버라이딩의 조건

  • 메서드 이름이 같아야 한다.
  • 매개 벼누의 개수, 타입, 순서가 같아야 한다.
  • 리턴 타입이 같아야 한다.
  • 접근 제한자는 부모 보다 범위가 넓거나 같아야 한다.
  • 조상보다 더 큰 예외를 던질 수 없다.

@Override 어노테이션을 이용하여 이러한 조건을 만족하는지 확인할 수 있다.

super키워드

  • this를 통해 멤버에 접근했듯이 super를 통해 조상 클래스 멤버 접근

    • super.을 이용해 조상의 메서드 호출로 조상의 코드 재사용

      void jump(){
      	if(isSpider){
          	spider.jump();
          } else{
          	System.out.println("뛰기");
          }
      }
      
      void jump(){
      	if(isSpider){
          	spider.jump();
          } else{
          	super.jump();
          }
      }
    • jump()에서 아래 jump()로 수정하여 조상의 코드를 재사용 할 수 있다.

  • 변수의 scope

    • 사용된 위치에서점점 확장해가며 처음 만난 선언부에 연결됨

    • method 내부 -> 해당 클래스 멤버 변수 -> 조상 클래스 멤버 변수

      class Parent {
      	String x = "parent";
      }
      class Child extends Parent {
        String x = "child";
      
        void method() {
            String x = "method";
            System.out.println("x : " + x); //가까운 곳에서 찾아서 출력 (method)
            System.out.println("this.x : " + this.x); //전역변수 출력 (child)
            System.out.println("super.x : " + super.x); //조상의 전역변수 출력 (parent)
        }
      }
      public class ScopeTest {
      
        public static void main(String[] args) {
            Child child = new Child();
            child.method();
        }
      }
  • this()가 해당 클래스의 다른 생성자를 호출하듯 super()는 조상 클래스의 생성자 호출

    • 조상 클래스에 선언된 멤버들은 조상 클래스의 생성자에서 초기화가 이뤄지므로 이를 재활용
    • 자식 클래스에 선언된 멤버들만 자식 클래스 생성자에서 초기화
  • super()는 자식 클래스 생성자의 맨 첫 줄에서만 호출 가능

    • 즉 생성자의 첫 줄에만 this() 또는 super()가 올 수 있다.
  • 명시적으로 this() 또는 super()를 호출하지 않는 경우 컴파일러가 super삽입

    • 결론적으로 맨 상위의 Object까지 객체가 다 만들어지는 구조

코드를 다음과 같이 수정할 수 있다.

public class Person{
	public Person(String name) {
		// super() 가 생략되어 있음 => 컴파일러가 생성
		this.name = name;
	}
	public Person() {}
    String name;

    void eat(){
        System.out.println("냠");
    }
    void jump(){
        System.out.println("인간 점프");
    }
}

public class SpiderMan extends Person{
    boolean isSpider;
    //has a 관계
    Spider spider; //reference type => null이 초기값
    public SpiderMan() {
    	this("피터파커");
    }
    public SpiderMan(String name) {
    	super(name); // 조상(Person) 생성자
    	this.spider = new Spider();
    }
    void fireWeb(){
    	if(isSpider) {
    		spider.fireWeb();
    	}else {
    		System.out.println("지금은 안됨");
    	}
    }
}

public class SpiderManTest {
	public static void main(String[] args) {
		SpiderMan sman = new SpiderMan();
		sman.isSpider = true;
		sman.jump();
		sman.fireWeb();
		System.out.println(sman.name);
	}
}

위 SpiderManTest를 실행하면

인간 점프
슉슉~
피터파커

가 출력된다. 어떤 과정으로 해당 출력문이 생성되는지 따라가보도록.

Annotation

  • 사전적 의미 : 주석
  • 컴파일러, JVM, 프레임워크 등이 보는 주속
  • 소스코드에 메타 데이터를 삽입하는 형태
    • 소스코드에 메타 데이터를 삽입하는 형태
    • 코드에 대한 정보 추가 -> 소스 코드의 구조 변경, 환경 설정 정보 추가 등의 작업 진행
  • 기본 annotation의 예
    • @Depricated :
      컴파일러에게 해당 메서드가 deprecated 되었다고 알려줌
      이 api말고 다르 api 쓰라고 알려줌
    • @Override :
      컴파일러에게 해당 메서드는 override한 메서드 임을 알려줌
      @Override 가 선언된 경우 반드시 super class에 선언 되어있는 메서드 여야 함
    • SuppressWarnings :
      컴파일러에세 사소한 warning을 신경쓰지 말라고 알려줌

Package

  • 일반적인 package naming 룰
    • 소속, 프로젝트, 용도
    • com.ssafy.hrm.common, ...

import

  • 다른 패키지에 선언된 클래스를 사용하기 위해 키워드

    • 패키지와 클래스 선언 사이에 위치
    • 패키지와 달리 여러번 선언 가능
  • 선언 방법

    • import 패키지명.클래스명
    • import 패키지명.*
    • java에서는 동적 로딩을 통해 필요한 매서드만 import한다.
    • 클래스명은 대문자로 시작하는게 관행

    몇글자 쓰고 ctrl + shift + o 하면 자동으로 추가

    제한자 (modifier)

  • 클래스, 변수, 메서드 선언부에 함께 사용되어 부가적인 의미 부여

  • 종류

    • 접근 제한자 ( 중복 불가 / 순서 상관 없음)

      • public : 누구나 다 사용 가능
      • protected : 같은 패키지 / 다른 패키지의 자손
      • (default = package)
      • private : 내 클래스만 사용 가능
    • 그 외 제한자 ( 중복 허용 / 순서 상관 없음 )

      • static : 클래스 레벨의 요소 설정
      • final : 요소를 더 이상 수정할 수 없게 함
      • abstract : 추상 메서드 및 추상 클래스 작성
      • synchronized : 멀티스레드에서의 동기화 처리

    final

  • 마지막, 더 이상 바뀔 수 없음

  • final class - 더 이상 확장할 수 없음 : 상속 금지 -> 오버라이드 방지

    • 상속받아서 확장하는 것 방지
    • 대표적인 final class : String, Math, ...
  • final method - 더 이상 재정의할 수 없음

    • overrideing 금지
  • final variable - 더 이상 값을 바꿀 수 없음 (상수)

    • Blank final - 값이 할당되지 않은 멤버 변수
      • final 멤버 변수에 초기 값이 할당되어버리면 모든 객체는 같은 값을 사용해야 함
      • 객체가 생겅되면 값을 변경할 기회가 없기 때문에 반드시 생성자에서 1회 초기화 가능
  • static final

    • 단지 final만 있으면 객체마다 같는 값으로 공용성이 없음
    • 진정한 상수는 객체와 무관하게 모두가 공용하는 값 (Math.PI, Math.E, ..)

0개의 댓글