본문 바로가기
생활코딩/JAVA

생활코딩 - JAVA (상속, 오버로딩, 오버라이딩)

by Love of fate 2020. 12. 5.
728x90
반응형

[상속]

상속 : 무엇인가를 물려준다.
어떤 연관된 변수와 메소드가 함께 담겨있는 덩어리를 객체라고 할 수 있다.
새로운 객체가 기존 객체가 갖고 있는 변수나 메소드를 그대로 물려받으면서 필요에 따라 자신만의 새로운 변수와 메소드를 추가하거나 기존의 변수와 메소드를 변경해서 사용할 수 있게 하는 것을 상속이라고 한다.

경우에 따라 새로운 메소드를 추가하기가 어렵거나 불가능할 떄가 있다.

객체를 자신이 만들지 않았을 때, 그래서 소스를 변경할 수 없다. 변경하면 소스를 업데이트하면 메소드가 덮어쓰게 되며 사라진다.
이러한 문제가 일어나지 않도록 지속적으로 코드를 관리해야한다.

객체가 다양한 곳에서 활용되고 있는데, 메소드를 추가함ㄴ 다른곳에서는 불필요한 기능이 포함될 수 있다.
이것은 자연스럽게 객체를 사용하는 입장에서 몰라도 되는 것까지 알아야 하는 문제가 된다.

상속이 생겨난 이유
기존 객체를 그대로 유지하면서 어떤 기능을 추가하는 방법이 없을 지 고민하게 되는데, 그렇게 해서 도출된 결과가 바로 상속이다.

부모객체(상위 클래스, 기초 클래스)
: 기존 객체가 기능을 물려준다는 의미

자식객체(하위 클래스, 유도 클래스)
: 기존 객체를 토대로 만들어진 새로운 객체가 기존객체를 물려받음
기존 객체가 갖고 있었던 변수나 메소드를 그대로 가지고 있으면서 동시에 자식 객체를 사용하는 맥락에서 필요한 변수나 메소드를 추가적으로 부여하거나 기존 부모 객체가 가지고 있었던 변수와 메소드의 동작 방법을 변경할 수 있도록 고안된 방법

기존 코드를 수정하지 않는다는 것이 중요!

상속 : extend (클래스 확장)
하위 클래스에서 확장하기 때문에 자신이 정의하지 않은 다른 메소드를 마치 자신이 가지고 있는 것처럼 호출할 수 있는 것

class MultiplicationableCalculator extends Calulator {
public void multiplication(){
System.out.println(this.left * this.right);
}
}

MultiplicationableCalculator 클래스가 있는데 이 클래스를 상속하는 또 다른 클래스를 만들 수 있다.

※ 장점
코드의 중복을 제거할 수 있다.
부모가 이미 만든 기능을 자식이 또 새로 만들 필요가 없다는 점
재활용성이 높다.
부모가 만든 코드를 자식이 사용할 수 있다는 점

유지보수가 편리
부모가 만든 코드에서 어떤 개선이 일어나면 해당 부모 클래스를 상속하는 모든 클래스에서 개선의 효과가 적용되기 때문에 유지보수가 편리하다.

가독성이 높아진다.
특정 자식 클래스가 가진 중요한 임무를 제외한 나머지 부분은 부모에게 의존 할 수 있다.



[상속과 생성자]

기본생성자
생성자는 객체를 생성하는 역할을 하고 그 객체를 생성하는 과정에서 최초로 수행해야 할 일이 있다면 그것을 할 수 있는 메소드를 정의할 기회를 제공한다.

ConstructorDemo 클래스에 생성자를 선언했는데 그 생성자에 매개변수가 있다는 것은 이 생성자가 기본 생성자가 아니라는 뜻이다.
이 상태에서 클래스를 인스턴스화하면 에러가 발생한다.

package org.opentutorials.javatutorials.Inheritance.example4;
public class ConstructorDemo {
public static void main(String[] args) {
ConstructorDemo c = new ConstructorDemo();
}
}


매개변수가 있는 생성하기 있을 때는 자동으로 기본 생성하는 만들어주지 않는다.
따라서 위의 예제는 존재하지 않는 생성자를 호출하고 있다. 이 문제를 해결하기 위해서는 아래와 같이 기본생성자를 추가해줘야 한다.

package org.opentutorials.javatutorials.Inheritance.example4;
public class ConstructorDemo {
public ConstructorDemo(){}
public ConstructorDemo(int param1) {}
public static void main(String[] args) {
ConstructorDemo c = new ConstructorDemo();
}
}

[SUPER]

package org.opentutorials.javatutorials.Inheritance.example2;

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 SubstractionableCalculator(int left, int right) {
this.left = left;
this.right = right;
}

public void substract() {
System.out.println(this.left - this.right);
}
}

public class CalculatorConstructorDemo4 {
public static void main(String[] args) {
SubstractionableCalculator c1 = new SubstractionableCalculator(10, 20);
c1.sum();
c1.avg();
c1.substract();
}
}

Subtractionablecalculator 클래스를 인스턴스화하면 Subtractionablecalculator의 생성자를 호출하기전에 이 클래스의 부모 클래스인 Calculator의 생성자를 자동ㅇ로 호출하도록 약속돼 있습니다.
부모 클래스에서 매개변수가 있는 생성자를 선언하면 자바는 자동으로 기본생성자를 생성하지 않기 때문에 하위 생성자는 기본 생성자를 호출할 수 없어서 에러가 발생한다.

매개변수가 없는 생성자를 사용하고 싶을 경우, 부모클래스의 기본생성자를 만들면 에러는 발생하지 않는다. 또는
부모 클래스와 하위 클래스가 동일한 생성자를 가지고 있는데 하위 클래스에서도 똑같이 부모 클래스와 같은 일을 하고 있다. 이것은 주ㅇ복이다.
다시 말해 부모 클래스에서도 생성자에 this.left와 this.right 값을 지정하는 로직이 ㅡㄹ어 있고 하위 클래스에서도 생성자에 독같은 로직이 들어 있다면 중복이라는 것이다.
즉, 유지보수나 코드 재활용이 어렵고 코드의 중복과 같은 문제가 발생한다.

상위 클래스와 하위 클래스에 각각 생성자가 잇는데 생성자가 하는 역할이 같다면 하위 클래스에서 상위 클래스에 있는 생성자와 똑같은 코드를 복사하는 대신 하이ㅜ 클래스가 생성될 대 상위 클래스의 생성자를 호출할 수 있다면 이 같은 문제를 해결할 수 있을 것이다.

package org.opentutorials.javatutorials.Inheritance.example3;

class Calculator {
int left, right;

public Calculator(){}

public Calculator(int left, int right){
this.left = left;
this.right = 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 SubstractionableCalculator(int left, int right) {
super(left, right);
}

public void substract() {
System.out.println(this.left - this.right);
}
}

public class CalculatorConstructorDemo5 {
public static void main(String[] args) {
SubstractionableCalculator c1 = new SubstractionableCalculator(10, 20);
c1.sum();
c1.avg();
c1.substract();
}
}

Super 키워드는 부모 클래스를 의미한다.여기에 ()를 붙이면 부모 클래스의 생성자를의미하게 된다. 부모 크래스의 기본생성자가 없어져도 오류가 발생하지 않는다.

하위 클래스의 생성자에서 Super를 사용할 때 주의 할 점은 Super가 가장 먼저 나타나야 한다는 점이다. 즉, 부모가 초기화 되기 전에 자식이 초기화되는 일을 방지해 위한 정책이라고 생각하자.

[오버라이딩]
오버리이딩이란 ‘재정의’ ‘새롭게 정의한다’ 라는 득이고 상속과 아주 밀접한 관계에 있는 개념이다.

상속은 부모 클래스가 있고 자식 클래스가 있을 대 부모 클래스에 이쓴 특정한 변수나 도는 메소드를 자식 클래스가 그대로, 마치 자식 클래스에 정의돼 잇는 것처럼 사용할 수 있게 하면서 동시에 자식 클래스에 어떤 특정한 메소드나 변수를 추가해서 부모 클래스가 가진 기능보다 더 많은 기능을 제공한다는 개념이다.

ex)
기존의 calculator 클래스에는 sum() 메소드가 있었는데 Clculator를 상속한 Subtractionable Calculator클래스에서 부모가 이미 갖고 잇는 메소드인 sum()을 재정의 한다.
그런데 subtractionable Calculator 클래스의 sum()을 호출하면 재정의한 sum()을 호출하면 재정의한 sum()을 사용하게 된다.

부모 클래스도 가지고 있고 자식클래스도 가지고 있을 때는 부모 클래스가 가진 메소드는 무시되고 자식 클래스가 가진 메소드가 실행된다는 것이 바로 메소드 오버라이딩 이다.

하위 클래스에서 sum() 메소드를 구현한다는 것은 해당 부모 클래스가 가진 sum() 메소드보다 높은 우선순위를 설정한다는 것이다. 이 같은 기법을 알아두면 나중에 프로그래밍할 때 유용할 것이다.

[오버라이딩을 하기 위한 제약사항]
부모클래스의 메소드 형식과 자식 클래스의 메소드 형식이 불일치 하는 경우 오버라이딩 할수 없다.

오버라이딩 하려면 아래의 조건을 충족해야 한다.(메소드의 형식, 메소드의 서명(signature))
1. 메소드 이름
2. 메소드 매개변수의 개수와 데이터 타입, 순서
3. 메소드의 반환 타입

부모클래스의 메소드와 자식 클래스의 메소드와 자식 클래스의 메소드가 서로 서명이 일치해야만 오버라이딩된다고 할 수 있다.

super 키워드를 이용하면 부모 클래스의 메소드가 가진 기능을 그대로 가져다 쓰면서 동시에 하위 클래스에서 필요로 하는 기능을 하나의 메소드 안에 추가할 수 있다.

[오버로딩]
오버로딩이란 클래스에 메소드를 정의할 때 이름이 같지만 서로 다른 매개변수 혀익을 지닌 메소드를 여러개 정의할 수 있는 방법이다.

이름은 같지만 매개변수가 다를 경우 무제가 나지않은 것이 바로 오버로딩의 개념이다.
이름이 같아도 매개변수 형식이나 매개변수 형식이나 매개변수 개수가 다르면 오버로딩이 가능해 지는 것이다.
자바 입장에서는 메소드의 이름이 같더라도 매개변수의 개수나 데이터 형식이 다르면 다른 메소드로 인식하게 된다. 이것이 바로 메소드 오버롣이다.

[오버로딩의 규칙]
메소드 오버로딩에서는 메소드의 매개변수 형식이 같더라도 반환형(반환값)이 달라지면 오버로딩이 되지 않고 오류가 발생한다.

반환형은 메소드를 사용하는 단계에서 알려줄 수 있는 정보가 아니라 메소드를사용한 결과이기 때문에 반환형을 기준으로 어떤 메소드를 호출할 것인지를 자바에게 알려줄 방법이 없다.
이 같은 모호함을이 발생하기 때문에 프로그램 입장에서는 에러를 발생시켜 그러한 모호함을 미리 방지하는 것이다.

* 오버로딩의 경우 메소드의 이름과 반환값은 같아야 하지만 매개변수는 달라야 한다.

* 오버로딩과 오버라이딩이 헷갈리는 이유는 아마 over라는 말이 공통분모로 들어가 있기 때문일 것이다.
 - riding은 '올라타다', 즉 부모가 정의한 메소드를 자식 클래스에서 '올라탄다'라는 의미에서 riding이라는 말을 쓴다고

   생각

 - loading은 이름은 같지만 다른 매개변수를 가지고 있는 여러 메소드를 클래스로 '로딩한다'라고 생각

이렇게 생각한다면 조금 덜 셋갈릴 것이다.

728x90
반응형

'생활코딩 > JAVA' 카테고리의 다른 글

생활코딩 - JAVA (접근 제어자)  (0) 2020.12.19
생활코딩 - JAVA (패키지)  (0) 2020.12.13
생활코딩 - JAVA (클래스패스)  (0) 2020.12.13
(2) JAVA : 변수  (0) 2020.10.25
(1) JAVA : 숫자와 문자  (0) 2020.10.25