🤔 "중복된 코드를 계속 둬야 할까?"
🤷🏻♀️ "어떻게 해결할 수 있을까?"
중복되는 코드가 많을 때 수정해야 할 파트가 많아지기 때문에 오류 발생 확률이 높아진다. 그래서 코드를 불러다 쓰는 방법이 없을까 하고 고민해야 함
🧒🏻 "이모이모! 방이 뭐야?"
👩🏻 "어..방은 말이야... "
방을 설명하고 나면
안방은방인데~ 엄마 아빠가 자는방이야.
공부방은방인데~ 공부하는방이야. 하고 설명하기 가능
👩🏻💻👩🏻💻👩🏻💻
( 코딩중... )
👩🏻 "버스" "스포츠카" "트럭"의 일반화된 개념이 뭐지?
👩🏻 ...차겠군!! 그러니차의 속성을 상속받는 것으로 구현하자~
➡️ 프로그래밍하다 보면 이런 순서로 가기도 함!
상속을 이용해보자!
⬇️
- OO는 OO다.
- OO는 OO의 종류 중 하나다.
라고 표현할 수 있을 때.
a.k.a. is a 관계 kind of 관계

말이 되는지를 봐야한다.
한번 상속받게 한 뒤에는 수정하는 게 쉽지가 않음
상속할 때 조심해야 하는 이유.jpg

스택인데 벡터를 상속받는 것부터 잘못됐다...
벡터가 가지는 기능을 다 쓸 수 있다는 뜻이기 때문
중간에서 꺼내는 동작이 일어나기 때문에 잘못 구현된 것!
필드로 선언해서 사용하는 게 나을 뻔했다.
근데도 고칠 수 없다.. 이미 오픈되어 어디선가 사용중일 것...
속성으로 가지면 되지 무작정 상속하면 안된다.
"상속이라는 문법을 사용해야 하나?" 에 대해 고민할 때 "OO는 OO의 종류 중 하나다."에 들어맞는지 체크해보아야
문법보다도(별 게 없음), "왜 상속을 해야 하지?"하고 개념을 이해하는 것이 중요
✏️child가 생성될 때 부모의 생성자가 먼저 실행되고 그 다음에 child의 생성자가 실행된다.
부모의 특정 생성자를 상속받고 싶을 때 오류 발생 가능
✏️ 생성자가 다른 생성자를 호출하게 할 수 있다. 바로
this()
this는 인스턴스가 있을 때만 가리킬 수 있다.this()는 생성자만 가리킬 수 있음; 생성자를 의미this()를 활용하는 것: 순서를 바꿔서도 가능!
cf. default 생성자를 안 만드는 eu?
아무 값 없이 생성하는 것이 의미가 없는 객체들은 default 생성자를 안 만드는 것이다.
Scanner 객체는 default 생성자가 없다.
➡️ 값을 어디서 줄 거야라는 정보를 주지 않으면 의미가 없기 때문에 정의해주지 않은 것
Scanner 클래스의 생성자 목록.jpg
↳ 위 문서에서 알 수 있는 것: System.in=InputStream
수행 흐름
여지껏은, 기본적으로 단일 쓰레드
카톡 구현하는 경우,
nextInt()는 값 입력할 때까지 기다리고 입력이 들어와야 다음 줄 실행하는데
채팅은 내가 입력을 하면서도 다른 사람이 입력 가능 : 시간을 굉장히 작은 단위로 쪼개서 - 사람이 느끼기에는 동시에 하는 것처럼 느껴지도록 : 멀티 스레드 : 시간 쪼개기
= 타임 쉐어링
스레드 객체 구현되어 있기 때문에 상속받아서 사용하면 됨
부모 → 자식 ⭕
자식 ← 부모 ❌

Car car2 = new Bus();
| 부모 | 자식 |
|---|---|
| Car | Bus |
| 큰 그릇 | 작은 그릇 |
이원준꺼 다시 한번 보기.. 왜 형질이 더 많은데 더 작은 범위일까? 이해가 되는데 또 안됨
자바는 단일 상속 ⭕, 다중 상속❌
자바는 다중 상속을 허용하지 않는다.
c라는 자식이 a라는 부모와 b라는 부모 동시에게 상속받을 수 없는 것
(파이썬은 순서롤 지정해주는 mro를 통해 가능)
자바는 부모가 하나만 있는 단일 상속
다만 부모의 부모의 부모는 가능!
직계는 가능!
가능한 이유: 자바가 가진 원칙(나중)
자식은 부모가 생기고 나서 생긴다.
child가 생길 때 반드시 parent가 생긴 후에 생긴다
child꺼로 getI()를 하면 자기껄 씀(내 꺼가 없을 때만 부모 꺼 씀)
parent입장에서는 물려준 거밖에 안 보인다.
가리킬 수는 있지만!
Car car2 = new Bus();레퍼런스 변수
car2와 Car객체
car2는 Car 타입의 참조 변수이다. 즉, "Car 타입으로 보이는 객체를 참조할 수 있다"는 것을 의미한다. 따라서car2는 Car의 필드와 메서드만 사용할 수 있도록 제한된다.
↳ 실제로 메모리에 저장된 객체는 Bus 전체이지만, 참조 변수는 이를 Car 관점에서만 보게 된다.
⭐car2는 Bus 객체의 일부분만 참조하는 것이 아니라 객체 전체를 참조하고 있지만 접근범위만 Car의 범위까지로 제한될 뿐이다.
일어나는 과정
| 좌변 | 우변 |
|---|---|
Car car2 | new Bus() |
car2는 Car 타입의 참조 변수; "Car 타입으로 보이는 객체를 참조할 수 있다" | Car의 필드와 메서드를 포함한 Bus 전체 객체가 생성됨 |
car2에 ⤺ 생성된 Bus 객체의 주소가 저장
⁕ car2는 Car 타입의 참조 변수이기 때문에, Car 클래스에 정의된 필드와 메서드만 접근 가능
⁕ 실제 객체는 Bus지만 car2를 통해서는 Car의 기능만 사용할 수 있다.
메모리에서는 무슨 일이 일어날까?
new Bus()호출 → 메모리에 Bus 객체가 생성
이 객체에는:
package day06;
//자바는 다중상속을 허용하지 않는다.
class Car {
String name;
int speed;
public void 운행하다(){
System.out.println("차가달립니다.");
}
}
class Bus extends Car{ //extends 클래스명
public void 승객을태우다(){
System.out.println("손님이 탑니다.");
}
}
class SeatBus extends Bus{
public void 좌석을예약하다(){
System.out.println("좌석이 예약 되었습니다.");
}
}
class Truck extends Car{
public void 짐을싣다(){
System.out.println("짐을 싣습니다.");
}
}
public class Exam01 {
public static void main(String[] args) {
Car car = new Car();
car.name = "티코";
car.speed = 100;
System.out.println(car.name);
System.out.println(car.speed);
car.운행하다();
// car.승객을태우다();
Bus bus = new Bus();
bus.name="스쿨버스";
bus.speed = 80;
System.out.println(bus.name);
System.out.println(bus.speed);
bus.운행하다();
bus.승객을태우다();
Truck truck = new Truck();
truck.짐을싣다();
truck.운행하다();
//부모(조상)는 자식(자손)을 가리킬(담을) 수 있다.
Car c = new Car();
Car c2 = new Bus();
Car c3 = new Truck();
Truck t = new Truck();
// Truck t2 = new Bus();
// Truck t3 = new Car();
SeatBus seatBus = new SeatBus();
seatBus.name = "";
seatBus.승객을태우다();
seatBus.좌석을예약하다();
//부모(조상)는 자식(자손)을 가리킬(담을) 수 있다.
Car sb1 = new SeatBus();
Bus sb2 = new SeatBus();
Object obj = new Car();
Object obj2 = new Bus();
Object obj4 = new SeatBus();
if(obj4 instanceof SeatBus) {
SeatBus ss = (SeatBus) obj4;
ss.좌석을예약하다();
((SeatBus) obj4).좌석을예약하다();
}
seatBus.좌석을예약하다();
SeatBus sb = (SeatBus) sb1;
sb.좌석을예약하다();
((SeatBus)sb1).좌석을예약하다(); //사용불가!!
}
}

오버라이딩
package day06;
//오버라이딩
//부모가 가진것을 자식이 똑같이 다시 정의 할 수 있다.
class Parent {
Parent(){
System.out.println("Parent 생성자 실행");
}
int i = 5;
public int getI() {
return i;
}
}
package day06;
class Child extends Parent {
Child(){
System.out.println("Child 생성자 실행!!");
}
int i = 10; //i가 오버라이딩 된 상태.
public int getI(){
return i;
}
public void print(){
System.out.println(i);
}
}
package day06;
public class Exam06 {
public static void test(Parent p){
System.out.println(p.i);
System.out.println(p.getI());
}
public static void main(String[] args) {
Parent p = new Parent();
System.out.println(p.i);
System.out.println(p.getI());
Child c = new Child();
System.out.println(c.i);
System.out.println(c.getI());
Parent pc = new Child();
System.out.println(pc.i);
System.out.println(pc.getI());
System.out.println("===================================");
test(p);
System.out.println("===================================");
test(c);
System.out.println("===================================");
test(pc);
}
}

pc.i가 5인 이유Parent pc = new Child();
pc는 Child 객체를 참조하고 있지만, Parent 타입으로 선언되었기 때문에 필드i에 접근할 때는 항상 Parent 클래스의i = 5를 사용한다.
맛보기
✏️
@Overrideannotation
java5부터 지원하는 @Override는 annotation인데, 안 써줘도 동작하지만 다음에 써준 코드가 정말 override가 맞는지 체킹해줌. 문법에 맞지 않으면 체킹 해줌!
Spring에서는 이러한 annotation을 많이 활용하므로 뒤에서 또 다룰 것임!
✏️super는 바로 위에 부모!
super()는 부모의 생성자