728x90
반응형
[Day] 08.06
[Chapter] ~ 49강
📌 상속(extends) 중복
로봇 오리
날다() : 오리 클래스
수영() : 고무오리 클래스
public class Main {
public static void main(String[] args) {
청둥오리 a청둥오리 = new 청둥오리();
a청둥오리.날다();
// 출력 : 오리가 날개로 날아갑니다.
a청둥오리.수영();
// 출력 : 오리가 오리발로 헤엄칩니다.
흰오리 a흰오리 = new 흰오리();
a흰오리.날다();
// 출력 : 오리가 날개로 날아갑니다.
a흰오리.수영();
// 출력 : 오리가 오리발로 헤엄칩니다.
고무오리 a고무오리 = new 고무오리();
a고무오리.날다();
// 출력 : 저는 날 수 없어요. ㅜㅠ
a고무오리.수영();
// 출력 : 오리가 둥둥 떠다닙니다.
고무2오리 a고무2오리 = new 고무2오리();
a고무2오리.날다();
// 출력 : 저는 날 수 없어요. ㅜㅠ
a고무오리.수영();
// 출력 : 오리가 둥둥 떠다닙니다.
로봇오리 a로봇오리 = new 로봇오리();
a로봇오리.날다();
// 출력 : 저는 못 날아요 ㅠㅠ
a로봇오리.수영();
// 출력 : 오리가 오리발로 헤엄칩니다.
}
}
class 오리 {
void 날다() {
System.out.println("오리가 날개로 날아갑니다.");
}
void 수영() {
System.out.println("오리가 오리발로 헤엄칩니다.");
}
}
class 흰오리 extends 오리 {}
class 청둥오리 extends 오리 {}
// 메서드 재정의 라고 합니다.
// 메서드 오버라이드 라고도 합니다.
// 메서드 재정의 => 부모가 물려준 능력을 다시 구현한다.
class 고무오리 extends 오리 {
void 날다() {
System.out.println("저는 못 날아요 ㅠㅠ");
}
void 수영() {
System.out.println("오리가 둥둥 떠다닙니다.");
}
}
class 고무2오리 extends 고무오리 {}
// 수영 메서드를 오버라이드 해서 해결할 수 있지만 코드가 중복됨.
// 상속으로는 코드 중복을 완전히 해결할 수 없음.
class 로봇오리 extends 고무오리{
void 수영(){
System.out.println("오리가 오리발로 헤엄칩니다.~~");
}
}
📌 문제점
- 자바에서
다중상속지원 ❌ - 수영() || 날다() / 수영() && 날다() 재정의 ➡️
중복 발생 - 상속만으로는 중복 해결 불가 ❌
중복 제거 해결
“상속보다는 구성을 사용하라” ➡️ 객체의 협력
[ 예제 ]
class practice {
public static void main(String[] args) {
홍길동 a홍길동 = new 홍길동();
a홍길동.자바개발();
홍길순 a홍길순 = new 홍길순();
a홍길순.자바개발();
a홍길순.파이썬개발();
}
}
class 홍길동 {
int age;
String name;
void 자바개발() {
System.out.println("자바 24 개발합니다.");
}
void C개발() {
System.out.println("C언어 개발 합니다.");
}
}
//자바개발 중복 -> 홍길동 클래스의 참조값(홍길동연락처)으로 홍길동 불러서 해결
class 홍길순 {
int age;
String name;
홍길동 홍길동연락처 = new 홍길동();
void 자바개발() {
홍길동연락처.자바개발();
}
void 파이썬개발(){
System.out.println("파이썬 개발 합니다.");
}
}
✅ 홍길동 클래스의 참조값(홍길동연락처)으로 홍길동 불러서 해결
- 홍길동 객체 생성하여 해결
Q. 객체 생성 이후 다시 사용안할 것 같은데 자동 제거 되나?
A. 객체 무쓸모 -> 자바내부 Gc(가비지컬렉터)가 수거
판단 기준: 참조값이 연결되어 있는지 여부 확인 ➡️ 연결 안되어 있으면 자동 제거
[ 문제7️⃣ 중복 제거 해결 ]
구성 방식 사용
public class Main {
public static void main(String[] args) {
청둥오리 a청둥오리 = new 청둥오리();
a청둥오리.날다();
// 출력 : 오리가 날개로 날아갑니다.
a청둥오리.수영();
// 출력 : 오리가 오리발로 헤엄칩니다.
흰오리 a흰오리 = new 흰오리();
a흰오리.날다();
// 출력 : 오리가 날개로 날아갑니다.
a흰오리.수영();
// 출력 : 오리가 오리발로 헤엄칩니다.
고무오리 a고무오리 = new 고무오리();
a고무오리.날다();
// 출력 : 저는 날 수 없어요. ㅜㅠ
a고무오리.수영();
// 출력 : 오리가 둥둥 떠다닙니다.
고무2오리 a고무2오리 = new 고무2오리();
a고무2오리.날다();
// 출력 : 저는 날 수 없어요. ㅜㅠ
a고무오리.수영();
// 출력 : 오리가 둥둥 떠다닙니다.
로봇오리 a로봇오리 = new 로봇오리();
a로봇오리.날다();
// 출력 : 저는 못 날아요 ㅠㅠ
a로봇오리.수영();
// 출력 : 오리가 오리발로 헤엄칩니다.
}
}
//<---구성 방식 사용--->
class 오리날개 {
void 사용() {
System.out.println("오리가 날개로 날아갑니다.");
}
}
class 고무날개 {
void 사용() {
System.out.println("저는 날 수 없어요. ㅜㅠ");
}
}
class 오리발 {
void 사용() {
System.out.println("오리가 오리발로 헤엄칩니다.");
}
}
class 고무발 {
void 사용() {
System.out.println("오리가 둥둥 떠다닙니다.");
}
}
//<----구성방식 사용--->
class 오리 {
오리날개 a오리날개 = new 오리날개();
오리발 a오리발 = new 오리발();
void 날다() {
a오리날개.사용();
}
void 수영() {
a오리발.사용();
}
}
class 흰오리 extends 오리 {
}
class 청둥오리 extends 오리 {}
class 고무오리 extends 오리 {
고무날개 a날개 = new 고무날개();
고무발 a발 = new 고무발();
void 날다() {
a날개.사용();
}
void 수영() {
a발.사용();
}
}
class 고무2오리 extends 고무오리 {}
class 로봇오리 extends 고무오리 {
고무날개 a날개 = new 고무날개();
오리발 a발 = new 오리발();
void 날다() {
a날개.사용();
}
void 수영() {
a발.사용();
}
}
📌 상속(extends) 자동 형변환
자바개발자 a = new 홍길동();
➡️ 자바개발자 ≠ 홍길동으로 타입이 다름
public class practice {
public static void main(String[] args) {
홍주식회사 a홍주식회사 = new 홍주식회사();
a홍주식회사.자바개발();
a홍주식회사.파이썬개발();
}
}
class 홍주식회사 {
자바개발자 a자바개발자 = new 이순신(); // 자바개발자 != 이순신, 자동 형변환
홍길순 a홍길순 = new 홍길순();
void 자바개발() {
a자바개발자.자바개발();
}
void 파이썬개발() {
a홍길순.파이썬개발();
}
}
class 자바개발자 {
void 자바개발() {
System.out.println("자바 개발을 합니다.");
}
}
class 이순신 extends 자바개발자 {
void 자바개발() {
System.out.println("자바 개발을 합니다.");
}
}
class 홍길동 extends 자바개발자 {
int age;
String name;
void 자바개발() {
System.out.println("자바 25 개발을 합니다.");
}
void C언어개발() {
System.out.println("C언어 개발을 합니다.");
}
}
class 홍길순 {
int age;
String name;
홍길동 홍길동연락처 = new 홍길동();
void 자바개발() {
홍길동연락처.자바개발();
}
void 파이썬개발() {
System.out.println("파이썬 개발을 합니다.");
}
}
✅ 홍길동이 자바개발자를 상속받으면 가능 (이순신도 마찬가지)
- 자동 형변환
- 객체의 형변환은 상속을 통해서 이루어짐
- 하위 타입이 상위 타입으로 갈 때 안전
[ 예제 ]
상속 관계에서는 자식 타입이 부모 타입으로 자동 형변환
public class Main {
public static void main(String[] args) {
무기 a무기 = new 칼(); //무기 클래스로부터 칼 클래스 생성
// 출력 : 칼로 공격합니다.
a무기 = new 활(); //무기 클래스로부터 활 클래스 생성
a무기.공격();
// 출력 : 활로 공격합니다.
}
}
//정답
class 무기 {
void 공격(){};
}
class 칼 extends 무기 {
void 공격() { //오버라이딩
System.out.println("칼로 공격합니다.");
}
}
class 활 extends 무기 {
void 공격() { //오버라이딩
System.out.println("활로 공격합니다.");
}
}
📌 아쉬운 점
- 칼 클래스 & 활 클래스 ➡️ 공격 메서드 재정의 (오버라이딩)
- 무기 클래스의 공격 메서드를 사용하지 ❌
✅
무기 클래스를 추상 클래스로,
공격 메서드를 추상 메서드로 변경
📌 추상 클래스(abstract)
추상 메서드를 가지는 클래스 ➡️ 객체화 불가능
추상 메서드 ➡️ 구현이 없는 메서드 (버튼 역할)
public class Main {
public static void main(String[] args) {
무기 a무기 = new 칼();
a무기.공격();
// 출력 : 칼로 공격합니다.
a무기 = new 활();
a무기.공격();
// 출력 : 활로 공격합니다.
}
}
abstract class 무기 { // 추상 클래스
abstract void 공격(); // 추상 메서드 -> 구현이 없는 메서드. 버튼 역할만 한다.
}
class 칼 extends 무기 {
void 공격() { // 물려 받은 추상메서드는 반드시 구현해야 한다. 오버라이딩 강제
System.out.println("칼로 공격합니다.");
}
}
class 활 extends 무기 {
void 공격() {
System.out.println("활로 공격합니다.");
}
}
✅ 물려 받은 추상 메서드는 반드시 구현 !
- 즉, 오버라이딩 강제
📌 접근 제한자 (private)
📍적용 대상 : 필드, 생성자, 메서드
⭕️ 접근 가능 : 클래스 내부
❌ 접근 불가능 : 클래스 외부
public class Main {
public static void main(String[] args) {
사람 a사람 = new 사람();
a사람.나이세팅(10);
a사람.이름세팅("홍길동");
a사람.자기소개();
}
}
class 사람 {
private int 나이; //보호
private String 이름; //보호
public void 자기소개() {
System.out.println("안녕하세요, 제 이름은 " + 이름 + "이고, 나이는 " + 나이 + "살입니다.");
}
public void 나이세팅(int 입력나이) {
if(입력나이 < 0) {
System.out.println("나이는 음수가 될 수 없습니다.");
return;
}
나이 = 입력나이;
}
public void 이름세팅(String 입력이름) {
이름 = 입력이름;
}
}
✅ 객체의 올바른 작동 보장하기 위해 private으로 객체의 데이터 보호
📌 getter / setter
자바 ➡️ 기본적으로 인스턴스 변수를 private으로 보호하고 getter / setter 를 사용하는 것이 관례
✅ Getter : 내부의 멤버변수에 저장된 값을 외부로 리턴
✅ Setter : 외부로부터 데이터를 전달받아 멤버변수에 저장
public class Main {
public static void main(String[] args) {
사람 a사람 = new 사람();
}
}
class 사람 {
private int 나이;
private String 이름;
private String 거주지;
public void 자기소개() {
System.out.println("안녕하세요, 제 이름은 " + 이름 + "이고, 나이는 " + 나이 + "살입니다.");
}
// 단축키 cmd + n
// 게터/세터 자동 생성 가능
public int get나이() {
return 나이;
}
public void set나이(int 나이) {
this.나이 = 나이;
}
public String get이름() {
return 이름;
}
public void set이름(String 이름) {
this.이름 = 이름;
}
public String get거주지() {
return 거주지;
}
public void set거주지(String 거주지) {
this.거주지 = 거주지;
}
}
public class Main {
public static void main(String[] args) {
사람 a사람 =new 사람(20, "홍길동", "서울");
a사람.자기소개();
// 사람 a사람 = new 사람();
// a사람.set나이(20);
// a사람.set이름("홍길동");
// a사람.set거주지("서울");
//
//
// a사람.자기소개();
}
}
class 사람 {
private int 나이;
private String 이름;
private String 거주지;
public void 자기소개() {
System.out.println("안녕하세요, 제 이름은 " + 이름 + "이고, 나이는 " + 나이 + "살입니다.");
}
// 생성자 -> class 이름과 동일, 리턴 X
// 올바른 객체 동작을 위한 객체 값 초기화 및 초기 세팅
사람(int 나이, String 이름, String 거주지) {
this.나이 = 나이;
this.이름 = 이름;
this.거주지 = 거주지;
}
// 단축키 cmd + n
// 게터/세터 자동 생성 가능
public int get나이() {
return 나이;
}
public void set나이(int 나이) {
this.나이 = 나이;
}
public String get이름() {
return 이름;
}
public void set이름(String 이름) {
this.이름 = 이름;
}
public String get거주지() {
return 거주지;
}
public void set거주지(String 거주지) {
this.거주지 = 거주지;
}
}728x90
반응형
'✏️공부 > 💡JAVA' 카테고리의 다른 글
| [JAVA] Java Stream | mapToInt() 활용한 연산, finFirst(), isPresent(), orElseThrow(), Optional<> (4) | 2025.08.07 |
|---|---|
| [JAVA] JAVA Stream | 명령형, 선언형, filter, map, stream, foreach, toArray, toList | 예제 ⭕️ (3) | 2025.08.06 |
| [JAVA] JAVA 기초 | static, 상속 (extends) | 예제 문제 ⭕️ (4) | 2025.08.05 |
| [JAVA] JAVA 기초 | 배열, 리스트(ArrayList<>) , 맵(Map<>), 제네릭 (3) | 2025.08.04 |
| [JAVA] JAVA 기초 | 클래스, 함수, 전역변수 vs 인스턴스 변수 (0) | 2025.08.01 |
