상속상속의 기본 개념
개념
상속은 기존 클래스를 바탕으로 새로운 클래스를 만드는 방법이다.
처음부터 전부 새로 만드는 것이 아니라, 이미 있는 클래스의 기능을 이어받고 필요한 부분만 추가해서 더 구체적인 클래스를 만든다.
자바에서는extends를 사용한다.class 자식클래스 extends 부모클래스 { // 추가 내용 }이렇게 상속하면 자식 클래스는 부모 클래스의
멤버변수와메서드를 사용할 수 있다.
다만 부모의 멤버를 필요한 것만 골라 받는 방식은 아니다. 부모에 있는 멤버를 바탕으로 자식 클래스가 확장되는 구조라고 이해하면 된다.
알아야할 것은생성자와초기화 블록은 예외로 상속되지 않는다.
대신 자식 객체를 만들 때 부모 쪽이 먼저 준비된다.
핵심 특징
- 상속은 기존 클래스를 재사용해서 새 클래스를 만드는 방법이다.
- 자식은 부모의
멤버변수,메서드를 물려받는다.- 자식은 부모를 바탕으로 기능을 확장한 클래스라고 보면 된다.
- 공통 기능은 부모에 두고, 자식은 자기에게 필요한 부분만 추가하는 식으로 쓴다.
생성자,초기화 블록은 상속되지 않는다. 대신 자식 객체를 만들 때 부모 쪽이 먼저 준비된다.
예제:
InheritanceBasicclass Car { int wheel = 4; // 부모가 가진 멤버변수 void drive() { // 부모가 가진 메서드 System.out.println("자동차가 달린다."); } } class SportsCar extends Car { // SportsCar는 Car를 상속받는 자식 클래스 int turbo = 1; // 자식이 추가한 멤버변수 } public class InheritanceBasic { public static void main(String[] args) { SportsCar car = new SportsCar(); // 자식 객체 생성 // → SportsCar 자신의 멤버 + Car에게서 물려받은 멤버 사용 가능 System.out.println(car.wheel); // 부모 Car에게서 물려받은 wheel 사용 car.drive(); // 부모 Car에게서 물려받은 drive() 호출 System.out.println(car.turbo); // 자식 SportsCar가 직접 가진 turbo 사용 } // 출력결과 // 4 // 자동차가 달린다. // 1 }이 코드는 상속의 가장 기본 형태를 보여준다.
SportsCar안에는wheel과drive()를 직접 만들지 않았다.- 그런데도 사용할 수 있다.
- 이유는
SportsCar가Car를 상속받았기 때문이다.즉 자식 객체는 부모의 기능을 자기 것처럼 사용할 수 있다.
헷갈리기 쉬운 부분부모의 기능을 쓸 수 있다고 해서 코드를 복사해 온 것으로 생각하면 안 된다.
상속은 복붙이 아니라 클래스 사이에 부모-자식 관계를 만든 것이다.
또생성자도 상속되는 것 아닌가하고 많이 헷갈리는데, 생성자는 상속되지 않는다.
부모 생성자가 먼저 호출될 뿐이다.
상속관계 이해하기
개념상속은 클래스를 위아래로 연결해서 보는 구조다.
이 구조를 그림으로 보면상속계층도가 된다.
예를 들어 아래처럼 되어 있으면,
class Parent { } class Child extends Parent { } class Child2 extends Parent { } class GrandChild extends Child { }
Parent는 조상 클래스Child,Child2는 자식 클래스GrandChild는Child의 자식이면서Parent의 자손 클래스가 된다.
여기서 중요한 점은 상속관계에는 조상과 자손 관계만 있다는 것이다.
Child와Child2는 같은 부모를 가졌어도 서로 직접 상속관계는 아니다.
또GrandChild는Child를 통해 기능을 물려받기 때문에Child쪽 변화와 관련이 있다.
하지만Child2는 같은 부모를 둔 형제 클래스일 뿐이므로,Child2가 바뀐다고GrandChild가 직접 영향을 받지는 않는다.
핵심 특징
- 공통 부분은 조상에서 관리하고, 개별 부분은 자손에서 관리하는 것이 자연스럽다.
- 조상이 바뀌면 자손도 영향을 받는다.
- 자손이 바뀐다고 조상이 영향을 받지는 않는다.
- 같은 부모를 둔 형제 클래스끼리는 서로 직접 상속관계가 아니다.
GrandChild는Child의 변화에는 영향을 받을 수 있지만,Child2의 변화에는 직접 영향을 받지 않는다.- 상속관계가 넓어질수록 변경 영향도 같이 넓어진다.
예제:
InheritanceCommonTestclass Parent { void login() { // 공통 기능은 부모에 둠 System.out.println("로그인 기능"); } } class Child extends Parent { void childMethod() { // Child만의 기능 System.out.println("Child의 기능"); } } class Child2 extends Parent { void child2Method() { // Child2만의 기능 System.out.println("Child2의 기능"); } } class GrandChild extends Child { // GrandChild는 Child를 상속 // → Parent의 기능 + Child의 기능 사용 가능 } public class InheritanceCommonTest { public static void main(String[] args) { Child c1 = new Child(); Child2 c2 = new Child2(); GrandChild gc = new GrandChild(); c1.login(); // Parent의 login() 사용 c2.login(); // Parent의 login() 사용 gc.login(); // Parent → Child → GrandChild 흐름으로 login() 사용 가능 gc.childMethod(); // Child의 기능을 GrandChild도 사용 가능 // gc.child2Method(); // 에러 // GrandChild는 Child 계층에 속하므로 Child2의 기능은 직접 사용할 수 없음 } // 출력결과 // 로그인 기능 // 로그인 기능 // 로그인 기능 // Child의 기능 }이 코드는 상속관계에서 누구의 기능을 물려받는지를 보여준다.
login()은Parent에 있으므로Child,Child2,GrandChild모두 사용할 수 있다.childMethod()는Child에 있으므로GrandChild도 사용할 수 있다.- 반대로
child2Method()는Child2에만 있으므로GrandChild는 사용할 수 없다.즉,
GrandChild는Child쪽 계층에 속해 있고,Child2와는 직접적인 상속관계가 아니다.
헷갈리기 쉬운 부분
Child와Child2가 같은Parent를 상속받는다고 해서 둘이 서로 특별한 관계가 생기는 것은 아니다.
또GrandChild는 이름만 보면Parent의 손자 클래스이기도 하지만,
실제로 바로 물려받는 대상은Child다.
그래서GrandChild는Child의 변화에는 영향을 받을 수 있어도,
형제 계층인Child2의 변화에는 직접 영향을 받지 않는다.
부모에 멤버를 하나 추가하면 그 부모를 상속받는 자식들까지 같이 영향을 받는다.
그래서 상속은 편리하지만, 아무 클래스끼리 연결하면 안 된다.
포함 관계
개념클래스 사이의 관계는 상속만 있는 것이 아니다.
포함은 한 클래스가 다른 클래스를 멤버로 가지고 있는 관계다.
쉽게 말하면 부품처럼 가지고 있는 구조다.
예를 들어 자동차를 생각하면,
- 자동차는 엔진이다 → 어색함
- 자동차는 엔진을 가지고 있다 → 자연스러움
이럴 때는 상속이 아니라 포함이다.
즉, 포함은 “다른 클래스를 내 안에 넣어서 함께 사용하는 방식”이라고 보면 된다.
핵심 특징
- 한 클래스가 다른 클래스를
멤버변수로 가진다.- 큰 클래스를 작은 클래스들의 조합으로 만든다.
- 필요한 부품을 나누어 관리할 수 있다.
- 코드를 역할별로 나누기 쉬워서 유지보수에 유리하다.
예제:
CompositeTestclass Engine { void start() { System.out.println("엔진을 켠다."); } } class Car { Engine engine = new Engine(); // Car가 Engine 객체를 멤버로 포함 void drive() { engine.start(); // Car가 직접 엔진 역할을 하는 것이 아니라 // 자신이 가지고 있는 Engine 객체의 메서드를 호출 System.out.println("자동차가 달린다."); } } public class CompositeTest { public static void main(String[] args) { Car car = new Car(); // Car 객체 생성 // → 내부에 포함된 Engine 객체도 함께 준비됨 car.drive(); // drive() 호출 // → engine.start() 실행 // → 그 다음 "자동차가 달린다." 출력 } // 출력결과 // 엔진을 켠다. // 자동차가 달린다. }이 코드는
포함의 가장 기본 형태를 보여준다.
Car안에Engine engine이 있다.- 즉,
Car는Engine을 상속받은 것이 아니라 멤버로 가지고 있는 것이다.drive()가 실행되면, 자동차가 직접 엔진 역할을 하는 것이 아니라
자신이 가지고 있는engine객체의start()를 호출한다.여기서 봐야 할 가장 중요한 부분은 이 줄이다.
Engine engine = new Engine();이렇게 다른 클래스 타입의 변수를 멤버로 선언해서 가지고 있으면 포함 관계다.
헷갈리기 쉬운 부분포함과 상속이 헷갈리면 문장으로 바꿔 보면 된다.
Circle is a Shape→ 자연스러움 → 상속Car has an Engine→ 자연스러움 → 포함즉,
is-a면 상속,has-a면 포함으로 보면 된다.
또 포함은
“내가 그 자체가 되는 것”이 아니라
“내가 그것을 가지고 사용하는 것”이라는 점이 중요하다.
그래서Car는Engine이 아니고,Engine을 가지고 있는 클래스다.
단일 상속
개념자바는
단일 상속만 허용한다.
즉 한 클래스는 부모 클래스를 하나만 가질 수 있다.
핵심 특징
- 여러 부모를 동시에 상속받는
다중 상속은 허용하지 않는다.- 이유는 구조가 복잡해지고, 같은 이름의 멤버가 충돌할 수 있기 때문이다.
- 여러 기능이 필요하더라도, 부모-자식 관계가 자연스러운 클래스 하나만 상속하고 나머지는 포함 관계로 푸는 경우가 많다.
예제:
SingleInheritanceTestclass Tv { void powerOn() { System.out.println("TV 전원 켜기"); } } class VCR { void play() { System.out.println("비디오 재생"); } } // class TVCR extends Tv, VCR { } // 에러 // 자바는 부모 클래스를 두 개 동시에 상속할 수 없음 class TVCR extends Tv { // TVCR은 Tv를 상속 VCR vcr = new VCR(); // VCR 기능은 포함 관계로 해결 void playVideo() { vcr.play(); // 포함한 VCR 객체의 기능 호출 } } public class SingleInheritanceTest { public static void main(String[] args) { TVCR tvcr = new TVCR(); // TVCR 객체 생성 // → Tv 기능은 상속으로 사용 // → VCR 기능은 내부 객체로 사용 tvcr.powerOn(); // Tv에게서 물려받은 기능 tvcr.playVideo(); // 포함한 VCR 기능 호출 } // 출력결과 // TV 전원 켜기 // 비디오 재생 }이 코드는 자바에서 두 클래스를 동시에 상속할 수 없기 때문에,
하나는 상속으로 받고 나머지는 포함으로 처리하는 방식을 보여준다.
헷갈리기 쉬운 부분
상속을 많이 하면 더 강력해 보인다고 생각하기 쉽지만 그렇지 않다.
상속은 많을수록 좋은 것이 아니라, 정확하게 필요한 곳에만 써야 한다.
Object 클래스
개념
Object는 모든 클래스의 최고 조상이다.
자바에서 클래스를 만들 때 다른 클래스를 상속하지 않아도, 실제로는 자동으로Object를 상속받는다.
그래서 자바의 모든 클래스는 결국Object와 연결된다.
이 말은 곧, 어떤 클래스를 만들든Object가 가진 기본 메서드를 함께 물려받는다는 뜻이다.
대표적으로toString(),equals(),hashCode()같은 메서드가 있다.
즉, 우리가 만든 클래스도 특별히 적지 않아도 이런 메서드를 기본적으로 사용할 수 있다.
핵심 특징
- 모든 클래스의 맨 위에는 결국
Object가 있다.- 코드에
extends Object를 직접 쓰지 않아도 자동으로 이어진다.- 그래서 어느 클래스든
Object의 메서드를 사용할 수 있다.Object는 모든 객체가 공통으로 가져야 할 기본 기능을 제공한다.
예제:
ObjectTestclass Tv { } // extends Object를 쓰지 않았지만 실제로는 Object와 연결됨 public class ObjectTest { public static void main(String[] args) { Tv tv = new Tv(); // 우리가 만든 객체 생성 System.out.println(tv.toString()); // Tv 안에 toString()을 직접 만들지 않았는데도 호출 가능 // 이유: Tv가 Object를 자동으로 상속받기 때문 } // 출력결과 // Tv@해시값 }이 코드는
Tv클래스에 아무 메서드도 만들지 않았는데도toString()을 호출할 수 있다는 점을 보여준다.
Tv클래스 안에는toString()이 없다.- 그런데도
tv.toString()이 가능하다.- 그 이유는
Tv가 자동으로Object를 상속받기 때문이다.- 즉,
toString()은Object로부터 물려받은 메서드다.출력 결과에 보이는
Tv@해시값형태는 기본toString()이 만들어 주는 문자열이다.
그래서 직접 오버라이딩하지 않으면 보통 이런 식으로 출력된다.
헷갈리기 쉬운 부분코드에
extends Object가 안 보여도Object와 연결되지 않은 클래스는 없다고 보면 된다.
또toString(),equals(),hashCode()는 내가 직접 만든 적이 없어도 사용할 수 있다.
이유는 이 메서드들이 원래Object에 들어 있기 때문이다.
instanceof Object가true로 나오는 것도 같은 이유다.
모든 클래스는 결국Object의 자손이기 때문이다.
오버라이딩
개념
오버라이딩은 부모에게서 상속받은 메서드를 자식 클래스에 맞게 다시 정의하는 것이다.
부모 메서드를 그대로 쓰면 안 맞는 경우에, 이름은 그대로 두고 내용만 바꾸는 것이다.
왜 필요한지 생각해보면 쉽다.
부모에서 만든 기능이 자식에게도 무조건 딱 맞는 것은 아니다.
자식의 역할이 더 구체적이면, 같은 이름의 메서드라도 자식에 맞게 동작이 달라져야 한다.
핵심 특징
- 부모에게서 받은 메서드를 자식 쪽에서 다시 정의한다.
- 메서드의
선언부는 같아야 한다.
- 이름이 같아야 한다.
- 매개변수가 같아야 한다.
- 리턴타입이 같아야 한다.
- 접근 제어자를 더 좁게 바꾸면 안 된다.
- 부모보다 더 많은 예외를 선언할 수 없다.
static메서드와 인스턴스 메서드를 서로 바꿔서 오버라이딩할 수 없다.- 매개변수가 달라지면 오버라이딩이 아니라 오버로딩이다.
@Override를 붙이면 오버라이딩 여부를 확인하기 쉽다.
예제:
OverrideTestclass Point { int x; int y; String getLocation() { // 부모가 만든 위치 문자열 메서드 return "x : " + x + ", y : " + y; } } class Point3D extends Point { int z; @Override String getLocation() { // 부모 메서드를 자식에 맞게 다시 정의 return "x : " + x + ", y : " + y + ", z : " + z; } } public class OverrideTest { public static void main(String[] args) { Point3D p = new Point3D(); p.x = 10; // 부모에게서 물려받은 x p.y = 20; // 부모에게서 물려받은 y p.z = 30; // 자식이 추가한 z System.out.println(p.getLocation()); // Point3D 객체에서 getLocation()을 호출하면 // 부모 버전이 아니라 자식이 다시 정의한 메서드가 실행됨 } // 출력결과 // x : 10, y : 20, z : 30 }이 코드는 부모의
getLocation()을 자식에 맞게 다시 만든 예제다.
Point는 2차원 좌표고,Point3D는 3차원 좌표이기 때문에 그대로 쓰면 부족하다.
그래서 자식 쪽에서z까지 포함하도록 다시 정의한 것이다.
헷갈리기 쉬운 부분
오버라이딩과오버로딩은 다르다.
오버라이딩→ 상속받은 메서드를 다시 정의오버로딩→ 같은 이름의 메서드를 새로 추가예를 들어 매개변수가 달라지면 오버라이딩이 아니라 오버로딩이다.
즉 선언부가 달라지는 순간, 부모 메서드를 바꾼 것이 아니라 새 메서드를 만든 것이다.
super
개념
super는 부모의 멤버를 가리킬 때 쓰는 참조 표현이다.
this와 비슷해 보이지만 역할은 다르다.
자식 객체가 만들어지면, 그 안에는 자식이 만든 부분만 있는 것이 아니라 부모로부터 물려받은 부분도 함께 들어 있다.
이때this는 현재 객체 전체를 가리키고,super는 그 안에서 부모로부터 물려받은 부분을 구별해서 가리킬 때 사용한다.
그래서 부모와 자식에 같은 이름의 변수나 메서드가 있을 때super가 특히 중요해진다.
핵심 특징
this는 현재 객체 자신을 가리킨다.super는 현재 객체 안에 있는 부모 쪽 멤버를 가리킬 때 사용한다.- 부모와 자식에 같은 이름의 멤버가 있을 때 구별할 수 있다.
- 오버라이딩한 메서드 안에서 부모 메서드를 다시 호출할 때도 쓴다.
예제:
SuperTestclass Parent { int x = 10; // 부모의 x } class Child extends Parent { int x = 20; // 자식의 x void printValue() { System.out.println(x); // 가까운 곳의 x → Child의 x System.out.println(this.x); // 현재 객체의 자식 쪽 x System.out.println(super.x); // 부모 Parent의 x } } public class SuperTest { public static void main(String[] args) { Child c = new Child(); // Child 객체 생성 c.printValue(); // 같은 이름의 x가 두 개 있을 때 누구를 가리키는지 확인 } // 출력결과 // 20 // 20 // 10 }이 코드는 부모와 자식에 같은 이름의
x가 있을 때 어느 쪽 값을 읽는지 보여준다.
- 그냥
x라고 쓰면 현재 클래스 기준으로 가까운Child의x를 본다.this.x도 현재 객체의 자식 쪽x를 가리킨다.super.x는 부모인Parent에 있는x를 가리킨다.즉,
super는 “현재 객체 안에서 부모 쪽 멤버를 꺼내 보겠다”는 뜻으로 이해하면 된다.
예제:
SuperMethodTestclass Point { int x; int y; String getLocation() { return "x : " + x + ", y : " + y; } } class Point3D extends Point { int z; @Override String getLocation() { return super.getLocation() + ", z : " + z; // 부모가 만든 x, y 부분은 그대로 재사용 // 자식은 자기에게 필요한 z만 추가 } } public class SuperMethodTest { public static void main(String[] args) { Point3D p = new Point3D(); p.x = 1; p.y = 2; p.z = 3; System.out.println(p.getLocation()); // Point3D의 getLocation() 호출 // → 내부에서 super.getLocation() 실행 // → 부모가 만든 문자열 뒤에 z 정보 추가 } // 출력결과 // x : 1, y : 2, z : 3 }이 코드는
super가 메서드에서도 왜 필요한지 보여준다.
Point는 이미x,y를 문자열로 만드는getLocation()을 가지고 있다.Point3D는 여기에z만 더해서 확장하고 싶다.- 그래서 부모가 만든 부분은
super.getLocation()으로 그대로 재사용하고, 자식에 필요한z만 뒤에 붙인다.이렇게 하면 부모가 만든 기능을 다시 처음부터 쓰지 않아도 된다.
헷갈리기 쉬운 부분
super는 부모 객체를 따로 하나 더 만드는 것이 아니다.
지금 사용 중인 같은 객체 안에서 부모로부터 물려받은 부분을 가리키는 것이다.
또 부모와 자식에 이름이 겹치지 않으면 굳이super를 쓸 필요는 없다.
상속받은 멤버는 원래 그냥 사용할 수 있기 때문이다.
즉,super는 보통 아래 두 경우에 가장 많이 쓴다.
- 부모와 자식의 멤버 이름이 같을 때
- 오버라이딩한 메서드 안에서 부모 메서드를 다시 쓰고 싶을 때
super()와 생성자 호출
개념
super()는 부모 생성자를 호출하는 문장이다.
자식 객체를 만들면 자식 부분만 생기는 것이 아니라, 그 안에 포함된 부모 부분도 먼저 만들어져야 한다.
그래서 자식 생성자가 실행될 때는 항상 먼저 부모 생성자가 호출되어 부모 쪽 초기화가 끝나야 한다.
쉽게 말하면 자식 객체는 한 번에 뚝 생기는 게 아니라,
1. 부모 부분 먼저 준비
2. 그다음 자식 부분 준비이 순서로 만들어진다.
핵심 특징
- 자식 생성자의 첫 줄에서는
this()또는super()가 와야 한다.- 직접 쓰지 않으면 컴파일러가
super()를 자동으로 넣는다.- 부모에 기본 생성자
Parent()가 없으면 자동 호출이 실패해서 에러가 날 수 있다.- 이런 경우
super(값)처럼 맞는 부모 생성자를 직접 호출해야 한다.
예제:
SuperConstructorOrderTestclass Parent { Parent() { System.out.println("Parent 생성자 호출"); } } class Child extends Parent { Child() { // super(); 가 첫 줄에 자동으로 들어감 System.out.println("Child 생성자 호출"); } } public class SuperConstructorOrderTest { public static void main(String[] args) { Child c = new Child(); // new Child() // → Child 생성자 시작 // → 먼저 Parent 생성자 호출 // → 부모 쪽 준비 완료 // → 그 다음 Child 생성자 실행 } // 출력결과 // Parent 생성자 호출 // Child 생성자 호출 }이 코드는 생성자 호출 순서를 가장 직접적으로 보여준다.
new Child()를 했지만Child()만 바로 실행되지 않는다.- 먼저 부모 생성자인
Parent()가 호출된다.- 부모 쪽 준비가 끝난 다음에 자식 생성자인
Child()가 실행된다.즉, 자식 객체를 만들 때는 항상 부모 생성자가 먼저 실행된다는 점이 핵심이다.
예제:
SuperConstructorTestclass Point { int x; int y; Point(int x, int y) { this.x = x; // 부모가 자기 멤버 x 초기화 this.y = y; // 부모가 자기 멤버 y 초기화 } } class Point3D extends Point { int z; Point3D(int x, int y, int z) { super(x, y); // 부모 생성자 호출 // → 부모 쪽 x, y 먼저 저장 this.z = z; // 그 다음 자식이 자기 멤버 z 저장 } } public class SuperConstructorTest { public static void main(String[] args) { Point3D p = new Point3D(10, 20, 30); // new Point3D(10, 20, 30) // → Point3D 생성자 호출 // → super(10, 20) 실행 // → 부모의 x, y 초기화 // → 자식의 z 초기화 // → 객체 생성 완료 System.out.println(p.x); // 부모에게서 물려받은 x System.out.println(p.y); // 부모에게서 물려받은 y System.out.println(p.z); // 자식이 추가한 z } // 출력결과 // 10 // 20 // 30 }이 코드에서 핵심은
super(x, y);이다.
- 부모 클래스
Point가 가진x,y는 부모 생성자가 초기화한다.- 자식 클래스
Point3D가 추가한z는 자식 생성자가 초기화한다.즉, 부모 멤버는 부모 생성자가 맡고, 자식 멤버는 자식 생성자가 맡는 구조다.
그래서super(x, y)는 부모 부분을 먼저 제대로 준비하는 문장이라고 이해하면 된다.
헷갈리기 쉬운 부분
super와super()는 완전히 다르다.
super→ 부모의 변수나 메서드를 가리킬 때 사용super()→ 부모 생성자를 호출할 때 사용또 자식 생성자에서
super()를 안 써도 된다고 생각하기 쉬운데, 실제로는 안 쓰면 컴파일러가 자동으로 넣는다.
그래서 부모에 기본 생성자가 없으면 아래처럼 에러가 난다.class Parent { Parent(int x) { } } class Child extends Parent { Child() { // super(); 가 자동으로 들어가는데 Parent()가 없어서 에러 } }이럴 때는 자동 호출에 맡기면 안 되고, 직접 맞는 부모 생성자를 불러야 한다.
class Parent { Parent(int x) { } } class Child extends Parent { Child() { super(10); } }여기서 중요한 건 자식 생성자가 부모 생성을 건너뛸 수 없다는 점이다.
부모 부분이 먼저 준비되지 않으면 자식 객체도 완성될 수 없기 때문이다.
헷갈리기 쉬운 부분 한 번에 정리
1. 상속과 포함
상속은 ~이다포함은 ~을 가지고 있다자연스럽게 말이 되면 그 관계가 맞는 경우가 많다.
2. 생성자는 상속되지 않는다부모 생성자가 자식 안으로 복사되는 것이 아니다.
자식 객체를 만들 때 부모 생성자가 먼저 호출되는 것이다.
3. 오버라이딩과 오버로딩은 다르다
- 선언부가 같고 내용만 바꾸면
오버라이딩- 이름은 같지만 매개변수가 다르면
오버로딩
4. super와 super()는 다르다
super.x,super.method()→ 부모 멤버 접근super()→ 부모 생성자 호출
5. 상속은 무조건 많이 쓰는 것이 아니다상속은 편리하지만, 조상의 변경이 자손 전체에 영향을 줄 수 있다.
그래서 정말 부모-자식 관계로 보는 게 맞을 때만 쓰는 것이 중요하다.
그 외에는 포함으로 푸는 편이 더 안전한 경우가 많다.
한 번에 정리
상속은 기존 클래스를 바탕으로 새 클래스를 만드는 방법이다.
공통 기능은 부모에 두고, 자식은 필요한 기능만 더해서 확장한다.
클래스 사이의 관계를 잡을 때는
먼저상속으로 볼지포함으로 볼지 판단해야 한다.
자바는단일 상속만 허용하므로, 하나만 상속하고 나머지는 포함으로 푸는 경우가 많다.
모든 클래스는 결국Object와 연결되어 있고,
부모 메서드를 자식에 맞게 바꾸는 것이오버라이딩이다.
부모 멤버를 구별할 때는super, 부모 생성자를 호출할 때는super()를 사용한다.
핵심은 이것이다.
공통 부분은 조상에서 관리하고, 자식은 자기에게 필요한 부분만 추가한다.
이 흐름만 잡히면 상속 전체가 훨씬 쉽게 보인다.