생성자
예제 1
class Calculator {
int left, right;
public Calculator(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);
}
}
를 보면
클래스 이름과 같은 메서드를 이용하여 초기화할 수 있다.
public Calculator(int left, int right){
this.left = left;
this.left = right;
}
이 class 이름과 같은 메서드를 생성자(constrctor)라고 한다.
생성자의 약속&역할
이 클래스가 생성될 때, 자동으로 클래스의 이름이 같은 생성자가 실행되도록 약속되어 있다.
이 생성자는 다른 어떤 메서드보다 빨리 실행되도록 되어 있다.
이 생성자를 이용하여 초기화 작업의 사용될 수 있다.
상속과 생성자
상속의 장점
- 코드의 중복을 제거
- 부모가 만든 내용을 자식이 또 만들 필요가 없다.(재활용성)
- 유지보수 편해짐
- 그 클래스가 가지고 있는 중요한 임무를 제외하고는 부모가 역할을 가지고 있기에 가독성 증가에 효과도 존재한다.
public class ConstructorDemo {
public ConstructorDemo(int param1){}
ConstructorDemo c = new ConstructorDemo();
}
만약 생성자를 만들었는데, 다음과 같이 생성자의 매개변수가 있다.
그렇다면 이 생성자는 기본생성자가 아니라는 뜻이다.
그래서 위와, 같이 인스턴스화하면 에러가 발생한다.
일단 자바는
public class ConstructorDemo {
public static void main(String[] args) {
ConstructorDemo c = new ConstructorDemo();
}
}
위와 같다면, CalculatorDemo는 어떠한 생성자도 존재하지 않는 상태입니다.
이렇다면 자바는 자동적으로 기본생성자를 스스로 만듭니다.
※ 기본생성자는 이 클래스의 이름과 같으면서 매개변수가 없는 메서드가 기본생성자입니다.
또한 내용이 비어있습니다.
그렇다면
ConstructorDemo c = new ConstructorDemo(); 는
기본생성자를 알아서 만들어주기 때문에 사용이 가능합니다.
하지만
public class ConstructorDemo {
public ConstructorDemo(int param1){}
ConstructorDemo c = new ConstructorDemo();
}
과 같이 매개변수가 있는 생성자를 명시적으로 만들게 되면, 자바는 자동으로 기본 생성자를 만들지 않습니다.
위와 같이, ConstructorDemo c = new ConstructorDemo();라고 선언하면
해당 class에는 인자가 없는 기본 생성자는 존재하지 않고, 자바 또한 기본생성자를 만들어주지 않기 때문에
에러가 발생합니다.
해결방법은
public class ConstructorDemo {
public ConstructorDemo(){}
public ConstructorDemo(int param1){}
ConstructorDemo c = new ConstructorDemo();
}
처럼 기본 생성자를 추가해 주면 해결할 수 있습니다.
여기서 상속과 생성자의 연관관계를 이해해야 합니다.
자식클래스(하위클래스)를 인스턴스화할 때,
자식클래스의 생성자를 호출하기 전에 상위클래스의 "기본생성자"를 호출하도록 약속되어 있다.
이때, 부모 생성자가 기본생성자가 아닌, 매개변수가 있는 생성자를 사용할 경우,
JVM은 그 생성자를 보고 기본생성자를 생성하지 않기로 되어 있다.
즉, 하위클래스가 상속을 받을 때 상위클래스에 있는 기본생성자를 호출해야 하는데 그 기본생성자가 존재하지 않으므로 에러가 발생하는 것이다.
=> 따라서 이 문제를 해결하는 가장 간단한 방법은 부모 클래스의 기본생성자를 만든다.
자식 클래스의 생성자가 호출될 때 자바는 기본적으로 부모클래스의 기본생성자를 호출한다
"왜 기본생성자를 호출할려고 시도하나요?"
ans: 자바에서 기본생성자를 호출하려는 시도는 상속과 객체 생성의 원칙을 위함이다.
- 객체 생성: 객체가 생성될 때는 해당 클래스의 생성자가 호출됩니다.
- 클래스 상속: 자식 클래스가 부모 클래스를 상속받을 때, 하위클래스는 상위클래스의 멤버(필드, 메서드)를 물려받습니다. 이를 통해 높은 재사용성과 계층적 구조를 구축합니다.
이는 자바의 객체지향 언어의 역할을 부여한다.
상속관계가 이루어질 때 "부모 클래스의 생성자 호출" 두 가지 이유로 중요합니다.
1. 상속된 멤버 초기화: 자식 클래스의 객체를 생성할 때, 부모 클래스의 멤버들도 초기화되어야 합니다.
부모클래스와 연관이 있는 클래스를 자식클래스로 상속받기에, 부모클래스도 생성자를
이용하여 초기화하여야 합니다.
2. 클래스 계층 구조 유지: 클래스가 상속 계층 구조를 논리적인 관계로 유지하려면, 부모클래스부터 순차적으로 초기화되어야 합니다.
따라서 기본 생성자를 호출하려는 것은 "상속 관계를 유지"하며 "객체 초기화"를 올바르게 처리하기 위한 방식입니다.
이와 별개로 부모 클래스에 기본생성자가 없는 경우에도 super() 키워드를 이용하여 부모의 매개변수를 사용한 생성자가 있다면 super(); 키워드로 호출하여 문제없이 동작이 가능합니다.
부모 클래스
class Calculator {
int left, right;
public Calculator(){}
public Calculator(int left, int right){
this.left = left;
this.right = right;
}
자식 클래스
class SubstaractionalbleCalculator extends Calculator {
public SubstaractionalbleCalculator(int left, int right){
this.left = left;
this.right = right;
}
public void substract(){
System.out.println(this.left - this.right);
}
}
main
public class CalcaulatorDemo4 {
public static void main(String[] args) {
SubstaractionalbleCalculator c1 = new SubstaractionalbleCalculator(10, 20);
}
}
이처럼 부모클래스의 기본 생성자를 추가함으로써 에러를 해결할 수 있다.
super 키워드
이때, 만약에 부모와 자식이 둘 다 생성자가 있는데 하는 역할이 같다면 (위의 예시처럼),
따로따로 쓴다면 유지보수나 재활용성의 문제가 생긴다.
그래서 역할이 같다면, 하위클래스(자식)에서 부모생성자를 호출해서 사용하면 된다.
그때 사용하는 것이 "super" 키워드이다.
super == 부모클래스를 의미한다.
super(); 라면 부모 클래스의 생성자를 의미한다.
class SubstaractionalbleCalculator extends Calculator {
public SubstaractionalbleCalculator(int left, int right){
super(left, right); // 같은거 일단 super를 이용해서 초기화
// 또한 상속이외에 자기자신의 생성자를 호출해야 한다면
// 자기자신이 필요한 생성자 코드를 여기에 추가로 넣는다.
// 상속받은 클래스가 해야 하는 작업을 할 수 있다.
// 또한 추가작업을 할때는
// super키워드를 먼저 쓰고 다음으로 추가적으로 초기화작업을 진행해야 한다.
}
따라서 위와 같이 바꿈으로써 유지보수와, 재활용성이 높은 코드를 만들 수 있다.
이때, 추가적인 초기화작업을 하고 싶다면
super키워드를 먼저 쓰고 다음으로 초기화를 진행해야 한다. (부모생성자가 먼저 선행되어야 한다.)
'CS🖥️ > OOP' 카테고리의 다른 글
[OOP] 오버라이딩 & 오버로딩 비교하기(핵심정리) (0) | 2023.09.02 |
---|---|
[OOP] 오버라이딩 (overriding) (0) | 2023.09.02 |
[OOP] 오버로딩 & 메서드 시그니처 (overloading & method signature) (0) | 2023.09.02 |