티스토리 뷰
⩤ 상속
객체 지향을 통해 달성하고자 하는 목표 중에서 가장 중요한 것은 당연히 기능을 재활용하는 것이다. 상속은 객체 지향의 재활용성을 극대화시킨 프로그래밍 기법이라고 할 수 있다. 또한 동시에 객체 지향을 복잡하게 하는 주요 원인이라고 할 수 있다.
상속: 물려준다.
어떤 객체가 있을 때 해당 객체가 갖고 있는 필드와 메서드를 다른 객체가 물려받을 수 있도록 한 것이 바로 상속이라고 한다.
기존의 객체를 유지하면서, 기능을 추가할 수 있는 방법이 바로 상속임
class C {
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 substractableCalculator extends C {
public void substract() {
System.out.println(this.left - this.right);
}
}
public class ScopeDemo {
public static void main(String[] args) {
substractableCalculator s = new substractableCalculator();
s.setOprands(10, 20);
s.sum();
s.avg();
s.substract();
}
}

클래스 다이어그램으로 이야기 한다고 한다.
s → 상속을 의미
c → 클래스를 의미
substractableCalculator라는 자식 클래스를 만든 것인데, 여기서 중요한 것은 extends를 사용한 뒤 상속할 클래스를 명시해야 한다. 그리고 만약에 위 코드를 코틀린으로 바꾸면 다음과 같다.
fun main(args: Array<String>) {
val c = substractableCalculator()
c.setOprands(10, 20)
c.sum()
c.avg()
c.substract()
}
open class C { // 코틀린에서는 상속을 하기 위한 class에 open을 붙여줘야함.
var left: Int = 0
var right: Int = 0
fun setOprands(left: Int, right:Int) {
this.left = left;
this.right = right;
}
fun sum() {
println(this.left + this.right)
}
fun avg() {
println((this.left + this.right) / 2)
}
}
class substractableCalculator: C() { // 자식 클래스가 상속받기 위해서는 ':'로 구분함.
fun substract() {
println(this.left - this.right)
}
}
보면 알겠지만, 문법은 매우 많이 동일하다. 차이점이 있다면, 굳이 메인 클래스를 만들지 않아도 main함수만 있다면 알아서 실행시킬 수 있다. 하나더 상속해보자.
class MultiplicationableCalculator extends C {
public void multiplication() {
System.out.println(this.left * this.right);
}
}
public class ScopeDemo {
public static void main(String[] args) {
MultiplicationableCalculator m = new MultiplicationableCalculator();
m.setOprands(10, 20);
m.multiplication();
}
}
class DivisionableCalculator extends MultiplicationableCalculator {
public void division() {
System.out.println(this.left / this.right);
}
}
public class ScopeDemo {
public static void main(String[] args) {
DivisionableCalculator d = new DivisionableCalculator();
d.setOprands(10, 20);
d.multiplication();
d.division();
}
}
위 2개의 코드를 보면 간접적으로든 직접적으로든 class C의 기능을 모두 상속받기 때문에, 상속한 뒤에 편리하게 추가하고 싶은 기능을 추가할 수 있다.
즉, 부모가 만든 기능을 자식이 또 만들 필요는 없는 것이다.
⩤ 상속과 생성자
생성자는 객체를 의미한다. 그 과정에서 해야 할 일들을 생성자 메소드에 지정해서 초기화 작업을 진행할 수 있다. 이번 수업을 이해하기 위해서는 기본 생성자의 성질에 대한 이해가 선행되어야 한다. (무지 중요하다는 의미)
다음 코드를 보면 좀 이상하다는 생각을 할 수 있다.
// 1
public class ContructorDemo {
public static void main(String[] args) {
ContructorDemo c = new ContructorDemo();
}
}
그렇다 자기 자신을 사용하고 있는 것이다. 근데 에러는 나지 않는다. 아무런 문제가 없다.
// 2
public class ContructorDemo {
public ContructorDemo(int params) {}
public static void main(String[] args) {
ContructorDemo c = new ContructorDemo();
}
}
다음 코드는 에러를 발생시킨다.
ContructorDemo클래스는 params라는 인자를 받으려고 한다. 이때 에러가 발생한다. 1번 코드의 경우 ContructorDemo는 자바가 기본생성자로 만들어주기 때문에 ContructorDemo c = new ContructorDemo();를 작성해도 아무런 문제가 발생하지 않는다. 하지만 2번 코드는 그렇지 않다. 자바에서는 ContructorDemo를로 다시 클래스를 할당했기 때문에 기본 생성자로 만들어주지 않는다. 따라서 2번 코드는 에러를 발생시킨다. 이 문제는 처음에 기본 생성자를 생성하지 않아서 생기는 문제이므로 생성자를 생성하면 문제는 해결된다. 다음과 같은 식으로 코드를 작성하면 에러는 사라진다.

결국에는 자바는 new ContructorDemo()는 public ContructorDemo(int params) {}가 아닌 public ContructorDemo() {}를 보고 생성자를 생성한다는 의미이다.
그렇다면, 생성자를 활용하여 초기화를 따로 시켜주지 않으려면, 어떻게 해야할까? 다음과 같이 코드를 작성하면 된다.
class SubstractableCalculator extends C {
public SubstractableCalculator(int left, int right) { // 이코드를 통해 생성자 초기화를 안할 수 있다.
this.left = left;
this.right = right;
}
public void substract() {
System.out.println(this.left - this.right);
}
}
public class ContructorDemo {
public static void main(String[] args) {
SubstractableCalculator s = new SubstractableCalculator(10, 20); // 다음과 같은 코드를 작성하면된다.
s.sum();
s.avg();
s.substract();
}
}
이때 부모 클래스에 기본 생성자가 생성되지 않았다면, 오류가 발생한다. 따라서 다음과 같이 코드를 작성하여 오류를 방지할 수 있다
class C {
int left, right;
public C(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 SubstractableCalculator extends C {
public SubstractableCalculator(int left, int right) {
super(left, right); // 얘가 받는다.
}
public void substract() {
System.out.println(this.left - this.right);
}
}
public class ContructorDemo {
public static void main(String[] args) {
SubstractableCalculator s = new SubstractableCalculator(10, 20);
s.sum();
s.avg();
s.substract();
}
}
super class를 잊지말자. 상위 클래스 초기화 하기 전에 뭘할건지 알려주는 것이다. 그리고 또 하나 중요한 것은 super 이후에 초기화 작업을 진행해야 한다.
'Spring > Java' 카테고리의 다른 글
| [Java] Overriding vs Overloading (0) | 2021.12.06 |
|---|---|
| [Java] 초기화와 생성자 (0) | 2021.12.02 |
| [Java] 유효범위 (0) | 2021.12.02 |
| [Java] 클래스 맴버와 인스턴스 맴버 (0) | 2021.12.02 |
| [Java] 클래스와 인스턴스 그리고 객체 (0) | 2021.12.02 |
- Total
- Today
- Yesterday
- DP
- 카카오
- 안드로이드
- Class
- 프로젝트구조
- 기본생성자
- 일반파라미터
- 코틀린
- 중첩클래스와 내부클래스
- 참조연산자
- 백준 #숨박꼭질3 #다익스트라 #알고리즘 #비전공개발자 #풀스택 #웹개발 #앱개발 #안드로이드 #python
- kotlin문법
- 백준알고리즘 #BFS #델타이동 #알고리즘풀이 #개발 #안전영역 #풀스택개발자가되고싶습니다. #노력할래요 # 꾸준히 # 화이팅! #비전공개발자
- 알고리즘
- 프로그래머스
- 백준
- 생성자
- Programmers #알고리즘 #Python #KAKAOINTERNSHIP #비전공개발자 #불량사용자
- 구간 합 구하기 4
- Python
- 안드로이드 #안드로이드스튜디오 #Kotlin #앱개발 #안드로이드기초 #비전공개발자 #풀스택개발자 #앱개발자
- 보조생성자
- 추가합격후기
- 비전공싸피합격
- Java #객체지향 #상속 #생성자 #개념 #비전공개발자 #FullStack을 #향해
- 싸피5기
- Kotlin
- Java
- 앱개발
- 비전공개발자
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
