※ Bus 1대로 진행
※ Taxi 1대로 진행
package test1;
//상위 클래스 Transportation --> 추상 클래스
public abstract class Transportation {
//필드
int num; //번호
int currentGas; //주유량
int acceleration; //속도
String status; //상태
//메소드 --> 추상 메소드: 앞에 abstract 을 붙임
//추상 메소드
abstract void board(int pass, String dest, int dis); //탑승 board: 메소드 명, 승객 int pass, 목적지 String dest, 거리 int dis: 매개변수
abstract void refuel(); //주유량 refuel: 메소드 명
//문법: abstract 반환타입 메소드이름();
abstract int refuel(int gas); //refuel: 메소드 명 int gas: 필드명
abstract int board(int pass); //board: 메소드 명, int pass: 필드명
}
추상화 vs 상속
- 추상화: 클래스간의 공통점을 찾아내서 공통의 부모를 설계 --> 상향, 하향 상관없음
- 상속: 상위 클래스를 사용하여, 하위 클래스를 정의 --> 하향
package test1;
import static test1.Taxi.gasLeft;
//클래스
public class Bus extends Transportation {
//필드
int maxPass = 30; // 최대 승객 수
int currentPass = 0; // 현재 승객 수
int cost = 1000; // 요금
//생성자
//버스 번호 지정 [고유값으로 생성되어야 되기에 랜덤함수로 함]
//버스 번호 (고유값으로 생성되어야 되기에 랜덤함수로. 랜덤함수는 기본형이 Double 형이기에 (int)로 정수화. 1부터 값을 뽑고 싶다면 +1 => 랜덤 함수는 0부터 나오기 때문에)
public Bus() { //Bus(): 기본 생성자, num: 상위 클래스의 필드명
this.num = (int) (Math.random() * 100 + 1); //Math.random() 메소드: 0.0 ~ 1에 무한히 가까운 수를 제공
System.out.println("버스 번호: " + num);
}
//메소드
// 버스 상태 변경
boolean busStatus(boolean change) { //boolean 메소드, busStatus: 메소드 명, boolean change: 매개변수(메소드 실행 시, 필요한 데이터를 받기 위한 변수)
if(change == true) //매개변수 chage가 true라면, 상위 클래스의 필드 status는 "운행중"이 된다
status = "운행중";
else { // 매개변수 chage가 false라면, 상위 클래스의 필드 status는 "차고지행", 하위 클래스의 필드 currentPass은 0, 하위 클래스의 필드 maxPass은 30이 된다
status = "차고지행";
currentPass = 0;
maxPass = 30;
}
return change;
}
// 버스 현재 상태
void currentBus() { //void 메소드, currentBus: 메소드 명 --> void 이므로, 리턴값은 없음
System.out.println("상태 = " + status); //상위 클래스의 필드 status 를 출력
System.out.println("주유량 = " + currentGas); //상위 클래스의 필드 currentGas 를 출력
}
//오버라이드
@Override
void board(int pass, String dest, int dis) { //상위 클래스에서 봤던 int pass, String dest, int dis 매개변수를 여기 하위 클래스에서 재정의(오버라이드)
}
// 주유량
@Override
void refuel() { //refuel: 상위 클래스의 메소드 명
}
int refuel(int gas) { //refuel: 상위 클래스의 메소드 명, int gas: 매개변수
currentGas += gas; //매개 변수 gas 를 더해서 상위 클래스의 필드 currentGas 로 값을 저장한다
if(!gasLeft()) { //import 에서 gasLeft 가 있기 때문에, gasLeft() 로 사용 가능. --> 하위 클래스 Taxi 에서 static boolean gasLeft()를 사용하므로
status = "차고지행"; //gasLeft가 아니라면, 상위 클래스의 status는 "차고지행"
}
return currentGas;
}
boolean available() { //available: 메소드 명 --> 이렇게 하위 클래스에서 새롭게 선언하기도 함
//승객 탑승은 ‘최대 승객수’ 이하까지 가능
return maxPass >= currentPass; //maxPass:하위 클래스의 필드, currentPass: 하위 클래스의 필드 --> 최대 승객 수는 현재 승객 수 보다 크거나 같다
}
// 승객 탑승
@Override
int board(int pass) { //board: 상위 클래스의 메소드 명, pass: 매개변수
if(pass >= (maxPass-currentPass)) //maxPass:하위 클래스의 필드, currentPass: 하위 클래스의 필드 --> 승객 수는 최대 승객 수에서 현재 승객 수를 뺀 수 보다 크거나 같다면
System.out.println("최대 승객 수 초과"); //"최대 승객 수 초과"를 출력
else { // 아니라면
if(available()) { //available: 하위 클래스 Bus 의 메소드 명 --> available 가 true 라면,
currentPass += pass; // 하위 클래스의 필드 currentPass 에 승객 수 pass 를 더하고, 탑승 승객 수, 잔여 승객 수, 요금 확인 을 출력한다
System.out.println("탑승 승객 수 = "+pass+"명");
System.out.println("잔여 승객 수 = "+(maxPass-currentPass)+"명");
System.out.println("요금 확인 = "+(cost*pass));
}
if(!available()) { //available 가 false 라면,
System.out.println("최대 승객 수 초과"); //최대 승객 수 초과 를 출력한다
}
}
return currentPass;
}
}
import static test1.Taxi.gasLeft;
- 클래스 내의 모든 정적(static) 메소드를 import 하기 위함
- import 란? 다른 패키지 안의 클래스를 사용하기 위해서
- import static 란? 일반적인 import 와 달리, 해당 클래스의 정적 변수나 메소드를 패키지명과 클래스명 없이 약칭으로 쓸 수 있도록 해준다.
- gasLeft는 Taxi 클래스의 static 의 메소드명 이다. --> 이렇게 사용되면, gasLeft() 메서드는 클래스명 없이 사용 가능해짐
- 전역참조 문자인 *를 사용해서 모두 불러오기도 함
오버라이드
- 부모 클래스에 있는 메소드를 자식 클래스에서 재정의 하는 것
- 부모 클래스의 메소드를 자식클래스에서 동일한 이름으로 다시 재정의 하면, 부모클래의 메소드를 찾지 않고 자식 클래스의 메소드를 호출
import java.util.*;
- 한 패키지에서 여러 클래스를 사용하는 경우 클래스의 이름을 일일이 지정해주는 것보다 '패키지명.*'과 같이 하는 것이 편리
- 단점: 하지만, import하는 패키지의 수가 많을 때는 어느 클래스가 어느 패키지에 속하는지 구별하기 어렵다
package test1;
public class testBus {
public static void main(String[] args) {
// 버스 테스트
// 1번
// 1~2. 버스 2대 생성 & 출력 --> 랜덤 번호 출력
Bus bus1 = new Bus(); //객체 생성
Bus bus2 = new Bus();
// 2번 (버스 1대로 진행)
// 1 ~ 2. 승객 +2 & 출력 //하위 클래스 Bus 의 int board 메소드 실행 --> if/else 中 else 문 실행 --> available()/!available() 中 true 인 available() 실행(available()메소드로 가서 true 인지 판단)
bus1.board(2); // --> 하위 클래스의 필드 currentPass 에 승객 수 pass 를 더하고, 탑승 승객 수, 잔여 승객 수, 요금 확인 을 출력
// 3 ~ 4. 주유량 50 //하위 클래스 Bus 의 int refuel 메소드 실행 --> 매개 변수 gas 를 더해서 상위 클래스의 필드 currentGas 로 값을 저장
bus1.refuel(50); //--> return currentGas
System.out.println("주유량 = "+bus1.currentGas);
// 5. 상태 변경 => 차고지행 //하위 클래스 Bus 의 boolean busStatus 메소드 실행 --> 매개변수 boolean change 가 false라면, status = "차고지행"
bus1.busStatus(false); // --> return change
// 6. 주유량 +10 //하위 클래스 Bus 의 int refuel 메소드 실행
bus1.refuel(10);
// 7. 버스 상태와 주유량 출력
bus1.currentBus();
// 8. 상태 변경 => 운행중
bus1.busStatus(true);
// 9 ~ 10. 승객 +45 => 최대 승객 수 초과 //하위 클래스 Bus 의 int board 메소드 실행
bus1.board(45);
// 11 ~ 12. 승객 +5 & 출력 //하위 클래스 Bus 의 int board 메소드 실행
bus1.board(5);
// 13. 주유량 -55 //하위 클래스 Bus 의 int refuel 메소드 실행 --> if(!gasLeft()) 이면, status = "차고지행"
bus1.refuel(-55);
// 14. 버스 상태와 주유량 출력 //하위 클래스 Bus 의 currentBus 메소드 실행 --> "상태 = " + status 와 "주유량 = " + currentGas 출력
bus1.currentBus();
}
}
package test1;
public class Taxi extends Transportation {
//필드
String destination; // 목적지
int distance; // 목적지까지 거리
int maxPass = 4; // 최대 승객수
int defaultDistance = 1; // 기본 거리
int defaultCost = 3000; // 기본 요금
int perDistance = 1000; // 거리당 요금
//정적(static) 필드(변수)
static String status = "일반"; // 상태
int speed = 0; // 속도
int total = 0; // 누적 금액
int cost; // 승객이 지불할 금액
//생성자
// 택시 번호 지정 [고유값으로 생성되어야 되기에 랜덤함수로 함]
public Taxi() {
this.num = (int)(Math.random()*100+1);
// 랜덤함수는 기본형이 Double 형이기에 (int)로 정수화
// 1부터 값을 뽑고 싶다면 +1 => 랜덤 함수는 0부터 나오기 때문에
System.out.println("택시 번호 : "+num);
Taxi.drive();
}
//static 메소드: 메소드 명 앞에 static 을 붙임 --> 객체 생성없이 클래스를 통해 메서드를 직접 호출 가능
static boolean drive() {
if (!gasLeft()) {
status = "운행 불가";
System.out.println("주유 필요");
return false;
}
return true;
}
static boolean gasLeft() {
return false;
}
// 탑승 승객 목적지 거리
@Override
void board(int pass, String dest, int dis) { //상위 클래스에서 봤던 int pass, String dest, int dis 매개변수를 여기 하위 클래스에서 재정의(오버라이드)
if(status == "일반") {
if(pass > 4)
System.out.println("최대 승객 수 초과");
else {
if(dis==1)
cost = defaultCost+ (perDistance*dis);
else
cost = defaultCost+ (perDistance*(dis-1));
status = "운행중";
System.out.println("탑승 승객 수 = "+pass);
System.out.println("잔여 승객 수 = "+ (maxPass-pass));
System.out.println("기본 요금 확인 = "+defaultCost);
System.out.println("목적지 = "+dest);
System.out.println("목적지까지 거리 = "+ dis+"km");
System.out.println("지불할 요금 = "+cost);
total += cost;
}
}
}
@Override
void refuel() {
}
// 주유량
@Override
int refuel(int gas) {
currentGas += gas;
if(!gasLeft()) {
status = "운행 불가";
}
return currentGas;
}
@Override
int board(int pass) {
return 0;
}
// 요금 지불
int pay() {
status = "일반";
maxPass = 4;
System.out.println("누적 요금 = "+ total);
if(!gasLeft())
System.out.println("주유 필요");
cost = 0;
return total;
}
void passenger(int pass) {
if(pass > 4)
System.out.println("최대 승객 수 초과");
}
// 속도변경
int changeSpeed(int acceleration) {
//주유 상태를 체크하고 주유량이 10 이상이어야 운행할 수 있음
if(gasLeft()) {
this.acceleration = acceleration;
speed += acceleration;
System.out.println("현재 속도는 "+ speed+"입니다.");
}
System.out.println("주유량을 확인해주세요."+currentGas);
return currentGas;
}
}
package test1;
public class testTaxi {
// 정적(static) 메소드
public static void main(String[] args) {
//TODO Auto-generated method stub
// 택시 테스트
// 1번
// 1~2. 버스 2대 생성 & 출력
Taxi taxi1 = new Taxi(); //객체 생성
Taxi taxi2 = new Taxi();
System.out.println("taxi1 주유량 = "+taxi1.currentGas);
System.out.println("taxi1 상태 = "+taxi1.status);
System.out.println("taxi2 주유량 = "+taxi2.currentGas);
System.out.println("taxi2 상태 = "+taxi2.status);
//2번(Taxi 1대로 진행)
// 1~2.승객+2 목적지 = 서울역 목적지까지 거리 2km & 출력
taxi1.board(2, "서울역", 2);
System.out.println("상태 = "+ taxi1.status);
// 3. 주유량 -80
taxi1.refuel(-80);
// 4~5. 요금결제 & 출력
System.out.println("주유량 = "+taxi1.currentGas);
taxi1.pay();
// 6~7. 승객+5 & 최대승객수 초과
taxi1.passenger(5);
// 8~9. 승객+3 목적지 = 구로디지털단지역 목적지까지 거리 12km & 출력
taxi1.board(3, "구로디지털단지역", 12);
// 10. 주유량 -20
taxi1.refuel(-20);
// 11~12. 요금 결제 & 출력
System.out.println("주유량 = "+taxi1.currentGas);
taxi1.pay(); // 하위 클래스 Taxi 의 int pay() 메소드 실행
}
}