230320 풀스택 13일차 - 자바 기초 복습(상속~)

황인성·2023년 3월 20일
0

상속 기본구조

class Main {
	public static void main(String[] args) {
		흰고양이 a = new 흰고양이();
		a.숨쉬다();
		a.야옹();
		a.미래를_예지하다();
		
		검은고양이 b = new 검은고양이();
		b.숨쉬다();
		b.야옹();
		b.목숨을_늘린다();
	}
}
class 고양이 {
	void 숨쉬다() { }
    void 야옹() { }
	void 뛰어넘다() { }
}	
class 흰고양이 extends 고양이{
    void 미래를_예지하다() { }
}
class 검은고양이 extends 고양이{
	void 목숨을_늘린다() { }
}

상속의 단계별 응용(흰오리, 청둥오리, 고무오리, 고무2오리, 로봇오리)

/* 가정
우리는 게임개발회사에 입사했다.
우리에게는 성격좋은 사수 한명이 있다.
내가 개발할 게임은 오리시뮬레이션 게임이다.
선임이 나의 개발을 도와주진 않지만 조언은 해준다.
*/

/* 요구사항
- D1 요구 : 오리를 생성하고 날게하시오.
*/

class Main {
  public static void main(String[] args) {
    오리 a오리 = new 오리();
    a오리.날다();
    // 출력 : 오리가 날개로 날아갑니다.
  }
}
class 오리 {
	void 날다() { // 리턴값이 없는 매개변수를 지칭할때
		System.out.println("오리가 날개로 날아갑니다.");
	}
}
/* 가정
우리는 게임개발회사에 입사했다.
우리에게는 성격좋은 사수 한명이 있다.
내가 개발할 게임은 오리시뮬레이션 게임이다.
선임이 나의 개발을 도와주진 않지만 조언은 해준다.
*/
/* 요구사항
- D1 요구 : 오리를 생성하고 날게하시오.
- D1 완료 : 클래스와 메서드를 만들어서 처리
- D2 요구 : 게임의 디테일을 살리기 위해서 `청둥오리`와 `흰오리`를 생성하고 날게하시오.
*/
class Main {
	public static void main(String[] args) {
		청둥오리 a청둥오리 = new 청둥오리();
		a청둥오리.날다();
		// 출력 : 오리가 날개로 날아갑니다.
		흰오리 a흰오리 = new 흰오리();
		a흰오리.날다();
		// 출력 : 오리가 날개로 날아갑니다.
	}
}
class 오리 {
	void 날다() {}
}
class 청둥오리 extends 오리{
	void 날다() {
		System.out.println("오리가 날개로 날아갑니다.");
	}
}
class 흰오리 extends 오리{
	void 날다() {
		System.out.println("오리가 날개로 날아갑니다.");
	}
}
/* 가정
우리는 게임개발회사에 입사했다.
우리에게는 성격좋은 사수 한명이 있다.
내가 개발할 게임은 오리시뮬레이션 게임이다.
선임이 나의 개발을 도와주진 않지만 조언은 해준다.
*/

/* 요구사항
- D1 요구 : 오리를 생성하고 날게하시오.
- D1 완료 : 클래스와 메서드를 만들어서 처리
- D2 요구 : 게임의 디테일을 살리기 위해서 `청둥오리`와 `흰오리`를 생성하고 날게하시오.
- D2 완료 : 클래스와 메서드를 만들어서 처리
- D3 요구 : 오리 계열의 클래스에 날다 메서드가 중복되었습니다. 중복을 제거해주세요.
- D3 완료 : 상속을 사용해서 처리
- D4 요구 : 게임의 재미를 위하여 고무오리를 추가하고 날게 하시오.
*/

class Main {
  public static void main(String[] args) {
    청둥오리 a청둥오리 = new 청둥오리();
    a청둥오리.날다();
    // 출력 : 오리가 날개로 날아갑니다.
    
    흰오리 a흰오리 = new 흰오리();
    a흰오리.날다();
    // 출력 : 오리가 날개로 날아갑니다.
    
    고무오리 a고무오리 = new 고무오리();
    a고무오리.날다();
    // 출력 : 오리가 날개로 날아갑니다.
  }
}

class 오리 {
  void 날다() {
    System.out.println("오리가 날개로 날아갑니다.");
  }
}

// 오리 => 부모 클래스
// 흰오리 => 자식 클래스
// 흰오리 extends 오리 => 흰오리가 오리의 능력을 물려 받는다.
// "`흰오리`는 `오리`이다." 라고 자바에게 알려준다.
// `A 는 B 이다.` 테스트에 통과하는 것만 상속이 가능하다.
// 클래스와 객체는 명사이다.
// 메서드는 동사이다.
class 흰오리 extends 오리 {
  
}

class 청둥오리 extends 오리 {
}
class 고무오리 extends 오리 {
}
/* 가정
우리는 게임개발회사에 입사했다.
우리에게는 성격좋은 사수 한명이 있다.
내가 개발할 게임은 오리시뮬레이션 게임이다.
선임이 나의 개발을 도와주진 않지만 조언은 해준다.
*/

/* 요구사항
- D1 요구 : 오리를 생성하고 날게하시오.
- D1 완료 : 클래스와 메서드를 만들어서 처리
- D2 요구 : 게임의 디테일을 살리기 위해서 `청둥오리`와 `흰오리`를 생성하고 날게하시오.
- D2 완료 : 클래스와 메서드를 만들어서 처리
- D3 요구 : 오리 계열의 클래스에 날다 메서드가 중복되었습니다. 중복을 제거해주세요.
- D3 완료 : 상속을 사용해서 처리
- D4 요구 : 게임의 재미를 위하여 고무오리를 추가하고 날게 하시오.
- D4 완료 : 클래스와 메서드를 만들어서 처리
- D5 요구 : 주말 주주회의에서 고무오리가 하늘을 날아다니는 것에 대해서 태클이 들어왔습니다. 고무오리 계열은 하늘을 날 수 없게 해주세요.
*/

class Main {
  public static void main(String[] args) {
    청둥오리 a청둥오리 = new 청둥오리();
    a청둥오리.날다();
    // 출력 : 오리가 날개로 날아갑니다.
    
    흰오리 a흰오리 = new 흰오리();
    a흰오리.날다();
    // 출력 : 오리가 날개로 날아갑니다.
    
    고무오리 a고무오리 = new 고무오리();
    a고무오리.날다();
    // 출력 : 저는 날 수 없어요. ㅜㅠ
  }
}

class 오리 {
  void 날다() {
    System.out.println("오리가 날개로 날아갑니다.");
  }
}

// 오리 => 부모 클래스
// 흰오리 => 자식 클래스
// 흰오리 extends 오리 => 흰오리가 오리의 능력을 물려 받는다.
// "`흰오리`는 `오리`이다." 라고 자바에게 알려준다.
// `A 는 B 이다.` 테스트에 통과하는 것만 상속이 가능하다.
// 클래스와 객체는 명사이다.
// 메서드는 동사이다.
class 흰오리 extends 오리 {
  
}

class 청둥오리 extends 오리 {
}

class 고무오리 extends 오리 {
	void 날다 () { // 부모에 이미 날다 메서드가 있지만 오버라이딩으로 자식이 갖고있는 값으로 재정의 된다.
		System.out.println("저는 하늘을 날 수 없어요 ㅜㅜ");
	}
}
/* 가정
우리는 게임개발회사에 입사했다.
우리에게는 성격좋은 사수 한명이 있다.
내가 개발할 게임은 오리시뮬레이션 게임이다.
선임이 나의 개발을 도와주진 않지만 조언은 해준다.
*/

/* 요구사항
- D1 요구 : 오리를 생성하고 날게하시오.
- D1 완료 : 클래스와 메서드를 만들어서 처리
- D2 요구 : 게임의 디테일을 살리기 위해서 `청둥오리`와 `흰오리`를 생성하고 날게하시오.
- D2 완료 : 클래스와 메서드를 만들어서 처리
- D3 요구 : 오리 계열의 클래스에 날다 메서드가 중복되었습니다. 중복을 제거해주세요.
- D3 완료 : 상속을 사용해서 처리
- D4 요구 : 게임의 재미를 위하여 고무오리를 추가하고 날게 하시오.
- D4 완료 : 클래스와 메서드를 만들어서 처리
- D5 요구 : 주말 주주회의에서 고무오리가 하늘을 날아다니는 것에 대해서 태클이 들어왔습니다. 고무오리 계열은 하늘을 날 수 없게 해주세요.
- D5 완료 : 메서드 오버라이드를 사용해서 처리
- D6 요구 : 고무오리가 반응이 좋습니다. 고무2오리를 추가하고 날게 해주세요.
*/

class Main {
  public static void main(String[] args) {
    청둥오리 a청둥오리 = new 청둥오리();
    a청둥오리.날다();
    // 출력 : 오리가 날개로 날아갑니다.
    
    흰오리 a흰오리 = new 흰오리();
    a흰오리.날다();
    // 출력 : 오리가 날개로 날아갑니다.
    
    고무오리 a고무오리 = new 고무오리();
    a고무오리.날다();
    // 출력 : 저는 날 수 없어요. ㅜㅠ
    
    고무2오리 a고무2오리 = new 고무2오리();
    a고무2오리.날다();
    // 출력 : 저는 날 수 없어요. ㅜㅠ
  }
}

class 오리 {
  void 날다() {
    System.out.println("오리가 날개로 날아갑니다.");
  }
}

// 오리 => 부모 클래스
// 흰오리 => 자식 클래스
// 흰오리 extends 오리 => 흰오리가 오리의 능력을 물려 받는다.
// "`흰오리`는 `오리`이다." 라고 자바에게 알려준다.
// `A 는 B 이다.` 테스트에 통과하는 것만 상속이 가능하다.
// 클래스와 객체는 명사이다.
// 메서드는 동사이다.
class 흰오리 extends 오리 {
  
}

class 청둥오리 extends 오리 {
}

class 고무오리 extends 오리 {
  // 메서드 재정의 라고 합니다.
  // 메서드 오버라이드 라고도 합니다.
  // 메서드 재정의 => 부모가 물려준 능력을 다시 구현한다.
  void 날다() {
    System.out.println("저는 날 수 없어요. ㅜㅠ");
  }
}
class 고무2오리 extends 오리 {
	void 날다 () {
		System.out.println("저는 날 수 없어요. ㅜㅠ");
	}
}
/* 가정
우리는 게임개발회사에 입사했다.
우리에게는 성격좋은 사수 한명이 있다.
내가 개발할 게임은 오리시뮬레이션 게임이다.
선임이 나의 개발을 도와주진 않지만 조언은 해준다.
*/
/* 요구사항
- D1 요구 : 오리를 생성하고 날게하시오.
- D1 완료 : 클래스와 메서드를 만들어서 처리
- D2 요구 : 게임의 디테일을 살리기 위해서 `청둥오리`와 `흰오리`를 생성하고 날게하시오.
- D2 완료 : 클래스와 메서드를 만들어서 처리
- D3 요구 : 오리 계열의 클래스에 날다 메서드가 중복되었습니다. 중복을 제거해주세요.
- D3 완료 : 상속을 사용해서 처리
- D4 요구 : 게임의 재미를 위하여 고무오리를 추가하고 날게 하시오.
- D4 완료 : 클래스와 메서드를 만들어서 처리
- D5 요구 : 주말 주주회의에서 고무오리가 하늘을 날아다니는 것에 대해서 태클이 들어왔습니다. 고무오리 계열은 하늘을 날 수 없게 해주세요.
- D5 완료 : 메서드 오버라이드를 사용해서 처리
- D6 요구 : 고무오리가 반응이 좋습니다. 고무2오리를 추가하고 날게 해주세요.
- D6 완료 : 고무2오리를 추가
- D7 요구 : 고무오리계열에서 날다 메서드의 중복을 제거해주세요.
*/
class Main {
	public static void main(String[] args) {
		청둥오리 a청둥오리 = new 청둥오리();
		a청둥오리.날다();
		// 출력 : 오리가 날개로 날아갑니다.
		흰오리 a흰오리 = new 흰오리();
		a흰오리.날다();
		// 출력 : 오리가 날개로 날아갑니다.
		고무오리 a고무오리 = new 고무오리();
		a고무오리.날다();
		// 출력 : 저는 날 수 없어요. ㅜㅠ
		고무2오리 a고무2오리 = new 고무2오리();
		a고무2오리.날다();
		// 출력 : 저는 날 수 없어요. ㅜㅠ
	}
}
class 오리 {
	void 날다() {
		System.out.println("오리가 날개로 날아갑니다.");
	}
}
// 오리 => 부모 클래스
// 흰오리 => 자식 클래스
// 흰오리 extends 오리 => 흰오리가 오리의 능력을 물려 받는다.
// "`흰오리`는 `오리`이다." 라고 자바에게 알려준다.
// `A 는 B 이다.` 테스트에 통과하는 것만 상속이 가능하다.
// 클래스와 객체는 명사이다.
// 메서드는 동사이다.
class 흰오리 extends 오리 {
}
class 청둥오리 extends 오리 {
}
class 고무오리 extends 오리 {
	// 메서드 재정의 라고 합니다.
	// 메서드 오버라이드 라고도 합니다.
	// 메서드 재정의 => 부모가 물려준 능력을 다시 구현한다.
	void 날다() {
		System.out.println("저는 날 수 없어요. ㅜㅠ");
	}
}
class 고무2오리 extends 고무오리 {
	// 메서드 재정의 라고 합니다.
	// 메서드 오버라이드 라고도 합니다.
	// 메서드 재정의 => 부모가 물려준 능력을 다시 구현한다.
	
}
/* 가정
우리는 게임개발회사에 입사했다.
우리에게는 성격좋은 사수 한명이 있다.
내가 개발할 게임은 오리시뮬레이션 게임이다.
선임이 나의 개발을 도와주진 않지만 조언은 해준다.
*/

/* 요구사항
- D1 요구 : 오리를 생성하고 날게하시오.
- D1 완료 : 클래스와 메서드를 만들어서 처리
- D2 요구 : 게임의 디테일을 살리기 위해서 `청둥오리`와 `흰오리`를 생성하고 날게하시오.
- D2 완료 : 클래스와 메서드를 만들어서 처리
- D3 요구 : 오리 계열의 클래스에 날다 메서드가 중복되었습니다. 중복을 제거해주세요.
- D3 완료 : 상속을 사용해서 처리
- D4 요구 : 게임의 재미를 위하여 고무오리를 추가하고 날게 하시오.
- D4 완료 : 클래스와 메서드를 만들어서 처리
- D5 요구 : 주말 주주회의에서 고무오리가 하늘을 날아다니는 것에 대해서 태클이 들어왔습니다. 고무오리 계열은 하늘을 날 수 없게 해주세요.
- D5 완료 : 메서드 오버라이드를 사용해서 처리
- D6 요구 : 고무오리가 반응이 좋습니다. 고무2오리를 추가하고 날게 해주세요.
- D6 완료 : 고무오리가 반응이 좋습니다. 고무2오리를 추가하고 날게 해주세요.
- D7 요구 : 고무오리계열에서 날다 메서드의 중복을 제거해주세요.
- D7 완료 : 상속으로 해결
- D8 요구 : 자바에서 다중상속은 불가능 합니다. 상속에는 한계가 있습니다. 복잡한 상속을 사용하지 않고 고무오리계열의 중복을 제거해주세요.
  - 복잡한 상속을 사용하지 않는다는 것의 의미 : 모든 오리 계열 클래스들은 부모클래스가 오리 클래서 여야 한다.
*/

class Main {
  public static void main(String[] args) {
    청둥오리 a청둥오리 = new 청둥오리();
    a청둥오리.날다();
    // 출력 : 오리가 날개로 날아갑니다.
    
    흰오리 a흰오리 = new 흰오리();
    a흰오리.날다();
    // 출력 : 오리가 날개로 날아갑니다.
    
    고무오리 a고무오리 = new 고무오리();
    a고무오리.날다();
    // 출력 : 저는 날 수 없어요. ㅜㅠ
    
    고무2오리 a고무2오리 = new 고무2오리();
    a고무2오리.날다();
    // 출력 : 저는 날 수 없어요. ㅜㅠ
  }
}

class 오리 {
  void 날다() {
    System.out.println("오리가 날개로 날아갑니다.");
  }
}

// 오리 => 부모 클래스
// 흰오리 => 자식 클래스
// 흰오리 extends 오리 => 흰오리가 오리의 능력을 물려 받는다.
// "`흰오리`는 `오리`이다." 라고 자바에게 알려준다.
// `A 는 B 이다.` 테스트에 통과하는 것만 상속이 가능하다.
// 클래스와 객체는 명사이다.
// 메서드는 동사이다.
class 흰오리 extends 오리 {
  
}

class 청둥오리 extends 오리 {
  
}

class 고무오리 extends 오리 {
  // 메서드 재정의 라고 합니다.
  // 메서드 오버라이드 라고도 합니다.
  // 메서드 재정의 => 부모가 물려준 능력을 다시 구현한다.
  void 날다() {
    System.out.println("저는 날 수 없어요. ㅜㅠ");
  }
}

class 고무2오리 extends 오리 {
  void 날다() {
    System.out.println("저는 날 수 없어요. ㅜㅠ");
  }
}
// 문제 : 아래와 같이 출력되도록 해주세요.
// 조건 : 소스코드 중복이 없어야 합니다.
// 조건 : 복잡한 상속을 써도 됩니다.

class Main {
	public static void main(String[] args) {
		System.out.println("== 청둥오리 ==");
		청둥오리 a청둥오리 = new 청둥오리();
		a청둥오리.날다(); // 오리가 날개로 날아갑니다.
		a청둥오리.수영하다(); // 오리가 물갈퀴로 수영합니다.
		
		System.out.println("== 흰오리 ==");
		흰오리 a흰오리 = new 흰오리();
		a흰오리.날다(); // 오리가 날개로 날아갑니다.
		a흰오리.수영하다(); // 오리가 물갈퀴로 수영합니다.
		
		System.out.println("== 고무오리 ==");
		고무오리 a고무오리 = new 고무오리();
		a고무오리.날다(); // 저는 못 날아요 ㅠㅠ
		a고무오리.수영하다(); // 오리가 물에 둥둥 떠다닙니다.
		
		System.out.println("== 고무2오리 ==");
		고무2오리 a고무2오리 = new 고무2오리();
		a고무2오리.날다(); // 저는 못 날아요 ㅠㅠ
		a고무2오리.수영하다(); // 오리가 물에 둥둥 떠다닙니다.
		
		System.out.println("== 로봇오리 ==");
		로봇오리 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 Main {
  public static void main(String[] args) {
    무기 a무기 = new(); // 칼이 자동형변환이 되려면 무기가 부모가 되어야 함.
  } // a무기에 리모컨이 들어가서 무언가를 제어할 수 있게 됐다.
}

class 무기 {
	
}
classextends 무기{ // class 칼 extends 무기 => 칼은 무기(의 자식)이다 라고 읽을 수 있음 
	
}
// 문제 : 아래가 실행되도록 해주세요.

class Main {
  public static void main(String[] args) {
    칼 a칼 = new();
    a칼 = new(); // 칼 a칼 = new 활(); 과 같은 형태
	  // 활이 부모형태라면 타입이 맞지 않아서 에러가 남.
	  // 칼이 활보다 부모여야 됨(포괄)
  } // 기본 자료형 이외의 모든 참조 자료형 리모컨이 들어간다.
}

class{
	
}
classextends{
	
}
class Main {
  public static void main(String[] args) {
    // 정수가 실수 화 되어서 들어간다.
    // 5가 5.0이 되어서 들어간다.
    double d = 5;
    
    // `칼 리모콘`이 `무기 리모콘`화 되어서 들어간다.
    
    // 실제 처리
    // 무기 a무기 = (무기)new 칼();
    // (무기) => 무기리모콘 화
    무기 a무기 = new(); // new 칼(주소)이라는 할당값이 무기의 형태로 형변환되어서 a무기(new 칼 을 제어할 수 있는)라는 변수에 할당된다.
    
    a무기.공격();
    // 출력 : 칼로 공격합니다.
  }
}

// 리모콘 전용 클래스
class 무기 {
  // 버튼 전용 메서드(함수)
  void 공격() { }
}

classextends 무기 {
  void 공격() {
    System.out.println("칼로 공격합니다.");
  }
}

문제. 동물 사람 원숭이 형변환 문제(클래스가 헷갈리기 시작한 타이밍)

class Main {
	public static void main(String[] args) {
		사람 a사람 = new 사람();
		원숭이 a원숭이 = new 원숭이();
	// 문제 1 : 아래 줄의 코드가 되는 이유 설명
	동물 a동물 = a원숭이; // "동물 자료형으로 a동물을 선언해줘서 a원숭이(=new 원숭이();)를 넣어줌" - 나의 답
	// 형변환이 가능한 구조이다 : 동물이 사람보다 부모이기 때문이다(상속을 해줬다.) - 선생님 설명
	// 좌항이 우항보다 범위가 크다 그래서 형변환이 가능하다.- 선생님 설명
	// 좌항이 우항의 부모이다.- 선생님 설명
	
	원숭이 a원숭이2 = null; // null 은 쓰레기 리모콘이라는 뜻
	// null로 초기화.
	
	// 문제 2 : 아래 줄의 코드가 안되는 이유 설명
	// a원숭이2 = a동물; // a원숭이2라는 변수의 자료형은 명시해줬지만 할당값이 없어서(초기화가 안되어서) 안됨. - 나의 답
	// 좌항이 우항보다 범위가 넓어야 하는데 우항이 좌항보다 범위가 넓어서 안됨. - 선생님 설명
	
	// 문제 3 : 아래 줄의 되는 이유 설명
	a원숭이2 = (원숭이)a동물; // 자료형 명시해줘서 강제 형변환 해줬고 a동물의 값(a원숭이)도 할당해주었기 때문에 리모컨으로 사용가능. - 나의 답
	// a동물에 원숭이로 형변환을 시키면 변환이 된 상태에서 원숭이로 들어감. - 선생님 설명
	
	사람 a사람2 = null;
	
	// 문제 4 : 위 코드를 순차적으로 참고하여 아래 줄의 코드가 수동 형변환 까지 했는데도 안되는 이유 설명
	// a사람2 = (사람)a동물;
	// a사람2라는 변수의 자료형은 명시해줬지만 할당값이 없어서(초기화가 안되어서) 안됨. - 나의 답
	// 동물에서 원숭이라는 타입을 받아서 강제형변환을 했는데 이미 형변환된 원숭이2를 사람으로 한번 더 형변환 해줬기때문에 안됨.- 선생님 설명
}

}
abstract class 동물 {
void 숨쉬다() {
System.out.println("동물이 숨을 쉽니다.");
}
}
class 사람 extends 동물 {
void 말하다() {
System.out.println("사람이 말을 합니다.");
}
}
class 원숭이 extends 동물 {
void 원숭이묘기를하다() {
System.out.println("원숭이묘기를하다.");
}
}


> 위 문제에 대한 선생님 설명

```java
class Main {
	public static void main(String[] args) {
		사람 a사람 = new 사람();
		원숭이 a원숭이 = new 원숭이();
		
		// 문제 1 : 아래 줄의 코드가 되는 이유 설명
		// - 상황 : 원숭이 클래스가 동물 클래스를 상속받은 상황이다.
		// - 상황 : 자바는 이제 원숭이가 동물 이라는 것을 안다.
		// - 정답 1 : 동물리코몬으로 원숭이 객체를 조종해도 괜찮기 때문에 가능하다.
		// - 정답 2 : 원숭이리모콘이 동물리모콘으로 자동으로 바뀌어도(자동형변환) 문제가 없기 때문에 가능하다.
		// - 정답 3 : `a동물` 변수는 오직 동물객체랑 연결될 수 있다. 그런데 지금 원숭이 객체를 연결시키려고 하고 있다. 원숭이 객체는 동물객체이기 때문에 가능하다.
		동물 a동물 = a원숭이;
		
		원숭이 a원숭이2 = null; // null 은 쓰레기 리모콘이라는 뜻
		
		// 문제 2 : 아래 줄의 코드가 안되는 이유 설명
		// - 상황 : 동물리모콘은 원숭이 객체를 가리키고 있다.
		// - 상황 : 그렇지만 자바는 동물리모콘에 연결된 것이 동물객체라는 것은 알지만 그게 사람객체인지 동물객체인지는 알 수 없다.
		// - 상황 : `a원숭이2` 변수는 오직 원숭기 객체랑만 연결될 수 있다.
		// - 상황 : 동물리모콘이 원숭이 리모콘으로 변해야 하는 상황이다.
		// - 상황 : 기존의 리모콘에 `원숭이묘기를하다` 버튼을 추가로 넣어야 하는 상황이다.
		// - 정답 1 : 실제로 동물리모콘은 원숭이를 가리킨다. 하지만 자바는 그 사실을 알지 못하고 동물리모콘에 원숭이 아닌 다른 객체(예를들면 사람객체)가 연결되어 있지는 않을까 두려워 한다. 그렇기 때문에 임의로 동물리모콘에 `원숭이묘기를하다` 버튼을 추가하지 못한다.
		// - 정답 2
		// -- `a동물` 변수가 `a원숭이2` 변수에게 말한다.
		// -- "`a원숭이2`야 내가 지금 어떤 객체랑 연결되어 있는데, 너도 나랑 같은 객체와 연결되자!"
		// -- `a원숭이2` 변수는 말합니다.
		// -- "나는 오직 원숭이 객체랑만 연결될 수 있는데, 너가 연결되어 있는 객체가 원숭이객체 맞니?"
		// -- `a동물` 변수는 말합니다.
		// -- "나랑 연결되어 있는 객체가 동물객체인건 확실한데.. 그게 원숭이객체 인지 사람객체인지 고릴라객체인지는 알 수 없어. 그래도 원숭이객체일 확률이 있긴 하니까, 그냥 진행하지 않을래?"
		// -- `a원숭이2`가 말합니다.
		// -- "내가 지금 이렇게 넘어가면 프로그램을 실행하는 도중에 문제가 발생할 수 도 있어, 너도 알다시피 어떤 문제든 런타임보다 컴파일 타임에 발생하는게 좋잖아? 아무튼 이건 내선에서는 정할 수 없는 문제야. 일단 내가 여기서 에러를 발생시키면 개발자 이 문제를 인지하고, 최종적으로 넣을지 말지 결정해 주겠지. 일단 오류를 발생시킬게. 미안;;"
		// a원숭이2 = a동물;
		
		// 문제 3 : 아래 줄의 되는 이유 설명
		// - 상황 : 동물리모콘은 원숭이 객체를 가리키고 있다.
		// - 상황 : 그렇지만 자바는 동물리모콘에 연결된 것이 동물객체라는 것은 알지만 그게 사람객체인지 동물객체인지는 알 수 없다.
		// - 상황 : `a원숭이2` 변수는 오직 원숭기 객체랑만 연결될 수 있다.
		// - 상황 : 동물리모콘이 원숭이 리모콘으로 변해야 하는 상황이다.
		// - 상황 : 기존의 리모콘에 `원숭이묘기를하다` 버튼을 추가로 넣어야 하는 상황이다.
		// - 정답 1 : 실제로 동물리모콘은 원숭이를 가리킨다. 하지만 자바는 그 사실을 알지 못하고 동물리모콘에 원숭이 아닌 다른 객체(예를들면 사람객체)가 연결되어 있지는 않을까 두려워 한다. 그렇기 때문에 임의로 동물리모콘에 `원숭이묘기를하다` 버튼을 추가하지 못하는 상황이다. 그래서 자바가 `(원숭이)` 즉 수동형변환을 해주었다. 이 상황에서 자바는 여전히 불안하긴 하지만 그냥 개발자 믿고 컴파일 오류를 발생하지 않는다.
		// - 정답 2
		// -- `a동물` 변수가 `a원숭이2` 변수에게 말한다.
		// -- "`a원숭이2`야 내가 지금 어떤 객체랑 연결되어 있는데, 너도 나랑 같은 객체와 연결되자!"
		// -- `a원숭이2` 변수는 말합니다.
		// -- "나는 오직 원숭이 객체랑만 연결될 수 있는데, 너가 연결되어 있는 객체가 원숭이객체 맞니?"
		// -- `a동물` 변수는 말합니다.
		// -- "나랑 연결되어 있는 객체가 동물객체인건 확실한데.. 그게 원숭이객체 인지 사람객체인지 고릴라객체인지는 알 수 없어. 그래도 원숭이객체일 확률이 있긴 하니까, 그냥 진행하지 않을래? 내 앞에 붙은 `(원숭이)` 이거 보이지? 이거 개발자가 사인 한거야. 개발자님 믿고 그냥 진행하자. 실제로 이게 문제가 되어서 사용자가 이 프로그램을 사용하다가 오류가 난다고 하더라도 우리책임은 아니잖아 ㅎㅎ"
		// -- `a원숭이2`가 말합니다.
		// -- "불안하긴 한데... 개발자님이 생각이 있으시니까 사인하셨겠지, 그냥 진행하자!"
		a원숭이2 = (원숭이)a동물;
		
		사람 a사람2 = null;
		
		// 문제 4 : 아래 줄의 코드가 수동 형변환 까지 했는데도 안되는 이유 설명
		// 상황 : `a사람2` 변수는 오직 사람객체랑만 연결 가능 합니다.
		// 상황 : `a동물` 변수는 오직 동물객체랑만 연결 가능 합니다.
		// 상황 : `a동물` 변수는 현재 원숭이객체와 연결되어 있습니다.
		// - 정답 1
		// -- `a동물` 변수가 `a사람2` 변수에게 말한다.
		// -- "`a사람2`야 내가 지금 어떤 객체랑 연결되어 있는데, 너도 나랑 같은 객체와 연결되자!"
		// -- `a사람2` 변수는 말합니다.
		// -- "나는 오직 사람객체랑만 연결될 수 있는데, 너가 연결되어 있는 객체가 사람객체가 맞니?"
		// -- `a동물` 변수는 말합니다.
		// -- "나랑 연결되어 있는 객체가 동물객체인건 확실한데.. 그게 원숭이객체 인지 사람객체인지 고릴라객체인지는 알 수 없어. 그래도 사람객체일 확률이 있긴 하니까, 그냥 진행하지 않을래? 내 앞에 붙은 `(사람)` 이거 보이지? 이거 개발자가 사인 한거야. 개발자님 믿고 그냥 진행하자. 실제로 이게 문제가 되어서 사용자가 이 프로그램을 사용하다가 오류가 난다고 하더라도 우리책임은 아니잖아 ㅎㅎ"
		// -- `a사람2`가 말합니다.
		// -- "불안하긴 한데... 개발자님이 생각이 있으시니까 사인하셨겠지, 그냥 진행하자!"
		// -- 몇일뒤
		// -- 실제로 아래 코드가 실행되었을 때
		// -- `Exception in thread "main" java.lang.ClassCastException: 원숭이 cannot be cast to 사람` 예외가 발생하였습니다.
		// -- `원숭이 cannot be cast to 사람` 는 원숭이 리모콘을 사람 리모콘으로 캐스팅(형변환)하는 게 안된다는 뜻 입니다.(왜냐하면 당연히 안되는 거니까요. 그 이유는 직접 생각해 보세요.)
		// -- 실행 중 문제를 뜻하는 예외(Exception)가 발생해서 고객에게 클레임이 들어왔고 개발자는 선임에게 불려가 혼이 났습니다.
		// a사람2 = (사람)a동물;
		
	}
}
abstract class 동물 {
	void 숨쉬다() {
		System.out.println("동물이 숨을 쉽니다.");
	}
}
class 사람 extends 동물 {
	void 말하다() {
		System.out.println("사람이 말을 합니다.");
	}
}
class 원숭이 extends 동물 {
	void 원숭이묘기를하다() {
		System.out.println("원숭이묘기를하다.");
	}
}

문제 : a무기.공격(); 가 실행되는 세부과정을 자세히 쓰세요.

// 문제 : `a무기.공격();` 가 실행되는 세부과정을 자세히 쓰세요.

class Main {
  public static void main(String[] args) {
    무기 a무기 = new();
    
    // 리모컨이 두개(무기, 칼 class)가 있고 무기 리모컨으로 칼을 제어하고싶다.
	// 무기 리모컨에 칼로 연결되는 리모컨 버튼(void 공격() { })이 없어서 칼 리모컨에 접근할 수 없다.
	// 그리고 칼 리모컨엔 무기를 상속받았고 실제 실행값이 있다. 
	  a무기.공격();
  }
}

class 무기 {
  
}

classextends 무기 {
  void 공격() { }
}
class Main {
	public static void main(String[] args) {
		게임 a게임 = new 게임();
		게임.작동하다();
	}
}
class 게임 {
	// static은 설계도에 바로 접근할 수 있는 키워드
	static void 작동하다() {
		// 설명 : 무기형의 무기변수 선언
		무기 a무기;
		
		// 설명 : 무기 설계도에 맞춘 무기 객체 리모컨 변수에 할당
		a무기 = new 무기();
	}
}
class 무기 { // 무기 설계도
	void 공격() {}
}
class Main {
	public static void main(String[] args) {
		// 'class 칼 extends 무기 {}' 의 의미 설명
		// 칼 class는 무기 class의 메서드를 상속받는다.
		// 칼 리모컨이 a무기에 담긴다. 그런데 형변환에 의해서 무기 리모컨에 칼 리모컨이 담긴다. -선생님 설명
		// 무기 class에 공격은 단독으로 실행될 수 있다.
		// 칼 class에 사과껍질제거는 단독으로 실행될 수 없다. (칼class는 무기class를 상속받았고 무기class에 사과껍질제거를 실행할 버튼이 없다.)
		// 
		무기 a무기 = new(); // 무기 타입으로 a무기를 선언하고 칼class의 값을 할당해줬다.
		// 무기리모컨에서 공격버튼을 누른다. 그 버튼을 누르면 칼이 공격한다. -선생님 설명
		a무기.공격(); // 선언된 a무기는 무기class타입이기 때문에 무기class의 내용을 먼저 참조하고 메서드를 출력한다.
		// a무기는 칼class의 값을 가지고 있고 칼class는 무기class를 상속받았지만 칼class에 공격 메서드가 없기때문에 칼 class 내엔 불러올 값이 없다 고로 a무기는 무기class에 있는 공격 메서드만 출력한다.
		
	}
}
class 무기 {
	void 공격 () {
		System.out.println("공격");
	}
}
classextends 무기 {
	void 사과껍질제거() {
		System.out.println("사과껍질깎기");
	}
}

이해했는지 확인하는 문제
=>이해못함. 복습 필요

// 문제 : 매개변수를 사용해서 전사가 매번 다르게 공격하도록 해주세요.

class Main {
  public static void main(String[] args) {
	  전사 a전사 = new 전사();

    a전사.공격(/* 수정가능지역 시작 */"브라이언", "칼" /* 수정가능지역 끝 */); 
    // 브라이언이(가) 칼(으)로 공격합니다.
	  

    a전사.공격(/* 수정가능지역 시작 */"필립", "창" /* 수정가능지역 끝 */); 
    // 필립이(가) 창(으)로 공격합니다.
	  
	 a전사.공격(/* 수정가능지역 시작 */"마크", "지팡이"/* 수정가능지역 끝 */); 
    // 마크(가) 지팡이(으)로 공격합니다.
  }
}
class 전사 {
	String 이름;
	String 무기;
	void 공격 (String 이름, String 무기) {
		System.out.println(이름 + "이(가) " + 무기 + "(으)로 공격합니다.");
	}
}

위 문제 정답 응용해서 오버라이딩

// 문제 : 매개변수를 사용해서 전사가 매번 다르게 공격하도록 해주세요.
class Main {
  public static void main(String[] args) {
	  전사 a전사 = new 전사();
	  
	  a전사.공격(/* 수정가능지역 시작 */"브라이언", "칼"/* 수정가능지역 끝 */);
	  a전사.공격(/* 수정가능지역 시작 */"필립", "창"/* 수정가능지역 끝 */);
	  a전사.공격(/* 수정가능지역 시작 */"마크", "지팡이"/* 수정가능지역 끝 */);

    a전사.공격(/* 수정가능지역 시작 */"브라이언", "칼", 100 /* 수정가능지역 끝 */); // 오버라이딩 조건값
    // 브라이언이(가) 칼(으)로 공격합니다.

    a전사.공격(/* 수정가능지역 시작 */"필립", "창", 200 /* 수정가능지역 끝 */); // 오버라이딩 조건값
    // 필립이(가) 창(으)로 공격합니다.
	  
	 a전사.공격(/* 수정가능지역 시작 */"마크", "지팡이", 15/* 수정가능지역 끝 */); // 오버라이딩 조건값
    // 마크(가) 지팡이(으)로 공격합니다.
  }
}
class 전사 {
	void 공격 (String 이름, String 무기) {
		System.out.println(이름 + "이(가) " + 무기 + "(으)로 공격합니다.");
	}
	void 공격 (String 이름, String 무기, int 데미지) { // 오버라이딩
		System.out.println(이름 + "이(가) " + 무기 + "(으)로 공격합니다." + " \n데미지 : " + 데미지);
	}
}

this.과 인스턴스 변수를 이해하면 풀 수 있는 재공격 문제

// 문제 : 매개변수를 사용해서 전사가 매번 다르게 공격하도록 해주세요.

class Main {
  public static void main(String[] args) {
    전사 a전사 = new 전사();

    a전사.공격(/* 수정가능지역 시작 */"브라이언", "칼" /* 수정가능지역 끝 */); 
    // 브라이언이(가) 칼(으)로 공격합니다.

    a전사.재공격();
    // 브라이언이(가) 칼(으)로 공격합니다.

    a전사.공격(/* 수정가능지역 시작 */ "필립", "창"/* 수정가능지역 끝 */); 
    // 필립이(가) 창(으)로 공격합니다.

    a전사.공격(/* 수정가능지역 시작 */ "마크", "지팡이"/* 수정가능지역 끝 */); 
    // 마크(가) 지팡이(으)로 공격합니다.

    a전사.재공격();
    // 마크(가) 지팡이(으)로 공격합니다.

    a전사.재공격();
    // 마크(가) 지팡이(으)로 공격합니다.
  }
}
class 전사 {
	String 이름;
	String 무기;
	void 공격 (String 이름, String 무기) {
		this.이름 = 이름;
		this.무기 = 무기;
		System.out.println(이름 + "이(가) " + 무기 + "(으)로 공격합니다");
	}
	void 재공격 () {
		System.out.println(이름 + "이(가) " + 무기 + "(으)로 재공격합니다");
	}
}

상속과 abstract, 매개변수 이용해서 관계 이해하기 이 관계 이해되면 다 됨. (수업페이지 자바기초 30강)

class Main {
	public static void main(String[] args) {
		전사 a전사 = new 전사();
		String 이름 = "카니";
		a전사.이름 = 이름;
		a전사.a무기 = new();
		a전사.공격();
		// 출력 : 카니가 활로 공격합니다.
		a전사.a무기 = new();
		a전사.공격();
		// 출력 : 카니가 칼로 공격합니다.
	}
}
class 전사 {
	String 이름;
	int 나이;
	무기 a무기;
	void 공격 () {
		a무기.실행(this.이름);
	}
}
abstract class 무기{
	abstract void 실행 (String 이름);
}
classextends 무기 {
	void 실행 (String 이름) {
		System.out.println(이름 + "가 활로 공격합니다.");
	}
}
classextends 무기 {
	void 실행 (String 이름) {
		System.out.println(이름 + "가 칼로 공격합니다.");
	}
}
profile
문제 해결을 위해 끊임없이 파고드는 걸 좋아합니다.

0개의 댓글