VO 클래스 : Car
package edu.kh.poly.ex1.model.vo; public class Car { //최상위 클래스인 오브젝트를 컴파일러로부터 자동으로 상속받는다. //추상화 private int wheel; // 바퀴 개수 private String handle; private String engine; public Car() { super(); //얘도 자동생성이지만 super()를 넣어서,, 알려준다... } //매개변수 있는 생성자 자동 완성 (alt+ shift + s->o) public Car(int wheel, String handle, String engine) { super(); this.wheel = wheel; this.handle = handle; this.engine = engine; } //getter/setter public int getWheel() { return wheel; } public void setWheel(int wheel) { this.wheel = wheel; } public String getHandle() { return handle; } public void setHandle(String handle) { this.handle = handle; } public String getEngine() { return engine; } public void setEngine(String engine) { this.engine = engine; } //객체의 필드 정보를 하나의 문자열로 반환하는 용도의 메소드 // Objcet.toString() 오버라이딩 @Override public String toString() { return wheel + " / " + handle + " / " + engine; } }
➡ 추상화로 자동차의 특징 만들기
매개변수 있는 생성자 완성 후
super
게터 세터 생성
객체의 필드 정보를 하나의 문자열로 반환하는 용도의 메소드 // Objcet.toString() 오버라이딩
VO 클래스 : TeslaCar
package edu.kh.poly.ex1.model.vo; public class TeslaCar extends Car{ //Car를 상속 받는 TeslaCar //추상화 //TeslaCar는 전기차만 있다고 가정 private int batteryCapacity; //배터리 용량 //기본 생성자 public TeslaCar() { super(); //상속받는 Car의 기본 생성자 } //매개 변수 있는 생성자 public TeslaCar(int wheel, String handle, String engine, int batterCapacity) { // this.wheel; 안되는 이유 : 부모의 것은 private을 쓸 수 없다. 상ㅅ고 받은 private 멤버는 직접 접근 불가 super(wheel, handle, engine); this.batteryCapacity = batterCapacity; } //매개 변수 있는 생성자 public TeslaCar(int batteryCapacity) { super(); this.batteryCapacity = batteryCapacity; } //getter / setter public int getBatteryCapacity() { return batteryCapacity; } public void setBatteryCapacity(int batteryCapacity) { this.batteryCapacity = batteryCapacity; } @Override public String toString() { //부모객체 안에 있는 걸 불러올 수 있는 super참조변수 사용 return super.toString() + " / " + batteryCapacity; //getWheel + getHandle도 되지만 중복되지 않게 super로 재사용 } }
➡
Service 클래스
package edu.kh.poly.ex1.model.service; import edu.kh.poly.ex1.model.vo.Car; import edu.kh.poly.ex1.model.vo.TeslaCar; public class PolymorphismService { public void example1() { //컴퓨터 연산 규칙 : 같은 자료형끼리만 연산이 가능하다. Car c = new Car(4, "원형핸들", "경유엔진"); // 부모 타입의 참조변수 = 부모 타입의 객체 ==> 같은 타입이기때문에 대입 가능 // 객체와 참조변수의 타입이 같으므로 대입연산 가능 TeslaCar t = new TeslaCar(4, "원형핸들", "전기모터", 50000); // 자식 타입의 참조변수 = 자식 타입 객체 Car c2 = new TeslaCar(6, "원형핸들", "전기모터", 50000); // 부모 타입의 참조 변수 = 자식 타입의 객체 // -> 참조변수와 객체의 타입이 불일치하나 대입연산이 가능한 상태이다. } }
➡객체와 참조변수의 타입이 같으므로 대입연산 가능
부모 타입의 참조변수 = 부모 타입의 객체
자식 타입의 참조변수 = 자식 타입 객체 ==> 같은 타입이기때문에 대입 가능
➡ 부모 타입의 참조 변수 = 자식 타입의 객체
참조변수와 객체의 타입이 불일치하나 대입연산이 가능한 상태이다.
각 객체의 필드 정보 출력
Service 클래스 PolymorphismService
// 각 객체의 필드 정보 출력(toString 출력) System.out.println("c : " + c.toString() ); System.out.println("t : " + t.toString() ); /*error*/ System.out.println(c2.getBatteryCapacity);
➡ System.out.println(c2.getBatteryCapacity);
부모 타입의 참조 변수로는 자식 객체만의 멤버를 참조할 수 없으므로 에러 발생.
자동완성에서도 t의 멤버는 보이지 않는다.
Run 클래스
package edu.kh.poly.ex1.run; import edu.kh.poly.ex1.model.service.PolymorphismService; public class PolymolphismRun { public static void main(String[] args) { PolymorphismService service = new PolymorphismService(); service.example1(); } }
➡
자식 클래스 추가
VO 클래스 : RollsRoyce
package edu.kh.poly.ex1.model.vo; public class RollsRoyce extends Car{ private String umbrellaColor; // 우산 색 public RollsRoyce() { super(); //생략가능 } //매개변수 있는 생성자+super()까지 한번에 만들기 public RollsRoyce(int wheel, String handle, String engine, String umbrellaColor) { super(wheel, handle, engine); this.umbrellaColor = umbrellaColor; } //getter/setter public String getUmbrellaColor() { return umbrellaColor; } public void setUmbrellaColdr(String umbrellaColor) { this.umbrellaColor = umbrellaColor; } @Override public String toString() { return super.toString() + " / " + umbrellaColor; } }
➡
VO 클래스 : Spark
package edu.kh.poly.ex1.model.vo; public class Spark extends Car{ private double discountOffer; //할인 혜택 public Spark() {} //기본 생성자 //매개변수+ super클래스 public Spark(int wheel, String handle, String engine, double discountOffer) { super(wheel, handle, engine); this.discountOffer = discountOffer; } //getter/setter public double getDiscountOffer() { return discountOffer; } public void setDiscountOffer(double discountOffer) { this.discountOffer = discountOffer; } //오버라이딩 @Override public String toString() { return super.toString() + " / " + discountOffer; } }
➡
Service 클래스 : PolymorphismService
public void example2() { //다형성 업캐스팅 활용 //1)객체 배열 //기본 생성자 +초기화 TeslaCar tesla = new TeslaCar(4, "원형핸들", "전기모터", 50000); RollsRoyce royce = new RollsRoyce(4, "원형", "경유", "검정"); Spark spark = new Spark(4, "원형", "휘발유 엔진", 0.5); // TeslaCar, RollsRoyce, Spark 공통점 : Car의 자식 // 부모 - 자식 관계에서 부모 참조변수로 자식 객체를 참조하는 다형성이 적용된다. //객체배열을 만들어서 engine정보 한번에 출력 Car[] arr = new Car[3]; //부모 타입 참조변수 배열 // 배열의 각 요소가 Car 타입의 참조 변수 // Car[3] 안에 자식 객체 넣기 TeslaCar, RollsRoyce, Spark // arr[0] = new TeslaCar(); //arr[] : 부모 타입 // TeslaCar: 자식객체 arr[0] = tesla; //tesla == TeslaCar 객체의 주소가 저장되어있다 arr[1] = royce; //RollsRoyce 타입 객체 //Car 타입 참조 변수 arr[2] = spark; //Spark; // 해당 배열 인덱스의 엔진값 출력 for(int i = 0; i < arr.length; i++) { System.out.println(arr[i].getEngine()); } }
➡
➡ 테슬라카 두개는 자료형이 같으니 참조하는데 문제 없다
테슬라카에 저장된값을 arr[0]에 대입하라- > telsa의 주소가 복사된다
car[]타입의 arr 참조 변수로 자식 객체를 참조하는데 그 안의 car만 볼 수 있다
== 다형성의 업캐스팅
TeslaCar tesla = new TeslaCar(4, "원형핸들", "전기모터", 50000);
Car[] arr = new Car[3];
arr[0] = tesla = new TeslaCar(); //자식객체의 주소를 tesla라는 변수에 저장
arr[0] = tesla; //그 tesla를 부모타입에 저장
상속관계가 되어있는 car가 안쪽에 구현되어있으니 자식 관계는 보지 않고 부모인car만 참조한다.
Run 클래스
코드작성
➡
이걸로 선택하면 매개변수 있는 생성자+ super클래스 까지 다 생성됨
다운캐스팅
Service 클래스 : PolymorphismService
+ instanceof
public void example3() { //다운 캐스팅 Car c = new Spark(); // c.getDidountOffer() -> 부모타입의 참조 변수로는 부모부분만 참조 가능 // () 먼저 수행되고 ((Spark)c).getDiscountOffer(); //부모 타입 참조 변수를 자식 타입으로 형변환하여 // 자식 부분을 참조 가능하게 한다 == 다운캐스팅 TeslaCar t = new TeslaCar(); //t instanceof TeslaCar System.out.println(c instanceof Car); System.out.println(c instanceof Spark); //선언 동시에 초기화 Car[] carArr = { new Car(8, "큰 원형 핸들", "v8 디젤엔진"), new TeslaCar(4, "기능 많은 핸들", "전기 모터", 80000), //다형성의upcasting new RollsRoyce(6, "금붙이 핸들","디젤 엔진","갈색우산"), new Spark(4, "조그만 원형 핸들", "가솔린 엔진", 0.5) }; //for문을 이용하여 배열요소 하나씩 접근 //현재 배열 요소가 참조하는 객체의 타입을 확인 for(int i = 0; i<carArr.length; i++) { if( carArr[i] instanceof TeslaCar) { //carArr[i] 참조변수 //carArr[i] 한 칸이 다 car배열로 car참조변수로 부모타입이다 => 안에있는 부모만 참조할 수 있다 System.out.println(((TeslaCar)carArr[i]).getBatteryCapacity() ); //getBatteryCapacity 자식꺼이니 참조 못하니깐 자식으로 바꾼다 //TeslaCar로 강제 형변환 } else if( carArr[i] instanceof RollsRoyce) { System.out.println(((RollsRoyce)carArr[i]).getUmbrellaColor() ); } else if( carArr[i] instanceof Spark) { System.out.println(((Spark)carArr[i]).getDiscountOffer() ); } else { //Car인 경우 System.out.println(carArr[i].toString() ); } } }
➡
1) TeslaCar 자료형이면 => 배터리 용량 출력
2) RollsRoyce 자료형이면 -> 우산 색을 출력
3) Spark자료형이면 -> 할인 혜택 비율을 출력
4) Car 자료형이면 -> toString()을 출력
👉 if( carArr[i] instanceof TeslaCar) { .... } else { ..}
->참조되는 모든 객체가 Car 객체를 포함하고 있기 때문에
Car를 검사하는 조건문은 마지막에 작성. 먼저 작성하게되면 계속toString만 나온다. (
정적 · 동적 바인딩
Service 클래스 - 정적 바인딩
public void example4() { //바인딩: 실제 실행할 메소드 코드와 메소드 호출부를 연결하는 것 // ex1() // 메서드 호출 // public void ex1() { ...} //메서드 실행 // 1. 정적 바인딩 // - 프로그램 실행 전 컴파일 단계에서 // 메서드 코드와 메서드 호출부를 연결 Car c = new Spark(4, "원형 핸들", "가솔린 엔진", 0.5); //up casting상태 System.out.println( c.toString() );코드작성
➡
Service 클래스 - 동적 바인딩
public void example4() { Car c = new Spark(4, "원형 핸들", "가솔린 엔진", 0.5); //up casting상태 System.out.println( c.toString() ); }
➡ toString() : String - Car
프로그램 실행 전 c.toString()은 Car 클래스에 있는 toString() 메서드와 연결되어 있다. == 정적 바인딩
➡ 실행 시 출력 모양 예상 : 4/ 원형 핸들 / 가솔린 엔진
실제 출력 모양 : 4 / 원형 핸들 / 가솔린 엔진 / 0.5
-> Spark에 오버라이딩된 toString()반환값 그래서 discountOffer값이 같이 출력되는것
-> 프로그램 실행 중
정적 바인딩 된 메서드가 아닌 실행할 당시의 객체 타입의 오버라이딩된 메서드로 바인딩된다. == 동적 바인딩
추상 클래스
VO 클래스 : Animal
package edu.kh.poly.ex2.model.vo; // 강아지, 고양이, 기린, 펭귄, 호랑이, 알파카, 코끼리, 곰, 돼지 // 뱀, 거미, 개미, 사람, 갈매기, 고래, 금붕어 public abstract class Animal { // 추상 클래스(abstract class) // 1. 추상 메소드를 포함하고 있는 미완성된 클래스 // 2. 미완성된 부분이 없어도 객체로 생성되서는 안되는 클래스 // 필드 private String type; // 종 private String eatType; //식성(초식, 육식, 잡식) // 생성자 : 객체 생성 기능 // 추상 클래스는 직접적인 객체 생성은 불가능 하지만 // 상속 받은 자식 객체 내부에 생성될 수 있으므로 생성자 작성기능 // (자식 생성자 코드 내부 super() 생성자를 위함) public Animal(){ } public Animal(String type, String eatType) { super(); this.type = type; this.eatType = eatType; } // 기능 public String getType() { return type; } public void setType(String type) { this.type = type; } public String getEatType() { return eatType; } public void setEatType(String eatType) { this.eatType = eatType; } }
VO 클래스 : Dog
package edu.kh.poly.ex2.model.vo; public class Dog extends Animal{ //extends로 Animal 상속받기 //animal이 추상메서드가 있어서 에러뜬다. //Dog 다 하고나ㅣ면 객체 생성도 가능해진다. private int loyalty; //충성심 // 생성자 public Dog() { super(); } public Dog(String type, String eatType, int loyalty) { super(type, eatType); //animal참조한듯 this.loyalty = loyalty; } // 상속 받은 미완성 메서드 hunt 오버라이딩 @Override public void hunt() { //실행할때는 동적 바인딩으로 위치가 바뀐다. System.out.println("달려가서 쎄게 문다."); } //getter/setter public int getLoyalty() { return loyalty; } public void setLoyalty(int loyalty) { this.loyalty = loyalty; } }
➡dog클래스에서 // 상속 받은 미완성 메서드 hunt 오버라이딩
@Override
public void hunt() { //실행할때는 동적 바인딩으로 위치가 바뀐다.
System.out.println("달려가서 쎄게 문다.");
}
오버라이딩 안한다면 클래스 전체가 error
Service 클래스: EXAMPLE Service
package edu.kh.poly.ex2.model.service; import edu.kh.poly.ex2.model.vo.Animal; import edu.kh.poly.ex2.model.vo.Dog; public class ExampleService { public void example1() { //1) 추상 클래스를 이용한 객체 생성 // Animal animal = new Animal(); // 추상클래스이기 때문에 객체화 불가능 // 2) 추상클래스를 상속 받아 구현한 일반 클래스 객체 생성 Dog dog = new Dog("강아지과", "잡식", 100); dog.hunt(); //3) 추상 클래스는 부모 타입 참조변수로 사용할 수 있다. Animal animal = new Dog("강아지과", "잡식", 50); //다형성 업 캐스팅 적용 animal.hunt(); // 정적 바인딩: 미완성 메서드와 연결됨 // 동적 바인딩: 오버라이딩된 Dog의 HUNT()와 연결된다. } }
➡
인터페이스
Interface : Calculator
package edu.kh.poly.ex2.model.service; public interface Calculator { //인터페이스 // - 상수형 필드와, 추상 메서드만을 작성할 수 있는 // 추상클래스의 변형체 //인터페이스 사용 목적 // 1. 일관된 인터페이스(작업환경)을 제공 public abstract int plus(int num1, int num2); //미완성인 코드를 줄테니 알아서 구현해봐라~ public abstract int minus(int num1, int num2); public abstract int multiple(int num1, int num2); public abstract int divide(int num1, int num2); }
➡
인터페이스 사용 목적
1. 일관된 인터페이스(작업환경)을 제공
> implements 구문을 이용한 인터페이스 상속을 통해 상속 받은 모든 클래스에서 동일한 메서드를 강제적으로 오버라이딩 하게 한다.
2. 클래스간의 접점을 만들어 강제적인 부모, 자식 관계 형성
묵시적으로 메서드는 public abstract
int plus(int num1, int num2); //미완성인 코드를 줄테니 알아서 구현해봐라~
이렇게만 써도 되긴한다.
=> double 가능
Service 클래스 : MyCalculator
package edu.kh.poly.ex2.model.service; public class MyCalculator implements Calculator{ @Override public int plus(int num1, int num2) { // TODO Auto-generated method stub return 0; } @Override public int minus(int num1, int num2) { // TODO Auto-generated method stub return 0; } @Override public int multiple(int num1, int num2) { // TODO Auto-generated method stub return 0; } @Override public int divide(int num1, int num2) { // TODO Auto-generated method stub return 0; } //extends : 클래스간의 상속, 인터페이스 간의 상속 // implements: 인터페이스- 클래스 상속 관계 (구현하다) // }
➡오버라이딩된 일정한 구문이 나온다
exampleService
public void example2() { Marker[] arr = new Marker[3]; arr[0] = new MyCalculator(); arr[1] = new NewCalculator(); arr[2] = new Test(); }
➡ 마커
마커 인터페이스를 만들어 아무것도 없는 인터페이스이지만
테스트도 만들어서 사용가능
➡ public class Test implements Marker{ 이렇게 추가해서
➡example서비스에서
public void example2() {
Marker[] arr = new Marker[3];
arr[0] = new MyCalculator();
arr[1] = new NewCalculator();
arr[2] = new Test();
}
'Backend > 문제 풀이' 카테고리의 다른 글
[Java] 학생관리프로그램(displayMenu) (0) | 2021.10.06 |
---|---|
컬렉션 예제1 _Student, ArrayStudent, CollectionStudent, CollectionRun (0) | 2021.10.04 |
[Java] Inheritance(상속) 예제 (0) | 2021.09.08 |
[Java|연습] 2차원 Array(배열)_기초 문제 행,열 합 (0) | 2021.09.02 |
[Java|연습] Array(배열)_lotto(Math.random()) (0) | 2021.09.02 |