[5-5] 상속
상속 : 부모 기능 ---> 자식 클래스
extends : 클래스 상속 위해 꼭 필요함 !!!
<자식 클래스의 기능 확장하기>
class Animal {
String name;
void setName(String name) {
this.name = name;
}
}
class Dog extends Animal {
void sleep() {
System.out.println(this.name+" zzz");
}
}
public class Sample {
public static void main(String[] args) {
Dog dog = new Dog();
dog.setName("poppy");
System.out.println(dog.name);
dog.sleep();
}
}
generally, 상속받은 자식 클래스 = 부모 클래스 기능 + 기능 + 기능 ....
<IS - A 관계>
Animal ----> Dog
(상위) (하위)
Dog is a Animal(개는 동물이다) : IS-A 관계
자식 클래스 객체는 부모 클래스 자료형처럼 사용 O
Animal dog = new Dog(); // Dog is a Animal
{{{{{{주의}}}}}}
Dog 객체를 Animal 자료형으로 사용할 경우 : Dog 클래스에만 존재하는 sleep 메서드 사용 X
Animal 클래스에 구현된 setName 메서드만 사용 가능
부모 클래스로 만들어진 객체를 자식 클래스의 자료형으로는 사용할 수 없다
※ Object 클래스 ※
자바 모든 클래스는 Object 클래스 상속받음
<메서드 오버라이딩>
class Animal {
String name;
void setName(String name) {
this.name = name;
}
}
class Dog extends Animal {
void sleep() {
System.out.println(this.name+" zzz");
}
}
class HouseDog extends Dog {
}
public class Sample {
public static void main(String[] args) {
HouseDog houseDog = new HouseDog();
houseDog.setName("happy");
houseDog.sleep(); // happy zzz 출력
}
}
출력 : happy zzz
IF , 출력값 변경 ( happy zzz in house)
class HouseDog extends Dog {
}
↓
void sleep() {
System.out.println(this.name + " zzz in house");
}
}
HouseDog 클래스 (자식 클래스) 에 Dog 클래스(부모 클래스)와 동일 형태인 sleep 메서드 ▶ (우선순위 : HouseDog 클래스의 sleep 메서드 > Dog 클래스의 sleep 메서드) 즉, HouseDog 클래스의 sleep 메서드 호출
메서드 오버라이딩 : 부모 클래스의 메서드를 자식 클래스가 동일한 형태로 또다시 구현하는 행위
<메서드 오버로딩>
위의 코드에 메서드 추가
void sleep(int hour) {
System.out.println(this.name+" zzz in house for " + hour + " hours");
}
동일한 이름의 sleep 메서드 또 생성 O
★단, 메서드 입력 항목 다를 경우만★
메서드 오버로딩 : 입력 항목이 다른 경우 동일한 이름의 메서드 생성 O
<다중 상속>
다중 상속 : 클래스가 동시에 하나 이상의 클래스를 상속받는 것
but ! 자바는 다중상속 XXXXXXXXX !!!!!!
이유 : 상속받은 거 중 뭘 선택해야할지 애매모호!
[5-6] 생성자
<생성자>
class Animal {
String name;
void setName(String name) {
this.name = name;
}
}
class Dog extends Animal {
void sleep() {
System.out.println(this.name + " zzz");
}
}
class HouseDog extends Dog {
void sleep() {
System.out.println(this.name + " zzz in house");
}
void sleep(int hour) {
System.out.println(this.name + " zzz in house for " + hour + " hours");
}
}
public class Sample {
public static void main(String[] args) {
HouseDog houseDog = new HouseDog();
houseDog.setName("happy");
houseDog.sleep();
houseDog.sleep(3);
}
}
main 메서드 수정
(... 생략 ...)
public class Sample {
public static void main(String[] args) {
HouseDog dog = new HouseDog();
System.out.println(dog.name);
}
}
이때 name 변수에 어떠한 값도 없기 때문에 null 출력
이때 생성자 !!!!로 객체 변수에 값을 무조건 설정해야만 객체가 생성될 수 있도록 강제할수 있는 방법을 사용해부자.
class HouseDog extends Dog {
HouseDog(String name) {
this.setName(name);
}
생성자 : 메서드명이 클래스명과 동일하고 리턴 자료형을 정의하지 않는 메서드
{규칙}
- 클래스명 = 메서드명
- 리턴 타입 정의 X (void 사용 X)
생성자 호출
: new 클래스명(입력인수, ...)
{new 키워드로 객체를 만들 때 문자열 전달해야함.}
즉 문자열 전달이 되지 않아서 위에서 null 이 나온겨.
<디폴트 생성자>
class Dog extends Animal {
Dog() {
}
void sleep() {
System.out.println(this.name + " zzz");
}
}
위의 코드 중
Dog() {
}
이 부분을 디폴트 생성자 : 생성자의 입력 항목 X, 생성자 내부에 내용 X
IF, 클래스에 생성자 X : 컴파일러 자동으로 디폴트 생성자 추가
<생성자 오버로딩>
class Animal {
String name;
void setName(String name) {
this.name = name;
}
}
class Dog extends Animal {
void sleep() {
System.out.println(this.name + " zzz");
}
}
class HouseDog extends Dog {
HouseDog(String name) {
this.setName(name);
}
HouseDog(int type) {
if (type == 1) {
this.setName("yorkshire");
} else if (type == 2) {
this.setName("bulldog");
}
}
void sleep() {
System.out.println(this.name + " zzz in house");
}
void sleep(int hour) {
System.out.println(this.name + " zzz in house for " + hour + " hours");
}
}
public class Sample {
public static void main(String[] args) {
HouseDog happy = new HouseDog("happy");
HouseDog yorkshire = new HouseDog(1);
System.out.println(happy.name); // happy 출력
System.out.println(yorkshire.name); // yorkshire 출력
}
}
두개의 생성자 존재
- String 자료형을 입력으로 받는 생성
→ 차이 : 입력 항목 - int 자료형을 입력으로 받는 생성자
[5-7] 인터페이스
<인터페이스는 왜 필요한가?>
난 동물원(zoo)의 사육사(zookeeper)이다.
육식동물(predator)이 들어오면 난 먹이를 던져준다(feed).
호랑이(tiger)가 오면 사과(apple)를 던져준다.
사자(lion)가 오면 바나나(banana)를 던져준다.
class Animal {
String name;
void setName(String name) {
this.name = name;
}
}
class Tiger extends Animal {
}
class Lion extends Animal {
}
class ZooKeeper {
void feed(Tiger tiger) { // 호랑이가 오면 사과를 던져 준다.
System.out.println("feed apple");
}
void feed(Lion lion) { // 사자가 오면 바나나를 던져준다.
System.out.println("feed banana");
}
}
public class Sample {
public static void main(String[] args) {
ZooKeeper zooKeeper = new ZooKeeper();
Tiger tiger = new Tiger();
Lion lion = new Lion();
zooKeeper.feed(tiger); // feed apple 출력
zooKeeper.feed(lion); // feed banana 출력
}
}
출력값 :
feed apple
feed banana
그런데 ZooKeeper는 클래스 추가될 때 마다 feed 메서드 추가해야함.
그런데 일일히 하면 너무 복잡해.
이때 ! 인터페이스 !
<인터페이스 작성하기>
interface Predator {
}
class Animal {
String name;
void setName(String name) {
this.name = name;
}
}
(... 생략 ...)
인터페이스 작성시
: interface !!!!!!!! 키워드 추가
(... 생략 ...)
class Tiger extends Animal implements Predator {
}
class Lion extends Animal implements Predator {
}
(... 생략 ...)
implements 키워드 : Tiger, Lion 클래스 인터페이스 구현
(... 생략 ...)
class ZooKeeper {
void feed(Tiger tiger) {
System.out.println("feed apple");
}
void feed(Lion lion) {
System.out.println("feed banana");
}
}
(... 생략 ...)
↓
(... 생략 ...)
class ZooKeeper {
void feed(Predator predator) {
System.out.println("feed apple");
}
}
(... 생략 ...)
feed 메서드 입력 : Tiger, Lion → Predator 인터페이스 대체
IS-A 관계 : 인터페이스에도 적용
- tiger: Tiger 클래스의 객체이자 Predator 인터페이스의 객체
- lion: Lion 클래스의 객체이자 Predator 인터페이스의 객체
보통 중요 클래스(ZooKeeper)를 작성하는 시점에서 클래스(Animal)의 구현체(Tiger, Lion)가 몇 개가 될지 알 수 없으므로 인터페이스(Predator)를 정의하여 인터페이스를 기준으로 메서드(feed)를 만드는 것이 효율적
<인터페이스의 메서드>
(... 생략 ...)
class ZooKeeper {
public void feed(Predator predator) {
System.out.println("feed apple"); // 항상 feed apple 만을 출력한다.
}
}
(... 생략 ...)
출력
: feed apple
feed apple
▶ Predator 인터페이스에 getFood 메서드 추가
interface Predator {
String getFood();
}
(... 생략 ...)
메서드에 몸통 X
인터페이스의 메서드는 메서드의 이름과 입출력에 대한 정의만 있고 그 내용은 없다
이유 : 인터페이스 = ' 규칙 '
(... 생략 ...)
class Tiger extends Animal implements Predator {
public String getFood() {
return "apple";
}
}
class Lion extends Animal implements Predator {
public String getFood() {
return "banana";
}
}
(... 생략 ...)
Tiger, Lion 클래스의 getFood 메서드 : 각각 apple과 banana 리턴
★ 인터페이스의 메서드 : 항상 public으로 구현 !!!!! ★
▶ ZooKeeper 클래스 변경
(... 생략 ...)
class ZooKeeper {
void feed(Predator predator) {
System.out.println("feed "+predator.getFood());
}
}
(... 생략 ...)
수정 feed 메서드 : feed apple→ "feed "+predator.getFood()
<인터페이스 더 파고들기>
ZooKeeper 클래스 : 동물 클래스에 의존적인 클래스 → 동물 클래스와 상관없는 독립적인 클래스가 되었다는 점
상속 vs 인터페이스
- 상속 : 강제성 X
- 인터페이스 : 강제성O
<디폴트 메서드>
인터페이스의 메서드 : 구현체 X
but, 디폴트 메서드 사용 → 실제 구현된 형태의 메서드 O
디폴트 메서드 : 메서드명 가장 앞에 default라고 표기 , 오버라이딩 가능
[5-8] 다형성
'WINK-(Web & App) > JAVA 스터디' 카테고리의 다른 글
[2024-2 Java 스터디] 강보경 #4주차 (2) | 2024.11.07 |
---|---|
[2024-2 Java 스터디] 김태일 #4주차 (0) | 2024.11.06 |
[2024-2 Java 스터디] 김민서 #4주차 (0) | 2024.11.06 |
[2024-2 Java 스터디] 김지나 #4주차 "5.5~5.9" (0) | 2024.11.06 |
[2024-2 Java 스터디] 정채은 #3주차 (0) | 2024.10.31 |