일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Java & SpringBoot로 시작하는 웹 프로그래밍
- 스쿼드 메이커
- 자바 인강
- 안드로이드
- 패스트캠퍼스
- 혼술 술자리 인싸앱
- 안드로이드 그림판#그림메모장#낙서장
- 박스#강아지집#만들기
- 랜덤스쿼드
- 아두이노#작품#사료급식기
- 홈CCTV
- D-ID
- 안녕 디지몬
- Ai
- 부의감각
- fifaonline4
- 피온4
- fifaonline
- 바이트디그리
- 안드로이드#앱만들기#알바
- 부르지마세요
- 독서감상문
- 내일배움카드
- 강아지 #박스집 #복층
- K디지털크레딧
- 안드로이드 #앱개발#계산기
- 랜덤
- 강아지 스마트 펜스
- 불끌때
- #FIFAONLINE4
- Today
- Total
LC Studio
JAVA & Spring 강의 (자바 인강 4주차) 객체 지향 핵심 본문
클래스 상속
- 일반적인 클레스로부터 구체적인 클레스로 확장해서 사용하는 것
- 이미 구현된 클래스보다 더 구체적인 기능을 가진 클래스를 구현하는 것
class B extends A{
}
위와 같은 문법으로 사용하면 됨
ex) 포유류 클래스를 상속받는 사람 클래스
class Mammal{
}
class Human extends Mammal{
}
멤버십 시나리오 구현 예제
1. Customer class 작성
//Siver을 기본으로
//하위클래스에서 접근 가능하도록 private가 아닌 protected로 선언
package ch02;
public class Customer {
protected int customerID; //하위 클래스에서는 접근 가능 , protected
protected String customerName;
protected String customerGrade;
int bonusPoint;
double bonusRatio;
public int getCustomerID() {
return customerID;
}
public void setCustomerID(int customerID) {
this.customerID = customerID;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public String getCustomerGrade() {
return customerGrade;
}
public void setCustomerGrade(String customerGrade) {
this.customerGrade = customerGrade;
}
public Customer()
{
customerGrade = "SILVER";
bonusRatio = 0.01;
}
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price;
}
public String showCustomerInfo() {
return customerName + "님의 등급은 " + customerGrade + "이며, 보너스 포인트는 "+bonusPoint+"입니다.";
}
}
2. VIPCustomer Class 작성
//Customer Class 상속
package ch02;
public class VIPCustomer extends Customer {
//상속으로 인해 아래의 중복되는 내용은 써줄필요가 없다
//private int customerID;
//private String customerName;
//private String customerGrade;
//int bonusPoint;
//double bonusRatio;
double salesRatio;
private String agentID;
public VIPCustomer()
{
bonusRatio = 0.05;
salesRatio = 0.1;
customerGrade = "VIP";
}
public String getAgentID() {
return agentID;
}
}
상속에서 클래스 생성 과정
하위 클래스를 생성하면 상위 클래스가 먼저 생성 됨
위의 예시에서 VIPCustomer Class를 호출하면 자동으로 Customer class가 호출되어 실행
그 역할을 해주는 것이 super 키워드
super()는 상위 클래스의 기본 생성자를 호출 함, 명시하지 않으면 자동으로 호출해줌
만약 디폴트 생성자 없애고 매개 변수가 있는 생성자 추가한다면?
public Customer(int customerID, String customerName) {
this.customerID = customerID;
this.customerName = customerName;
customerGrade = "SILVER";
bonusRatio = 0.01;
System.out.println("Customer(int, String) 생성자 호출");
}
상속받는 VIPCustomer class 에서 super를 이용하여 상위 클래스의 생성자 명시적으로 호출하면 된다.
public VIPCustomer(int customerID, String customerName) {
super(customerID, customerName);
customerGrade = "VIP";
bonusRatio = 0.05;
salesRatio = 0.1;
System.out.println("VIPCustomer(int, String) 생성자 호출");
}
형 변환(업캐스팅)
상위 클래스로 변수를 선언하고 하위 클래스의 생성자로 인스턴스를 생성
위의 예제에서,
Customer customerLee = new VIPCustomer();
하위 클래스는 상위 클래스의 타입을 내포하고 있으므로 상위 클래스로의 묵시적 형 변환이 가능함
(VIPCustomer이 Customer로 형 변환)
즉, 생성은 되지만 상위클래스로 형 변환했기 때문에 접근할 수 없다.
메서드 재정의하기(overring)
오버라이딩(overriding) :
상위 클래스에 정의된 메서드의 구현 내용이 하위 클래스에서 구현할 내용과 맞지 않는 경우 하위 클래스에서 동일한 이름의 메서드를 재정의 할 수 있음
상위 클래스의 Customer의 calcPrice 메서드
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price;
}
하위 클래스 VIPCustomer의 재정의한 calcPrice 메서드
@Override
public int calcPrice(int price) {
// TODO Auto-generated method stub
bonusPoint += price * bonusRatio;
price -= (int)(price * salesRatio);
return price;
}
위의 예제에서 @Override는 애노테이션(annotation) 주석이라는 뜻이다.
컴파일러에게 특별한 정보를 제공해주는 역할을 한다.
@Override = 재정의된 메서드라는 정보 제공
그렇다면,
Customer vc = new VIPCustomer();
위와같이 인스턴스를 생성한 경우,
vc.clacPrice를 호출하면, Customer, VIPCustomer 둘중 어느 클래스의 메서드가 호출될까?
정답은 VIPCustomer이다.
위를 설명하기 위해서는 가상 메서드의 원리에 대해 알아야한다.
가상 메서드의 원리
-가상 메서드 테이블(vitual method table)에서 해당 메서드에 대한 address를 가지고 있다.
-재정의된 경우는 재정의 된 메서드의 주소를 가리킨다.
자바의 모든 메서드는 가상 메서드이고, 각 Class별로 가상 메서드 테이블을 가지고 있다.
그리고 클래스의 해당하는 각각의 메서드들은 각각의 메서드 address를 가지고 있다.
각각의 메서드 address를 가지고 있지만, address가 가르키는 메서드 영역은 같을 수 있다.
예를 들어, Customer 클래스를 상속받은 VIPCistomer의 클래스의 메서드의 경우,
재정의 @Override를 하지 않는 이상, Customer 클래스의 메서드와 같은 메서드 영역을 가르키고 있을 것이다.
결론적으로,
Customer vc = new VIPCustomer();
vc.clacPrice 의 경우에는
2가지 상황에 따라 호출되는 메서드가 다르다.
1. calcPrice가 재정의 되지 않은경우 => Customer 클래스의 calcPrice매서드 호출
2. calcPrice가 재정의 된 경우 => VIPCustomer 클래스의 clacPrice매서드 호출
다형성(polymorphism) 이란?
-하나의 코드가 여러 자료형으로 구현되어 실행되는 것
overriding을 활용하여 같은 같은 코드에서 여러 다른 실행 결과가 나오는 것
ex)
package ch06;
import java.util.ArrayList;
class Animal{
public void move() {
System.out.println("동물이 움직입니다.");
}
public void eating() {
}
}
class Human extends Animal{
@Override
public void move() {
System.out.println("사람이 두 발로 걷습니다.");
}
public void readBook() {
System.out.println("사람이 책을 읽습니다.");
}
}
class Tiger extends Animal{
@Override
public void move() {
System.out.println("호랑이가 네 발로 뜁니다.");
}
public void hunting() {
System.out.println("호랑이가 사냥을 합니다.");
}
}
class Eagle extends Animal{
@Override
public void move() {
System.out.println("독수리가 하늘을 날아 다닙니다.");
}
public void flying() {
System.out.println("독수리가 양날개를 쭉 펴고 날아다닙니다.");
}
}
public class AnimalTest {
public static void main(String[] args) {
Animal hAnimal = new Human();
Animal tAnimal = new Tiger();
Animal eAnimal = new Eagle();
//AnimalTest test = new AnimalTest();
//test.moveAnimal(hAnimal);
//test.moveAnimal(tAnimal);
//test.moveAnimal(eAnimal);
ArrayList<Animal> animalList = new ArrayList<>();
animalList.add(hAnimal);
animalList.add(tAnimal);
animalList.add(eAnimal);
for(Animal animal : animalList) {
animal.move();
}
}
public void moveAnimal(Animal animal) {
animal.move();
}
}
위의 코드에서 같은 move()를 호출했지만, 각기 다른 결과가 출력된다.
위와같이 다형성을 사용하는 이유는,
-상속과 메서드 재정의를 활용하여 확장성 있는 프로그램을 만들 수 있고,
-위의 예제에서 다른 동물을 추가하는 경우 쉽게 수정할 수 있고,
-만약 if else문 등을 활용한다면 코드가 복잡해지고, 유지보수가 어려워진다.
앞선 Customer class를 상속받은 GOLDCustomer class를 구현해 보았다.
package ch06;
public class GoldCustomer extends Customer {
double salesRatio;
public GoldCustomer(int customerID, String customerName) {
super(customerID, customerName);
customerGrade = "GOLD";
salesRatio = 0.1;
bonusRatio = 0.02;
}
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price - (int)(price*salesRatio);
}
}
이처럼 다형성을 활용하여 쉽게 추가하고 수정할 수 있다.
상속은 언제 사용 할까?
- IS-A 관계(is a relationship : inheritance)
일반적인 개념 -> 구체적인 개념
ex) 전공 -> 정보통신, 소프트웨어, 컴퓨터
특징
- 상위 클래스의 수정이 하위 클래스에 영향을 미침
- 계층구조가 복잡할 경우 좋지 않음
- HAS-A 관계(composition)
이미 생성된 코드의 기능을 가져다 쓰는 것
코드 재사용의 가장 일반적인 방법
형 변환(다운캐스팅)
업캐스팅된 클래스를 다시 원래의 타입으로 형 변환
ex)
업캐스팅
Customer vc = new VIPCustomer(); //묵시적
다운캐스팅
VIPCustomer vCustomer = (VIPCustomer)vc; //명시적
instanceof
인스턴스의 형 체크 방법,
Animal hAnimal = new Human();
Animal tAnimal = new Tiger();
Animal eAnimal = new Eagle();
위와 같이 업캐스팅된 class 인스턴스들을
if(animal instanceof Human) {
Human human = (Human)animal;
}
if문을 통해 원래 인스턴스의 형이 맞는지 여부를 체크한다.
ex)
package ch08;
import java.util.ArrayList;
class Animal{
public void move() {
System.out.println("동물이 움직입니다.");
}
public void eating() {
}
}
class Human extends Animal{
@Override
public void move() {
System.out.println("사람이 두 발로 걷습니다.");
}
public void readBook() {
System.out.println("사람이 책을 읽습니다.");
}
}
class Tiger extends Animal{
@Override
public void move() {
System.out.println("호랑이가 네 발로 뜁니다.");
}
public void hunting() {
System.out.println("호랑이가 사냥을 합니다.");
}
}
class Eagle extends Animal{
@Override
public void move() {
System.out.println("독수리가 하늘을 날아 다닙니다.");
}
public void flying() {
System.out.println("독수리가 양날개를 쭉 펴고 날아다닙니다.");
}
}
public class AnimalTest {
public static void main(String[] args) {
Animal hAnimal = new Human();
Animal tAnimal = new Tiger();
Animal eAnimal = new Eagle();
AnimalTest test = new AnimalTest();
//test.moveAnimal(hAnimal);
//test.moveAnimal(tAnimal);
//test.moveAnimal(eAnimal);
ArrayList<Animal> animalList = new ArrayList<>();
animalList.add(hAnimal);
animalList.add(tAnimal);
animalList.add(eAnimal);
for(Animal animal : animalList) {
animal.move();
}
test.testDownCasting(animalList);
}
public void testDownCasting (ArrayList<Animal> list) {
for(int i=0;i<list.size();i++) {
Animal animal = list.get(i);
if(animal instanceof Human) {
Human human = (Human)animal;
human.readBook();
}
else if(animal instanceof Tiger) {
Tiger tiger = (Tiger)animal;
tiger.hunting();
}
else if(animal instanceof Eagle) {
Eagle eagle = (Eagle)animal;
eagle.flying();
}
else {
System.out.println("unsupported type");
}
}
}
public void moveAnimal(Animal animal) {
animal.move();
}
}
추상 클래스
구현 코드 없이 메서드의 선언만 있는 추상 메서드를 포함한 클래스
ex)
public abstract void display();
public abstract void typing();
-> { } 선언부가 없다.
new를 통해 인스턴스화 할 수 없다.
ex)
public abstract class Computer {
public abstract void display();
public abstract void typing();
}
위와같은 컴퓨터 클래스가 있다면, Computer c = new Computer X 이렇게 생성못함
abstract 예약어를 사용하여 표현한다.
주로 상속을 위해 만든 클래스이다.
만약 상속받은 클래스에서도, 추상 메서드를 선언하지 않는다면,
상속받은 클래스 또한, abstract 예약어를 클래스 앞에 붙여야한다.
package ch09;
public abstract class Computer {
public abstract void display();
public abstract void typing();
public void turOn() {
System.out.println("전원을 켭니다");
}
public void turnOff() {
System.out.println("전원을 끕니다");
}
}
package ch09;
public class Desktop extends Computer{
@Override
public void display() {
System.out.println("Desktop display");
}
@Override
public void typing() {
System.out.println("typing dispaly");
}
@Override
public void turnOff() {
System.out.println("Desktop turnOff");
}
}
package ch09;
public abstract class NoteBook extends Computer {
@Override
public void display() {
System.out.println("NoteBook display");
}
}
package ch09;
public class MyNoteBook extends NoteBook {
@Override
public void typing() {
System.out.println("MyNoteBook typing");
}
}
package ch09;
public class ComputerTest {
public static void main(String[] args) {
//Computer computer = new Computer(); //에러, 추상클래스는 선언할 수 없음
Computer desktop = new Desktop(); //업케스팅
desktop.display();
//단 Computer에서 정의한 메서드만 사용가능, Desktop에서 생성한 메서드 사용불가
}
}
추상 클래스 응용
템플릿 메서드 패턴
-> 추상 메서드나 구현 된 메서드를 활용하여 코드의 흐름(시나리오)를 정의하는 메서드
ex)
final public void run() {
startCar();
drive();
wiper();
stop();
turnOff();
washCar();
}
위와 같이 final로 선언하여 흐름을 선언하고,
하위클레스에서 이를 수정할 수 없음
package ch10;
public abstract class Car {
public abstract void drive();
public abstract void stop();
public abstract void wiper();
public void startCar() {
System.out.println("시동을 켭니다.");
}
public void turnOff() {
System.out.println("시동을 끕니다.");
}
public void washCar() {} //구현내용만 없고, 구현된 것이기 때문에 하위 클래스에서 정의할 필요없음
final public void run() { //하위 클래스에서 재정의하지 못함
startCar();
drive();
wiper();
stop();
turnOff();
washCar();
}
}
Car 클래스에서 final run() 메서드를 선언하여 흐름을 정의한다.
package ch10;
public class ManualCar extends Car{
@Override
public void drive() {
System.out.println("사람이 운전합니다.");
System.out.println("사람이 핸들을 조작합니다.");
}
@Override
public void stop() {
System.out.println("장애물 앞에서 브레이크를 밟아 멈춥니다.");
}
@Override
public void wiper() {
// TODO Auto-generated method stub
}
}
package ch10;
public class AICar extends Car{
@Override
public void drive() {
System.out.println("자율 주행을 합니다.");
System.out.println("자동차가 스스로 방향을 바꿉니다.");
}
@Override
public void stop() {
System.out.println("장애물 앞에서 스스로 멈춥니다.");
}
@Override
public void wiper() {
// TODO Auto-generated method stub
}
@Override
public void washCar() {
System.out.println("자동 세차를 합니다.");
}
}
Car을 상속받는 AICar과 ManualCar에서는 추상 메서드를 각각정의한다.
이런 식의 패턴을
템플릿 메서드 패턴이라 한다.
'Java > Java&Spring 기초 강의' 카테고리의 다른 글
JAVA & Spring 강의 (자바 인강 6주차) 자바와 자료구조 (0) | 2022.04.27 |
---|---|
JAVA & Spring 강의 (자바 인강 5주차) 객체 지향 핵심, 자바의 유용한 클래스들, 자바와 자료구조 (0) | 2022.04.20 |
JAVA & Spring 강의 (자바 인강 3주차) 객체 지향 입문 (0) | 2022.04.01 |
JAVA & Spring 강의 (자바 인강 2주차) 자바기초2 (0) | 2022.03.30 |
JAVA & Spring 강의 (자바 인강 1주차) 자바기초1 (0) | 2022.03.23 |