package com.interface_.animal;
/**
* 4.23 인터페이스
*
* How
* Interface를 선언하면 된다.
* 여기 안에 선언된 메서드는
* 모두 추상메서드가 돼야 한다.
*
* Why?
*/
public interface Animal {
//추상메서드 선언
public abstract void eat(); // 메서드 선언부만 있고 바디가 없다.
public void move(); // abstract 생략 가능
}//end of Animal
package com.interface_.animal;
/**
* 4.23 인터페이스
*/
public class Bird implements Animal{
@Override
public void eat() {
System.out.println("새가 모이를 먹는다");
}
@Override
public void move() {
System.out.println("새가 하늘을 난다");
}
}//end of Bird
package com.interface_.animal;
/**
* 4.23 인터페이스
* <p>
* 인터페이스는 상속이 아니라 구현받다, 구현하다 라고 말한다.
* <p>
* Animal 인터페이스를 구현받았다.
*/
public class Dog implements Animal {
//추상메서드를 구현메서드로 재정의 해야 한다.
@Override
public void eat() {
System.out.println("강아지가 먹이를 먹는다");
}
@Override
public void move() {
System.out.println("강아지가 달린다");
}
//main
public static void main(String[] args) {
//다형성 적용
Animal dog = new Dog(); //업캐스팅 됐다
Animal bird = new Bird();
dog.eat();
dog.move();
System.out.println();
bird.eat();
bird.move();
}//end of main
}//end of dog
public class Refrigerator implements Animal, SoundEffect { //인터페이스 구현
2-1.TV 클래스
package com.interface_.appliance;
/**
* 4.23 인터페이스 2강
*/
public class Television extends HomeAppliances implements RemoteController {
// //member
// int width;
// int height;
// String color;
//
// //method
// public void turnOn() {
// System.out.println("TV전원을 켠다");
// }
// public void turnOff() {
// System.out.println("TV전원을 끈다");
// }
@Override
public void turnOn() {
System.out.println("티비 전원을 켠다");
}
@Override
public void turnOff() {
System.out.println("티비 전원을 끈다");
}
}//end of TV
2-2.냉장고
package com.interface_.appliance;
/**
* 4.23 인터페이스 2강
*/
public class Refrigerator extends HomeAppliances
implements RemoteController, SoundEffect { // 인터페이스는 다중 구현이 가능하다.
@Override
public void turnOn() {
System.out.println("냉장고 전원을 켠다");
}
@Override
public void turnOff() {
System.out.println("냉장고 전원을 끈다");
}
@Override
public void soundOn() {
System.out.println("냉장고 문이 열렸다고 경고한다");
}
}//end of Refrige
2-3.장난감로봇
package com.interface_.appliance;
/**
* 4.23 인터페이스 2강
*
* 지금처럼 장난감 로봇이 가전을 상속받는다면 혼동이 올 수 있다.
*
* 추상클래스보다
* 더 유연한 설계기법이 필요하다.
*
* 그것이 인터페이스 Interface 다.
*/
public class ToyRobot implements RemoteController, SoundEffect {
String name;
@Override
public void turnOn() {
System.out.println("장난감 로봇을 켠다");
}
@Override
public void turnOff() {
System.out.println("장난감 로봇을 끈다");
}
@Override
public void soundOn() {
System.out.println("장난감 로봇이 소리를 낸다");
}
}//end of TR
2-4.가전 (추상클래스)
package com.interface_.appliance;
/**
* 4.23 인터페이스 2강
*/
public abstract class HomeAppliances implements RemoteController {
//member
int width;
int height;
String color;
// //method
// public void turnOn() {
// System.out.println("전원을 켠다");
// }
// public void turnOff() {
// System.out.println("전원을 끈다");
// }
}//end of HA
2-5. 리모콘 (인터페이스)
package com.interface_.appliance;
/**
* 4.23 인터페이스 2강
*
* 인터페이스 개념정리
*/
public interface RemoteController {
/*
⭐인터페이스란
구현된 것이 아무것도 없는
밑 그림만 있는 기본 설계도다.
모든 변수는 상수가 된다.
public static final int N;
모든 메서드는 추상메서드가 된다.
심지어 abstract 키워드도 필요 없다.
추상클래스보다 추상화 수준이 더 높다.
⭐Why
인터페이스는
동작 중심의 클래스를 선언해야 할 때 사용한다.
인터페이스는 동작 중심이다.
인터페이스는 표준이다.
또는 강제성 있는 규약이다.
*/
//오직 static final 상수만을 가질 수 있다.
public static final int SERIAL_NUMBER = 100;
//오직 abstract 추상 메서드만을 가질 수 있다.
public abstract void turnOn();
public void turnOff();
}//end of RemoteController
2-6. 음향(인터페이스)
package com.interface_.appliance;
/**
* 4.23 인터페이스 2강
*/
public interface SoundEffect {
//추상메서드
public abstract void soundOn();
}//end of SE
2-7. 코드 실행부
package com.interface_.appliance;
/**
* 4.23 인터페이스 2강
*/
public class MainTest1 {
//main
public static void main(String[] args) {
/*
인터페이스를 사용하면
유연한 코드를 설계할 수 있다.
*/
RemoteController[] remoteControllers = new RemoteController[3];
remoteControllers[0] = new Television(); //다형성
remoteControllers[1] = new Refrigerator();
remoteControllers[2] = new ToyRobot();
/*
인터페이스는 표준이다.
또는 강제성 있는 규약이다.
*/
for (int i = 0; i < remoteControllers.length; i++) {
remoteControllers[i].turnOn(); //한번에 모든 전원을 켰다.
}
}//end of main
}
예제 3)
다음 코드다이어그램(uml) 구현
Calc, 인터페이스로 작성
Claclator, 추상클래스로 작성
CompleteCalc, 구현클래스로 작성
⭐코드설계가 이미 완성돼 있다면
탑다운으로 작성하더라도 문제가 없다.
3-1.Calc(인터페이스) 작성
package com.interface_;
/**
* 4.23 인터페이스 3강
*/
public interface Calc { //인터페이스 선언
//인터페이스는 public abstract 생략 가능
void add(int n1, int n2);
void sub(int n1, int n2);
void multi(int n1, int n2);
void divide(int n1, int n2);
}//end of Calc
3-2. Calculator(추상클래스) 작성
package com.interface_;
/**
* 4.23 인터페이스 3강
*/
public abstract class Calculator implements Calc {
}//end of Calculator
3-3. CompleteCalc(구현클래스) 작성
F2를 누르면 구현메서드를 딸깍하고 만들 수 있다.
package com.interface_;
/**
* 4.23 인터페이스 3강
*/
public class CompleteCalc extends Calculator{
@Override
public void add(int n1, int n2) {
}
@Override
public void sub(int n1, int n2) {
}
@Override
public void multi(int n1, int n2) {
}
@Override
public void divide(int n1, int n2) {
}
}//end of CompleteCalc
package com.abstract_.animal;
/**
* 4.22 5교시 추상클래스
* <p>
* 추상클래스
* abstract class
* <p>
* 하나 이상의 추상 메서드를 포함한 클래스
* class 앞에 abstract가 뭍으면 추상클래스다.
*
* 강제적으로 타입으로만 설계하는 기법이다.
*
* abstract - 강제성
*/
public abstract class Animal { //추상클래스로 선언됐다.
String name;
public void move() {
System.out.println("동물이 이동한다");
}
//추상메서드를 만들어보자
public abstract void hunt();
/*
클래스 안에
단 하나라도 추상 메서드를 가지고 있다면
그 클래스는 반드시 추상 클래스가 돼야 한다.
*/
}//end of Animal
2. 자식클래스 호랑이
추상클래스를 상속받으면, 이렇게 오류가 발생한다. 해결방법은 1.자식클래스도 추상클래스로 변경 2.추상메서드를 구현메서드로 오버라이드 하는 방법이다.
package com.abstract_.animal;
/**
* 4.22 5교시 추상클래스
*
* 추상클래스를 사용하는 이유
*
* 단 하나라도 추상메서드가 있으면 추상클래스다.
*/
public class Tiger extends Animal {
@Override //오버라이드 하자 오류가 없어졌다
public void hunt() {
System.out.println("호랑이가 사냥을 한다");
}
@Override
public void move() {
System.out.println("호랑이가 살금살금 이동한다");
}
}//end of Tiger
3.자식클래스이자 추상클래스인 인간을 설계해봤다.
package com.abstract_.animal;
/**
* 4.22 5교시 추상클래스
*/
public abstract class Human extends Animal{
@Override
public void move() {
System.out.println("사람이 두 발로 걷는다");
}
}//end of Human
4. 인간 클래스의 자식클래스인 사람 클래스를 설계했다.
package com.abstract_.animal;
/**
* 4.22 5교시 추상클래스
*/
public class Person extends Human{
//구현 메서드로 만들어주면 된다.
@Override
public void hunt() {
System.out.println("총으로 동물을 사냥한다");
}
}//end of Person
5. 코드 실행부
추상클래스인 Animal, Human을 인스턴스화 하려고 하자 오류가 발생했다.
추상클래스를 객체 선언할 수 없다.
package com.abstract_.animal;
/**
* 4.22 5교시 추상클래스
*/
public class MainTest1 {
//main
public static void main(String[] args) {
/*
객체지향 개념으로
Animal이라는 클래스를 인스턴스화하면 좀 이상하다
*/
// animal = new Animal(); // 오류발생
/*
Animal 클래스는
abstract 키워드를 사용해
추상 클래스로 설계됐다.
추상 클래스는
new 키워드 생성자를 활용해서
독립적으로 메모리에 올릴 수 없다.
개발자가 객체를 생성시킬 때
다른 사용자가 마음대로 객체를 생성시키지 못하도록
강제성을 줄 수 있다.
*/
// Human human = new Human(); //오류 발생
}//end of main
}//end of class
package com.abstract_.computer;
/**
* 4.22 5_1교시 추상클래스
* 구현클래스
* Computer의 자식클래스
*/
public class DeskTop extends Computer {
void display() { System.out.println("데스크탑 화면을 띄웁니다"); }
void typing() { System.out.println("데스크탑에 문자를 입력합니다"); }
}//end of DeskTop
2-2. 노트북 클래스
추상클래스로 설계했다.
package com.abstract_.computer;
/**
* 4.22 5_1교시 추상클래스
* 추상클래스
* Computer의 자식클래스
*/
public abstract class NoteBook extends Computer {
void typing() { System.out.println("노트북에 글자를 입력합니다"); }
}//end of NoteBook
3. 내노트북 클래스
구현클래스로 설계했다(완)
package com.abstract_.computer;
/**
* 4.22 5_1교시 추상클래스
* 구현클래스
* NoteBook의 자식클래스
*/
public class MyNoteBook extends NoteBook {
void display() { System.out.println("내 노트북 화면을 띄웁니다"); }
}//end of MyNoteBook
4. 코드 실행부
데스크탑과 내노트북 클래스로 객체선언이 정상적으로 되는 것을 확인했다.
package com.abstract_.computer;
/**
* 4.22 5_1교시 추상클래스
* 코드 실행부
*/
public class ComperMainTest1 {
//main
public static void main(String[] args) {
Computer computer1 = new DeskTop(); //다형성
Computer computer2 = new MyNoteBook();
}//end of main
}//end of class
부모 타입으로 자식 클래스를 인스턴스화 할 수 있다는 점이다. 이는 자바의 굉장한 기능이다.
다형성을 이해한다면 유연한 코드를 작성할 수 있다.
예제) 동물 클래스를 인간, 호랑이 클래스가 상속하게 하자
package com.polymorphism;
/**
* 4.22 3교시 다형성
*/
public class Animal {
public void move() {
System.out.println("동물이 움직인다");
}
public void eat() {
System.out.println("동물이 먹는다");
}
}//end of Animal class
class Human extends Animal { // 상속 관계로 설정... 다형성
@Override
public void move() {
System.out.println("사람이 걷는다");
}
@Override
public void eat() {
System.out.println("사람이 식사한다");
}
public void read() {
System.out.println("사람이 읽는다");
}
}//end of Human class
class Tiger extends Animal {
@Override
public void move() {
System.out.println("호랑이가 활보한다");
}
public void hunt() {
System.out.println("호랑이가 사냥한다");
}
}//end of Tiger class
코드 테스트
package com.polymorphism;
/**
* 4.22 3교시 다형성
*
* 다형성
* 하나의 데이터 타입을 다양한 형태로 바라보는 것
*
* 한 메서드(클래스)가 여러 형태를 가질 수 있다.
* 상속관계를 통해 다형성을 살펴본다.
*/
public class AnimalTest1 {
//main
public static void main(String[] args) {
Animal animal1 = new Animal();
animal1.move();
animal1.eat();
System.out.println();
/*
다형성의 장점
부모 타입으로 자식 클래스를 인스턴스화 할 수 있다.
이는 자바의 굉장한 기능
*/
Animal animal2 = new Tiger(); //? 다형성.. 업캐스팅
animal2.move();
animal2.eat();
System.out.println();
/*
코드를 작성하는 컴파일 시점
프로그램을 실행하는 런타임 시점
*/
Animal animal3 = new Human();
animal3.move();
animal3.eat();
}//end of main
}//end of class
코드테스트2
package com.polymorphism;
/**
* 4.22 3교시 다형성
*/
public class AnimalTest2 {
//main
public static void main(String[] args) {
/*
다형성
하나의 메서드가
여러 형태를 가질 수 있는 능력
move()
배열
하나의 변수에 통으로 데이터를 관리하고 싶다면
*/
Animal[] animals = new Animal[3];
animals[0] = new Animal();
animals[1] = new Tiger();
animals[2] = new Human();
for (int i = 0; i < animals.length; i++) {
animals[i].move();
}
}//end of main
}//end of class
⭐업캐스팅 / 다운캐스팅
업캐스팅
부모클래스의 데이터타입으로 자식클래스의 객체를 대입하는 것을 말한다.
이는 자동으로 이뤄진다.
다운캐스팅
부모클래스의 참조변수를 자식클래스의 객체로
((Banana) fruits[i]).saleBanana();
이 객체가 특정 클래스에 종속됐는지 확인하는 구문
if (fruits[i] instanceof Banana) {}
예제)
복숭아, 바나나 클래스를 만들고
부모클래스인 과일 클래스를 만들어보자
1. 복숭아 클래스
package com.polymorphism.fruits;
/**
* 4.22 3_1교시 다형성
*
* 과일을 통해
* 상속
* 바텀업
* 업캐스팅
* 다운캐스팅 이해
*/
public class Peach extends Fruit {
// String name;
// int price;
public Peach() {
name = "춘식이복숭아";
price = 5000;
}
}//end of Peach
2. 바나나 클래스
바나나 클래스에는 고유의 멤버변수와 메서드를 넣었다.
package com.polymorphism.fruits;
/**
* 4.22 3_1교시 다형성
*/
public class Banana extends Fruit {
String ogrin; // Banana만의 멤버변수
public Banana() {
name = "델몬트바나나";
price = 3000;
ogrin = "필리핀";
}
public void saleBanana() {
System.out.println("지금은 할인 기간입니다");
System.out.println("이 방송이 나간 뒤(메서드호출) 바나나 가격을 천원 할인");
price -= 1000;
}
}//end of Banana
3. 부모클래스인 과일 클래스 설계
package com.polymorphism.fruits;
/**
* 4.22 3_1교시 다형성
*/
public class Fruit {
String name;
int price;
public Fruit() {
name = "춘식이복숭아";
price = 5000;
}
public void showInfo() {
System.out.print("상품명: ");
System.out.print(name + " ");
System.out.print("가격: ");
System.out.println(price + "원");
}
}//end of Fruits
4. 코드 실행부
package com.polymorphism.fruits;
/**
* 4.22 3_1교시 다형성
*
* 업캐스팅
* 다운캐스팅
*/
public class FruitTest1 {
//main
public static void main(String[] args) {
Fruit fruit1 = new Peach(); //업캐스팅된 상태
Fruit fruit2 = new Banana();
fruit1.showInfo();
fruit2.showInfo();
System.out.println();
/*
바나나의 원산지 정보를 출력하시오
이 문제는
컴파일 시점과 런타임 시점을 이해해야 한다.
업캐스팅된 상태에서는
컴파일 시점에 부모에 있는 변수나 메서드만 이해 가능
*/
//fruit2.orign
String reultOrigin = ((Banana)fruit2).ogrin; // 다운캐스팅
System.out.println("바나나 원산지: " + reultOrigin);
System.out.println();
/*
인스턴스오브 연산자
instanceof
↳예약어
다운캐스팅 관련 활용가능한 기능
*/
if (fruit2 instanceof Banana) { // true
System.out.println("바나나인가? true");
}
if (fruit2 instanceof Peach) { // false
System.out.println("복숭아인가? true");
}
System.out.println();
/*
fruit2에 saleBanana() 메서드를 호출하시오
*/
((Banana)fruit2).saleBanana(); //다운캐스팅
fruit2.showInfo();
}//end of main
}//end of class
5. 다운캐스팅 연습을 위한 심화문제
package com.polymorphism.fruits;
/**
* 4.22 3_1교시 다형성
*
* 업캐스팅
* 다운캐스팅
*/
public class EMart {
//main
public static void main(String[] args) {
Banana banana1 = new Banana();
Banana banana2 = new Banana();
/*
배열
배열을 사용할 때는
반드시 크기를 먼저 지정한다.
배열의 길이와
요소의 길이는 항상 동일한 것은 아니다.
*/
Banana[] bananas = new Banana[10];
bananas[0] = banana1;
bananas[1] = banana2;
Peach[] peaches = new Peach[3];
peaches[0] = new Peach();
peaches[1] = new Peach();
System.out.println();
/*
다형성
다형성을 이해한다면
유연한 코드를 작성할 수 있다.
*/
Fruit[] fruits = new Fruit[5];
fruits[0] = new Banana();
fruits[1] = new Peach();
fruits[2] = new Banana();
fruits[3] = new Peach();
/*
문제
배열 안에 들어있는 각각의 객체 showInfo 호출
데이터타입이 바나나면
원산지 정보와 세일 메서드를 호출하라
*/
for (int i = 0; i < fruits.length; i++) {
if (fruits[i] != null) {
if (fruits[i] instanceof Banana) {
System.out.print((i + 1) + "번 ");
fruits[i].showInfo();
System.out.println("원산지: " + ((Banana) fruits[i]).ogrin);
((Banana) fruits[i]).saleBanana();
System.out.println("===== ===== =====");
} else {
System.out.print((i + 1) + "번 ");
fruits[i].showInfo();
System.out.println("===== ===== =====");
}//end of if
}//defensive
}//end of for
}//end of main
}//end of class
클래스 간의 느슨한 결합 두 객체의 생명주기는 종속되지 않는다. (생명주기 = 선언~GC)
ex)
학생과 과목
선수와 팀
이는 폭넓은 개념인데 포함관계도 연관관계의 일부다. ⭐ 내부에서 객체가 생성될 때 따로 포함관계라고 한다
1. 학생 클래스 설계
package com.association;
/**
* 4.22 2교시 연관관계
*
* 학생과 과목 클래스의 연관관계를 만들어본다
*/
public class Student {
//member
private String name;
private Course course; //연관관계
//constructor
public Student(String name) {
this.name = name;
course = null; //수강 없음
}
//method
/*
1.강의를 듣는 메서드를 만든다.
과목에 대한 정보는 Course에 있다.
2.학생의 현재 수강상태를 보여주는 기능
3.수강 종료 기능을 만들어보시오
*/
// public void takeCourse(Course course) {
// System.out.println(this.name + "의 수강 과목");
// course.display();
// }
public void enroll(Course course) {
this.course = course;
System.out.println(name + ", " + course.getName() + " 과목 등록" );
}
public void showCourse() {
if (this.course != null) {
System.out.println(this.course.getName() + " 과목을 수강중입니다.");
} else {
System.out.println("수강중인 과목 없음");
}
}
public void end(Course course) {
if (course == null) {
System.out.println("수강중이 아닙니다");
} else {
System.out.println(course.getName() + " 수강 취소");
this.course = null;
}
}
}//end of Student
2. 과목 클래스 설계
package com.association;
/**
* 4.22 2교시 연관관계
*
* 학생과 과목 클래스의 연관관계를 만들어본다
*/
public class Course {
//member
private String name;
//constructor
public Course(String name) {
this.name = name;
}
//getter
public String getName() {
return name;
}
public void display() {
System.out.println(name + "강의");
}
}//end of Course
3. 코드 실행부
package com.association;
/**
* 4.22 2교시 연관관계
*/
public class MainTest1 {
//main
public static void main(String[] args) {
Student student = new Student("홍길동");
Course java = new Course("자바");
Course db = new Course("데이터베이스");
student.showCourse(); //상태
System.out.println();
student.enroll(java); //강의등록
student.showCourse(); //상태
System.out.println();
student.end(java); //수강취소
student.showCourse(); //상태
}//end of main
}//end of class
다음으로 선수와 팀을 만들어 연관관계를 만들어봤다.
1.선수 클래스 설계
package com.association;
/**
* 4.22 2_2교시 연관관계
*/
public class Player {
//member
private String name;
private Team team;
//constructor
public Player(String name) {
this.name = name;
}
//getter
public String getName() {
return name;
}
//method - 입단
public void join(Team team) {
this.team = team;
System.out.println(name + " " + team.getName() + " 입단");
}
//method - 탈단
public void leave(Team team) {
System.out.println(name + " " + team.getName() + " 탈단");
this.team = null;
}
//method - 현황
public void showRoster() {
System.out.print(name + " 팀 현황: ");
if (this.team != null) {
System.out.println(this.team.getName());
} else {
System.out.println("소속 팀 없음");
}
}
}//end of Player
2.팀 클래스 설계
package com.association;
/**
* 4.22 2_2교시 연관관계
*/
public class Team {
//member
private String name;
private Player player; //연관관계
//constructor
public Team(String name) {
this.name = name;
}
//getter
public String getName() {
return name;
}
//method - 영입
public void recruit(Player player) {
this.player = player;
System.out.println(name + " " + player.getName() + " 선수 영입");
}
//method - 방출
public void release(Player player) {
System.out.println(name + " " + player.getName() + " 선수 방출");
this.player = null;
}
//method - 현황
public void showRoster() {
System.out.print(name + " 선수 현황: ");
if (this.player != null) {
System.out.println(this.player.getName());
} else {
System.out.println("등록 선수 없음");
}
}
}//end of Team
3. 코드 실행부
package com.association;
/**
* 4.22 2_2교시 연관관계
*/
public class MainTest2 {
//main
public static void main(String[] args) {
Team team1 = new Team("롯데");
Player player1 = new Player("장원준");
team1.showRoster();
System.out.println();
team1.recruit(player1);
team1.showRoster();
System.out.println();
team1.release(player1);
team1.showRoster();
System.out.println();
player1.showRoster();
System.out.println();
player1.join(team1);
player1.showRoster();
System.out.println();
player1.leave(team1);
player1.showRoster();
}//end of main
}//end of class
package com.inheritance.animal;
/**
* 4.22 1교시 상속 심화
* xxx.java 파일에는 public을 가진 클래스는 오직 하나만 존재할 수 있다.
*/
//부모 클래스
class Animal {
/*
protected
접근제어지시자의 한 종류
자식클래스에서만 접근 가능하게 된다.
*/
protected String name;
void bark() {
System.out.println(name + " 짖는 중");
}
void eat() {
System.out.println(name + " 먹이 먹는 중");
}
}//end of Animal
//자식 클래스1
class Dog extends Animal {
// void bark() {
// System.out.println(name + " 멍멍 짖는 중");
// }
@Override // 어노테이션 = 주석+힌트 : 부모클래스의 메서드 eat 오버라이드
void eat() {
// super.eat(); 기존 필드.. 필요하다면 사용
// 강아지 전용 코드 작성
System.out.println(name + "사료 먹는 중");
}
}//end of Dog
//자식 클래스2
class Cat extends Animal {
// void bark() {
// System.out.println(name + " 야옹 하는 중");
// }
@Override
void eat() {
// super.eat();
//고양이 먹는 모습 구현
}
}//end of Cat
public class Main1 {
//main
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "바둑이";
dog.eat(); // 부모클래스 메서드 호출
dog.bark(); // 자식클래스 메서드 호출
}//end of main
}//end of class
/**
* 보다 일반적인 개념이 부모클래스가 된다. 동물 <= 개
*/
package com.inheritance.animal;
/**
* 4.22 1교시 상속 심화
*/
public class AnimalTest {
//main
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "멍멍이";
dog.bark();
Cat cat = new Cat();
cat.name = "야옹이";
cat.bark();
}//end of main
}//end of class
⭐상속 실무팁
탑 다운(부모 => 자식)으로 접근하면 문제가 발생할 가능성이 높아진다. 바텀 업(자식 => 부모)으로 접근하는 것이 안전
package com.composition;
/**
* 4.21 포함개념 8
*/
public class Engine {
//멤버변수설계
String name;
int price;
//메서드
void start() {
System.out.println("start() 엔진을 구동합니다.");
}
void stop() {
System.out.println("stop() 엔진을 정지합니다.");
}
}// end of Engine
/**
객체지향 패러다임 고민
Q 차와 엔진을 상속관계에 둬도 될까?
A 안된다 💀
*/
2. 차
차가 움직이려면 먼저 엔진이 가동해야 한다.
package com.composition;
/**
* 4.21 포함개념 8
*/
public class Car {
//멤버변수설계
String name;
int price;
/*
⭐Car 클래스는 Engine 객체를 포함한다.
포함관계(Compositoion)
*/
Engine engine;
//생성자
public Car(String name, int price) {
this.name = name;
this.price = price;
/*
자동차 객체가 생성될 때 엔진 객체도 함께 생성된다.
포함관계
⭐강한의존성
*/
engine = new Engine();
}
//메서드
void startCar() {
//car 객체를 통해 engine의 start(); 메서드를 호출한다
engine.start();
System.out.println("startCar() 자동차가 움직입니다.");
}
void stopCar() {
engine.stop();
System.out.println("stopCar() 자동차가 멈춥니다.");
}
//테스트코드작성
public static void main(String[] args) {
/*
⭐컴포지션 관계란
자동차 클래스 내부에서
엔진 객체를 생성시켜야 컴포지션 관계다
*/
Car car = new Car("소나타", 1000);
car.startCar(); // 시동걸기
System.out.println();
car.stopCar(); // 시동끄기
}//main
} // end of Car
또 다른 포함관계 예제
PC와 CPU 역시 강한 연관성(필수적)을 가지고 있다.
1.CPU
package com.composition;
/**
* 4.21 포함개념 8_1
*/
public class CPU {
//멤버변수
private String name;
private int id;
//메서드
void startCPU() {
System.out.println(this.name + "CPU 가동");
}
void stopCPU() {
System.out.println(this.name + "CPU 정지");
}
}//end of CPU
2. PC
package com.composition;
/**
* 4.21 포함개념 8_1
*/
public class PC {
//멤버변수
private String name;
private int id;
//CPU 객체 선언
CPU cpu;
//생성자
PC(String name, int id) {
this.name = name;
this.id = id;
cpu = new CPU();
}
//메서드
void startPC() {
cpu.startCPU();
System.out.println(this.name + " PC 가동");
}
void stopPC() {
cpu.stopCPU();
System.out.println(this.name + "PC 정지");
}
//main
public static void main(String[] args) {
PC pc1 = new PC("삼보", 1113);
PC pc2 = new PC("현대", 4321);
pc1.startPC();
pc1.stopPC();
System.out.println();
pc2.startPC();
pc2.stopPC();
}//end of main
}//end of PC
다른 형태의 포함관계를 생각해보자.
집과 방도 강한 연관성(필수적)을 가지고 있다.
1. 방
package com.composition;
/**
* 4.21 포함개념 8_2
*/
public class Room {
private String type;
public Room(String type) {
this.type = type;
}
void descrive() {
System.out.println(this.type + " 입니다.");
}
}// end of Room
2. 집
집은 여러개의 방으로 구성돼 있다.
반복되는 부분이 있는 점을 고려해
배열과 반복문을 응용해서 넣어봤다.
package com.composition;
/**
* 4.21 포함개념 8_2
*/
public class House {
private String address;
Room[] rooms;
public House(String address) {
this.address = address;
this.rooms = new Room[3];
rooms[0] = new Room("1.거실");
rooms[1] = new Room("2.침실");
rooms[2] = new Room("3.주방");
//속성으로 선언되고
//내붸서 객체생성
//컴포지션이다.
//room = new Room(type:"안방");
}
void showRoom() {
System.out.println(address+ "에 있는 한 주택의 방 목록: " );
for (int i = 0; i < rooms.length; i++) {
if (rooms[i] != null) {
rooms[i].descrive();
}
}
}
//테스트
public static void main(String[] args) {
House house = new House("부산시진구");
house.showRoom();
//house 객체가 소멸이 되면 rooms 도 Room 객체도 소멸
//GC에 의해 소멸
house = null;
}//end of main
}//end of House
package com.inheritance;
/**
* 4.21 상속개념 7
* 클래스 다이어그램 준수해야 한다.
*/
public class Customer {
//member
private int customerID;
private String customerName;
private String customerGrade;
private int bonuspoint;
private double bonusRatio;
static int idCount = 1;
//constructor
public Customer(String customerName) {
this.customerID = idCount;
idCount++;
this.customerName = customerName;
customerGrade = "일반";
bonuspoint = 0;
bonusRatio = 0.01;
}
//getter
int getCustomerID() {
return customerID;
}
String getCustomerName() {
return customerName;
}
String getCustomerGrade() {
return customerGrade;
}
int getBonuspoint() {
return bonuspoint;
}
//setter
void setCustomerGrade(String customerGrade) {
this.customerGrade = customerGrade;
}
//method
public int calcPrice(int int1) {
return (int) (bonusRatio * int1);
} //calcPrice
public void showCustomerInfo() {
System.out.print("고객 정보...");
System.out.print(" 고객ID: " + customerID);
System.out.print(" 고객이름: " + customerName);
System.out.print(" 고객등급: " + customerGrade + "(" + bonusRatio + ")");
System.out.println(" 포인트: " + bonuspoint);
} //showCustomerInfo
}//end of class
2.VIP클래스 설계
package com.inheritance;
/**
* 4.21 상속개념 7_1
* 클래스 다이어그램 준수해야 한다.
*/
public class VIPCustomer extends Customer {
//클래스속성
private int agentID;
private double salesRatio;
//생성자
public VIPCustomer(String customerName, int agentID) {
super(customerName);
this.agentID = agentID;
salesRatio = 0.03;
setCustomerGrade("VIP");
}
//getter
public int getAgentID() {
return agentID;
}
//메서드
public int calcPrice(int int1) {
return (int) (salesRatio * int1);
}
public void showCustomerInfo() {
System.out.print("고객 정보...");
System.out.print(" 고객ID: " + super.getCustomerID());
System.out.print(" 고객이름: " + super.getCustomerName());
System.out.print(" 고객등급: " + super.getCustomerGrade() + "(" + salesRatio + ")");
System.out.println(" 포인트: " + super.getBonuspoint());
}
}//end of class
3.GOLD 클래스 설계(VIP와 비슷)
package com.inheritance;
/**
* 4.21 상속개념 7_2
* 클래스 다이어그램 준수해야 한다.
*/
public class GoldCustomer extends Customer {
//클래스속성
private int agentID;
private double salesRatio;
//생성자
public GoldCustomer(String customerName, int agentID) {
super(customerName);
this.agentID = agentID;
salesRatio = 0.05;
setCustomerGrade("GOLD");
}
//getter
public int getAgentID() {
return agentID;
}
//메서드
public int calcPrice(int int1) {
return (int) (salesRatio * int1);
}
public void showCustomerInfo() {
System.out.print("고객 정보...");
System.out.print(" 고객ID: " + super.getCustomerID());
System.out.print(" 고객이름: " + super.getCustomerName());
System.out.print(" 고객등급: " + super.getCustomerGrade() + "(" + salesRatio + ")");
System.out.println(" 포인트: " + super.getBonuspoint());
}
}//end of class
4.실행부
package com.inheritance;
/**
* 4.21 상속개념 7_3
* 클래스 다이어그램 준수해야 한다.
*/
public class CustomerMainTest {
//main
public static void main(String[] args) {
Customer customer1 = new Customer("홍길동");
VIPCustomer vipCustomer1 = new VIPCustomer("장길산", 1);
GoldCustomer goldCustomer1 = new GoldCustomer("임꺽정", 1);
customer1.showCustomerInfo();
vipCustomer1.showCustomerInfo();
goldCustomer1.showCustomerInfo();
System.out.println(customer1.getCustomerName() + "이 받을 포인트: " + customer1.calcPrice(1000));
System.out.println(vipCustomer1.getCustomerName() + "이 받을 포인트: " + vipCustomer1.calcPrice(1000));
System.out.println(goldCustomer1.getCustomerName() + "이 받을 포인트: " + goldCustomer1.calcPrice(1000));
}//end of main
}//end of class
한편 xxx.java 파일 하나에 여러 클래스를 선언할 수 있다. 단 스코프는 분명히 구분된다.
또한 단 하나의 자바파일에 public 클래스는 오직 하나만 존재할 수 있다.
package com.inheritance;
/**
* 4.21 2강 상속개념 5
*
*선임이 작성한 코드라고 가정한다
*/
public class Cal {
//메서드를 만들어보자
public int sum(int n1, int n2) {
return n1 + n2;
}
public int multiply(int n1, int n2) {
return n1 * n2;
}
}//end of Cal
/**
* xxx.java 파일 하나에
* 여러 클래스를 선언할 수 있다.
* 단 스코프는 분명히 구분된다.
*
* 또한 단 하나의 자바파일에
* public 클래스는 오직 하나만 존재할 수 있다.
*
* 요청사항
* 마이너스 기능을 추가하라
* 곱하기 기능에서 n1과 n2에 0이 들어온다면
* 0을 입력하지 말라는 문구를 추가하라
*/
class ChildCal extends Cal { //자식 클래스는 접근제어코드 public을 붙일 수 없다
//마이너스 기능 추가
public int minus(int n1, int n2) {
return n1 - n2;
}
/*
상속을 사용했을때
메서드 오버라이드라는 개념이 있다.
Method Override
부모클래스의 메서드를 재정의 하는 것이다.
문법
부모클래스의 메서드 이름과 매개변수 개수 및 타입
즉, 모양이 동일해야 한다.
*/
//곱셈 기능 수정
public int multiply(int n1, int n2) {
if (n1 == 0 || n2 == 0) {
System.out.println("0을 입력하지 마시오");
}
return n1 * n2;
}
/*
부모 클래스의 메서드를 자식 클래스에서 수정했다면
메서드 오버라이드라고 한다.
*/
}//end of ChildCal
예제
부모클래스 Hero 클래스를
자식클래스인 Warrior, Archer, Wizarad로 상속시켰다.
package com.inheritance;
/**
* 4.21 상속개념 6
* 클래스 다이어그램 준수해야 한다.
*/
public class Hero {
// 클래스 속성
String name;
int hp;
//생성자
Hero(String name, int hp) {
this.name = name;
this.hp = hp;
}
//메서드
void attack() {
System.out.println("대상을 공격합니다");
}
}//end of class
💀 문법 주의
부모 사용자정의생성자가 기존재한다면 super(); 키워드를 생성하여 부모 생성자를 호출하여야 한다.
package com.inheritance;
/**
* 4.21 상속개념 6_1
* 클래스 다이어그램 준수해야 한다.
*/
public class Warrior extends Hero{
Warrior(String name, int hp) {
/*
this();
부모 사용자정의생성자가 기존재한다면
super(); 키워드를 생성하여
부모 생성자를 호출하여야 한다.
*/
super(name, hp);
}
//메서드
void comboAttack() {
System.out.println("대상에게 comboAttack을 시전합니다");
}
//메서드 오버라이드
//어노테이션 주석 + 힌트
@Override
void attack() {
System.out.println("전사가 공격을 합니다");
super.attack();
}
//
}//end of class
package com.inheritance;
/**
* 4.21 상속개념 6_2
* 클래스 다이어그램 준수해야 한다.
*/
public class Archer extends Hero {
Archer(String name, int hp) {
super(name, hp);
}
//메서드
void fireArrow() {
System.out.println("대상에게 fireArrow를 시전합니다");
}
}//end of class
package com.inheritance;
/**
* 4.21 상속개념 6_3
* 클래스 다이어그램 준수해야 한다.
*/
public class Wizard extends Hero {
Wizard(String name, int hp) {
super(name, hp);
}
//메서드
void freezing() {
System.out.println("대상에게 freezing을 시전합니다");
}
}//end of class
부모가 자식에게 재산을 물려주듯 미리 작성해둔 클래스의 1.속성과 2.메서드를 물려줄 수 있다.
부모클래스(상위,수퍼) 자식클래스(하위,차일드)
기능이 더 큰 쪽은 자식클래스 쪽이다. (부모기능 + 자식기능)
상속 개념은 기존의 코드를 변경하지 않고 활용하고 싶을 때 활용한다.
package com.inheritance;
/**
* 4.21 2강 상속개념 1
*
* 선임이 작성한 코드라고 가정한다
*/
public class A {
String name;
int height;
int weight;
int age;
}//end of A
package com.inheritance;
/**
* 4.21 2강 상속개념 2
*/
public class B {
//선임이 작성한 코드 예
String name;
int height;
int weight;
int age;
/*
선임이 작성한 코드는 그대로 두고
기존 코드를 복붙하여
추가로 필드를 선언해서 만든다
*/
int level;
String nickName;
/*
하지만 우리가 상속이라는 기법을 활용한다면
더 편하게 작업을 할 수 있다.
*/
}//end of B
package com.inheritance;
/**
* 4.21 2강 상속개념 3
*
* 선임이 작성한 코드를 따라쓴다고 가정한다
*
* 만약 상속이란 개념을 이해한다면
* 기존 클래스의 속성과 메서드를 상속받아 작업할 수 있다.
*/
public class C extends A {
/*
⭐C extends A
C가 A에 선언된 필드를 물려받겠다는 뜻이다.
이때 A클래스는 부모클래스가 되고
C클래스는 자식클래스가 된다.
💀단, 자바에서는 단일상속만 인정된다.
충돌을 방지하기 위해서다.
*/
int level;
String nickName;
}//end of C
⭐C extends A C가 A에 선언된 필드를 물려받겠다는 뜻이다.
이때 A클래스는 부모클래스가 되고 C클래스는 자식클래스가 된다.
💀단, 자바에서는 단일상속만 인정된다. 충돌을 방지하기 위해서다.
package com.inheritance;
/**
* 4.21 2강 상속개념 4
*/
public class CMainTest1 {
//main = 코드의 진입점
public static void main(String[] args) {
//A와 C는 상속관계
C c = new C();
c.name = "C클래스입니다";
c.height = 100;
c.weight = 20;
c.age = 10;
c.level = 1;
c.nickName = "자식 C클래스";
}//end of main
}//end of class