[JAVA] 상속

Coastby·2022년 8월 2일
0

JAVA

목록 보기
13/33

상속이 필요한 이유

객체에 메소드를 추가하기 어려운 경우가 있다.

  1. 객체를 자신이 만들지 않았다. 그래서 소스를 변경할 수 없다. 변경할 수 있다고 해도 원 소스를 업데이트 하면 메소드 substract이 사라진다. 이러한 문제가 일어나지 않게 하기 위해서는 지속적으로 코드를 관리해야 한다.
  2. 객체가 다양한 곳에서 활용되고 있는데 메소드를 추가한다면 다른 곳에서는 불필요한 기능이 포함될 수 있다. 이것은 자연스럽게 객체를 사용하는 입장에서 몰라도 되는 것까지 알아야 하는 문제가 된다.

기존의 객체를 그대로 유지하면서 어떤 기능을 추가하는 방법

기존의 객체는 기능을 물려준다는 의미에서 부모 객체 (super class)가 되고 새로운 객체는 기존 객체의 기능을 물려받는다는 의미에서 자식 객체 (base class, derived class)가 된다.

class Calculator {
    int left, right;
 
    public void setOprands(int left, int right) {
        this.left = left;
        this.right = right;
    }
 
    public void sum() {
        System.out.println(this.left + this.right);
    }
 
    public void avg() {
        System.out.println((this.left + this.right) / 2);
    }
}
 
class SubstractionableCalculator extends Calculator {
    public void substract() {
        System.out.println(this.left - this.right);
    }
}
 
public class CalculatorDemo1 {
 
    public static void main(String[] args) {
 
        SubstractionableCalculator c1 = new SubstractionableCalculator();
        c1.setOprands(10, 20);
        c1.sum();
        c1.avg();
        c1.substract();
    }
 
}

//
30
15 
-10

자식 클래스 (SubstractionableCalculator)에 내용이 없으면 부모 클래스 (Calculator)에서 내용을 찾게 된다. 따라서 부모 클래스에서 정의한 메소드들을 사용할 수 있게 된다.

상속의 장점

  1. 코드 중복을 제거할 수 있다.
  2. 부모 클래스가 개선되면 자식 클래스에게도 혜택이 돌아간다. 따라서 유지/보수가 편리하다
  3. 재활용성 및 가독성 증가

대신 복잡도가 증가하기 때문에 이를 보완할 수 있는 기술들이 필요하다.

  • 클래스 다이어그램

상속과 생성자

자기 자신을 인스턴스화할 수 있다.

생성자에 파라미터가 있다는 것은 기본 생성자가 아니라는 것이다. 자바는 이때 기본 생성자를 만들지 않는다.

하위 클래스의 인스턴스를 만들때, 하위 클래스보다 상위 클래스의 기본 생성자를 먼저 호출한다. 상위 클래스에 매개변수가 있는 생성자를 만들면 자동적으로 기본 생성자가 생기지 않아서 에러가 없으려면 상위 클래스에 기본 클래스를 만들어줘야한다.

상위 클래스와 하위 클래스에 각각 생성자가 있고 하는 일이 같을 때, super(); 를 사용한다. super()는 상위 클래스를 의미하고 괄호안의 인수를 매개변수로 전달한다. 이를 이용하여 하위 클래스가 사용하기 전에 상위 클래스의 초기화가 필요할 때 super()를 이용할 수 있다.

이렇게 하면 상위 클래스의 기본 생성자가 없어져도 오류가 발생하지 않는다.

class Calculator {
    int left, right;
     
    public Calculator(){}
     
    public Calculator(int left, int right){
        this.left = left;
        this.right = right;
    }
.
.
.
class SubstractionableCalculator extends Calculator {
    public SubstractionableCalculator(int left, int right) {
        super(left, right);
    }
.
.
.

하위 클래스의 초기화코드는 super()보다 뒤에 나와야 한다. 상속을 받기 위해서는 상위 클래스의 초기화가 먼저 이루어져야 하위 클래스의 초기화가 가능하기 때문이다.

👉 정리

  • 하위 클래스가 생성될 때는 상위 클래스의 생성자가 먼저 호출된다.
  • 상위 클래스에 생성자 코드가 따로 없으면 super()로 상위 클래스의 디폴트 생성자가 자동을 호출된다.
  • 상위 클래스에 디폴트 생성자가 없고 매개변수가 있는 생성자만 있을 경우 super() 에 매개변수를 추가하여, 매개변수가 있는 상위 클래스의 생성자를 직접 호출해야 한다.

Overriding

상속은 상위 클래스의 기능을 하위 클래스에게 물려주는 기능이다. 상위 클래스에 정의한 메서드가 하위 클래스에서 구현할 내용과 맞자 않을 경우에 하위 클래스에서 이 메서드를 재정의할 수 있다. 이를 메서드 오버라이딩 (method overriding)이라고 한다.

하위 클래스에서 상위 클래스와 오버라이딩하면 부모 클래스로부터 물려 받은 기본 동작 방법을 변경하는 효과를 갖게 된다. 상위 클래스의 메소드는 무시되고 하위 클래스의 메소드가 작동한다. 기본동작은 폭넓게 적용되고, 예외적인 동작은 더 높은 우선순위를 갖게하고 있다.

class Calculator {
    int left, right;
 
    public void setOprands(int left, int right) {
        this.left = left;
        this.right = right;
    }

//실행 안됨 
    public void sum() {
        System.out.println(this.left + this.right);
    }
.
.
.
class SubstractionableCalculator extends Calculator {

//실행됨     
    public void sum() {
        System.out.println("실행 결과는 " +(this.left + this.right)+"입니다.");
    }

//결과
//실행 결과는 30입니다.

오버라이딩을 하기 위해서는 아래의 조건을 충족시켜야 한다.

  • 메소드의 이름
  • 메소드 매개변수의 숫자와 데이터 타입 그리고 순서
  • 메소드의 리턴 타입

위와 같은 메소드의 형태를 정의하는 사항들을 통틀어서 메소드의 서명 (signature)라고 한다. 상위-하위 메소드 간의 서명이 다르면 에러가 발생한다.

오버라이딩 생성하기

하위 클래스에 우클릭 - source - override/implement.. 클릭 후 메소드 선택하면 자동으로 아래와 같이 생성된다.

.
.
	public void avg() {
			System.out.println((this.left + this.right) / 2);
		}
.
.
.
class SubstractionableCalculator extends Calculator {
	@Override
	public void avg() {
		// TODO Auto-generated method stub
		super.avg();

//오버라이딩했지만 상위 클래스와 같은 기능을 함

👉 Annotation
애노테이션은 영어로 주석이라는 의미이다. @ 기호를 사용하여 @애노테이션 이름 으로 표현한다. 자바에서 제공하는 애노테이션은 컴파일러에게 특정한 정보를 제공해 주는 역할을 한다. 예를 들어 @Override는 이 메서드가 재정의된 메서드임을 컴파일러에게 알려준다. 만약 메서드의 선언부가 다르다면 컴파일 오류가 발생하여 프로그래머의 실수를 막아준다. 주로 사용하는 표준 애노테이션은 다음과 같다.

Overloading

이름은 같지만 시그니쳐는 다른 메소드를 중복으로 선언할 수 있는 방법을 메소드 오버로딩 (method overloading)이라고 한다.

class OverloadingDemo2 {
	void A () {System.out.println("A");}
	void A (int arg1) {System.out.println("arg1");}
	String A (String arg1) {return arg1;}
	
	int add (int a, int b) {
		return a + b;
	}
	int add (int a, int b, int c) {
		return a + b + c;
	}
	double add (double a,  double b) {
		return a + b;
	}
}

public class OverloadingDemo {
	
	public static void main(String[] args) {
		OverloadingDemo2 od = new OverloadingDemo2();
		od.A();
		od.A(1);
		System.out.println(od.A("hoon"));
		
		System.out.println(od.add(1, 2, 3));
	}
}

메소드 이름을 여러개를 만들어야하는 수고로움이 없어진다.

다른 매개변수를 받으면 다른 리턴값을 가질 수 있다.

같은 매개변수를 받으면서 다른 리턴값을 가질 수는 없다

//안 됨
void A () {System.out.println("A");}
String A () {return arg1;}
profile
훈이야 화이팅

0개의 댓글