공부기록/사전학습

Java 사전학습_5

루팽 2022. 11. 19. 12:52

<Java 사전학습_5>

  1. 이클립스에서 자바 디버깅하기(21강)
  2. 상속과 다형성(22~23강)
  3. 오버 라이딩과 다형성(24강)
  4. 다형성 활용과 다운 캐스팅(25강)

 


 

1. 이클립스에서 자바 디버깅하기(21강)

break point-더블클릭
step into-그 함수 안으로 들어가기
step over-한 줄씩 실행
step retuen-함수 밖으로 빠져나가기

2. 상속과 다형성(22~23강)

상속
클래스를 정의할 때 이미 구현된 클래스를 상속(inheritance) 받아서 속성이나 기능이 확장되는 클래스를 구현함

상속하는 클래스
상위 클래스, parent class, base class, super class

상속받는 클래스
하위 클래스, child class, derived class, subclass

class B extends A {
}
//A클래스가 B클래스에게 상속한다 = B클래스가 A클래스를 상속받는다

상위 클래스는 하위 클래스보다 일반적인 의미를 가짐
하위 클래스는 상위 클래스보다 구체적인 의미를 가짐

class Mammal{
}
class Human extends Mammal{
}
//extends 뒤에는 단 하나의 class만 사용할 수 있음
//자바는 single inheritance만을 지원함

 

package inheritance;
public class Point {
	private int x;
	private int y;
	
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
}

 

package inheritance;
public class Circle {
	Point point; //has - a 관계
	
	private int radius;
	
	public Circle() {
		point = new Point();
	}
}


상속을 활용한 고객관리 프로그램
고객의 정보를 활용하여 고객 맞춤 서비스를 구현
고객의 등급에 따라 차별화된 할인율, 포인트를 지급
등급에 따른 클래스를 따로 구현하는 것이 아닌 일반적인 클래스를 먼저 구현하고 그보다 기능이 많은 클래스는 상속을 활용하여 구현

상위 클래스-Customer
하위 클래스-Vip Customer, Gold Customer

멤버 변수 설명
customerID 고객 아이디
customerName 고객 이름
customerGrade 고객 등급, 기본 생성자에서 지정되는 기본 등급은 SILVER입니다.
bonusPoint 고객의 보너스 포인트, 고객이 제품을 구매할 경우 누적되는 보너스 포인트
bonusRatio 보너스 포인트 적립 비율. 고객이 제품을 구매할 때 구매 금액의 일정 비율이 보너스 포인트로 적립됩니다. 이 때 계산되는 적립 비율입니다. 기본생성자에서 지정되는 적립 비율은 1%입니다. 즉 10,000원짜리를 구매하면 100원이 적립됩니다.


새로운 고객 등급이 필요한 경우
단골 고객에 대한 혜택이 필요함
우수 고객을 관리하기 위해 다음과 같은 혜택을 줌
고객 등급: VIP
제품 구매 할인율: 10%
보너스 포인트: 5%
담당 전문 상담원 배정

package inheritance;
public class Customer {
	protected int customerID; //protected는 상속관계에서 사용가능
	protected String customerName;
	protected String customerGrade;
	int bonusPoint; //디폴트는 같은 패키지 안에서 사용가능
	double bonusRatio;
	
	public Customer() {
		customerGrade = "SILVER";
		bonusRatio = 0.01;
	}
	
	public Customer(int customerID, String customerName) {
		this.customerID = customerID;
		this.customerName = customerName;
		customerGrade = "SILVER";
		bonusRatio = 0.01;
	}
	
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;
		return price;	
	}
	
	public String showCustomerInfo() {
		return customerName + "님의 등급은 " + customerGrade + "이며, 보너스 포인트는 "
				+ bonusPoint + "P 입니다.";
	}

	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;
	}
}

 

package inheritance;
public class VIPCustomer extends Customer {
	private int agentID;
	private double saleRatio;
	
	public VIPCustomer() {
		customerGrade = "VIP";
		bonusRatio = 0.05;
		saleRatio = 0.1;
	}
	
	public int getAgentID() {
		return agentID;
	}
}

 

package inheritance;
import inheritance.Customer;
public class CustomerTest1 {
	public static void main(String[] args) {
		Customer customer1 = new Customer();
		customer1.setCustomerID(00001);
		customer1.setCustomerName("Luppang");
		
		VIPCustomer customer2 = new VIPCustomer();
		customer2.setCustomerID(00002);
		customer2.setCustomerName("Luka");
		
		System.out.println(customer1.showCustomerInfo());
		System.out.println(customer2.showCustomerInfo());
	}
}


접근 제한자 가시성

  외부클래스 하위클래스 동일패키지 내부클래스
public O O O O
protected X O O O
선언되지 않음(default) X X O O
private X X X O


상속에서 클래스 생성 과정
하위 클래스가 생성될 때 상위 클래스가 먼저 생성됨
상위 클래스의 생성자가 호출되고 하위 클래스의 생성자가 호출됨
하위 클래스의 생성자에서는 무조건 상위 클래스의 생성자가 호출되어야 함
아무것도 없는 경우 컴파일러는 상위 클래스 기본 생성자를 호출하기 위한 super()를 코드에 넣어줌
super() 호출되는 생성자는 상위 클래스의 기본 생성자임
만약 상위 클래스의 기본 생성자가 없는 경우(매개변수가 있는 생성자만 존재하는 경우) 하위 클래스는 명시적으로 상위 클래스를 호출해야 함
상위 클래스의 인스턴스가 먼저 생성되고, 하위 클래스의 인스턴스가 생성됨

package inheritance;
public class Customer {
	protected int customerID; //protected는 상속관계에서 사용가능
	protected String customerName;
	protected String customerGrade;
	int bonusPoint; //디폴트는 같은 패키지 안에서 사용가능
	double bonusRatio;
	
	public Customer(int customerID, String customerName) {
		this.customerID = customerID;
		this.customerName = customerName;
		customerGrade = "SILVER";
		bonusRatio = 0.01;
		
		System.out.println("Customer(int, String) 호출");
	}
	
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;
		return price;	
	}
	
	public String showCustomerInfo() {
		return customerName + "님의 등급은 " + customerGrade + "이며, 보너스 포인트는 "
				+ bonusPoint + "P 입니다.";
	}

	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;
	}
}

 

package inheritance;
public class VIPCustomer extends Customer {
	private int agentID;
	private double saleRatio;
	
	public VIPCustomer(int customerID, String customerName) {
		super(customerID, customerName); //상위클래스 호
		customerGrade = "VIP";
		bonusRatio = 0.05;
		saleRatio = 0.1;
		
		System.out.println("VIPCustomer(int, String) 호출");
	}
	
	public int getAgentID() {
		return agentID;
	}
}

 

package inheritance;
import inheritance.Customer;
public class CustomerTest1 {
	public static void main(String[] args) {		
		VIPCustomer customer2 = new VIPCustomer(00002, "Luka");

		customer2.bonusPoint = 1000;
		
		System.out.println(customer2.showCustomerInfo());
		//상위 클래스인 Customer가 먼저 호출된 후 VIPCostomer 호출됨
	}
}


super 예약어
this가 자기 자신의 인스턴스의 주소를 가지는 것처럼
super는 하위 클래스가 상위 클래스에 대한 주소를 가지게 됨
하위 클래스가 상위 클래스에 접근할 때 사용할 수 있음

상위 클래스로의 묵시적 형 변환(업 캐스팅)
상위 클래스형으로 변수를 선언하고 하위 클래스 인스턴스를 생성할 수 있음
하위 클래스는 상위 클래스의 타입을 내포하고 있으므로 상위 클래스로 묵시적 형 변환이 가능함
형 변환에서의 메모리(아래의 예제에서 customer1이 가리키는 것)
VIPCustomer() 생성자의 호출로 인스턴스는 모두 생성되었지만 타입이 Customer이므로 접근할 수 있는 변수나 메서드는 Customer의 변수와 메서드임

Customer costomer1 = new VIPCustomer();
//선언된 클래스형(상위클래스형) Customer
//생성된 인스턴스의 클래스형(하위클래스형) VIPCustomer

 

3. 오버 라이딩과 다형성(24강)

메서드 오버 라이딩(overriding)
상위 클래스에 정의된 메서드 중 하위 클래스와 기능이 맞지 않거나 추가 기능이 필요한 결우 같은 이름과 매개변수로 하위 클래스에서 재정의함

가상 메서드(virtual method)
프로그램에서 어떤 객체의 변수나 메서드의 참조는 그 타입에 따라 이루어짐.
가상 메서드의 경우 타입과 상관없이 실제 생성된 인스턴스의 메서드가 호출되는 원리

package inheritance;
public class Customer {
	protected int customerID; //protected는 상속관계에서 사용가능
	protected String customerName;
	protected String customerGrade;
	int bonusPoint; //디폴트는 같은 패키지 안에서 사용가능
	double bonusRatio;
	
	public Customer(int customerID, String customerName) {
		this.customerID = customerID;
		this.customerName = customerName;
		customerGrade = "SILVER";
		bonusRatio = 0.01;
		
		System.out.println("Customer(int, String) 호출");
	}
	
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;
		return price;	
	}
	
	public String showCustomerInfo() {
		return customerName + "님의 등급은 " + customerGrade + "이며, 보너스 포인트는 "
				+ bonusPoint + "P 입니다.";
	}

	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;
	}
}

 

package inheritance;
public class VIPCustomer extends Customer {
	private int agentID;
	private double saleRatio;
	
	public VIPCustomer(int customerID, String customerName, int agentID) {
		super(customerID, customerName);
		customerGrade = "VIP";
		bonusRatio = 0.05;
		saleRatio = 0.1;
		this.agentID = agentID;
		
		System.out.println("VIPCustomer(int, String) 호출");
	}
	
	public int calcPrice(int price) { //오버라이딩, calcPrice재정의됨
		bonusPoint += price * bonusRatio;
		return price - (int)(price * saleRatio);	
	}
	
	public int getAgentID() {
		return agentID;
	}
}

 

package inheritance;
public class OverridingTestJava {
	public static void main(String[] args) {
		Customer customer1 = new Customer(0001, "Luppang");
		int price = customer1.calcPrice(10000);
		System.out.println("지불 금액은 " + price + "원이고, " + customer1.showCustomerInfo());
		//지불 금액은 10000원이고, Luppang님의 등급은 SILVER이며, 보너스 포인트는 100P 입니다.
		
		VIPCustomer customer2 = new VIPCustomer(0001, "Luka", 100);
		price = customer2.calcPrice(10000);
		System.out.println("지불 금액은 " + price + "원이고, " + customer2.showCustomerInfo());
		//지불 금액은 9000원이고, Luka님의 등급은 VIP이며, 보너스 포인트는 500P 입니다.
		
		Customer customerWho = new VIPCustomer(0002, "Who", 100);
		price = customerWho.calcPrice(10000);
		System.out.println("지불 금액은 " + price + "원이고, " + customerWho.showCustomerInfo());
		//지불 금액은 9000원이고, Who님의 등급은 VIP이며, 보너스 포인트는 500P 입니다.
		//타입은 Customer지만, 실제 생성된 인스턴스인 VIPCustomer클래스의 calcPrice()메서드가 호출됨
	}
}


다형성(polymorphism)
하나의 코드가 여러 가지 자료형으로 구현되어 실행되는 것
정보은닉, 상속과 더불어 객체지향 프로그래밍의 가장 큰 특징 중 하나
객체지향 프로그래밍의 유연성, 재활용성, 유지보수성의 기본이 되는 특징

다형성 구현하기
하나의 클래스를 상속받은 여러 클래스가 있는 경우 각 클래스마다 같은 이름의 서로 다른 메서드를 재정의함
상위 클래스 타입으로 선언된 하나의 변수가 여러 인스턴스에 대입되어 구현이 실행될 수 있음

package inheritance;
class Animal{
	public void move() {
		System.out.println("동물이 움직입니다.");
	}
}

class Human extends Animal {
	public void move() {
		System.out.println("사람이 두 발로 걷습니다.");
	}
}

class Tiger extends Animal {
	public void move() {
		System.out.println("호랑이가 네 발로 걷습니다.");
	}
}

class Eagle extends Animal {
	public void move() {
		System.out.println("독수리가 하늘을 납니다.");
	}
}

public class AnimalTest {
	public static void main(String[] args) {
		AnimalTest test = new AnimalTest();
		test.moveAnimal(new Human());
		test.moveAnimal(new Tiger());
		test.moveAnimal(new Eagle());
	}
	
	public void moveAnimal(Animal animal) {
		animal.move(); //다형성 구현, 동일한 코드에 각기 다른 구현이 실행됨
		//사람이 두 발로 걷습니다. 호랑이가 네 발로 걷습니다. 독수리가 하늘을 납니다.
	}
}


상속을 언제 사용할까
여러 클래스를 생성하지 않고 하나의 클래스에 공통적인 요소를 모으고 나머지 클래스는 이를 상속받은 다음 각각 필요한 특성과 메서드를 구현하는 방법
하나의 클래스에 여러 특성을 한꺼번에 구현하는 경우 코드 안에 if문이 많이 생길 수 있음

4. 다형성 활용과 다운 캐스팅(25강)

IS-A 관계(is a relationship: inheritance)
일반적인 개념과 구체적인 개념과의 관계
상위 클래스-일반적인 개념 클래스(ex. 포유류)
하위 클래스- 구체적인 개념 클래스(ex. 사람, 원숭이, 고래…)
단순히 코드를 재사용하는 목적으로 사용하지 않음

HAS-A관계(composition)
한 클래스가 다른 클래스를 소유한 관계
코드 재사용의 한 방법

Class Student {
	Subject majorSubject;
} //Student가 Subject를 포함한 관계

 

package witharraylist;
public class Customer {
	protected int customerID;
	protected String customerName;
	protected String customerGrade;
	int bonusPoint;
	double bonusRatio;
	
	public Customer(int customerID, String customerName) {
		this.customerID = customerID;
		this.customerName = customerName;
		customerGrade = "SILVER";
		bonusRatio = 0.01;
		
		System.out.println("Customer(int, String) 호출");
	}
	
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;
		return price;	
	}
	
	public String showCustomerInfo() {
		return customerName + "님의 등급은 " + customerGrade + "이며, 보너스 포인트는 "
				+ bonusPoint + "P 입니다.";
	}

	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;
	}
}

 

package witharraylist;
public class VIPCustomer extends Customer {
	private int agentID;
	private double saleRatio;
	
	public VIPCustomer(int customerID, String customerName, int agentID) {
		super(customerID, customerName);
		customerGrade = "VIP";
		bonusRatio = 0.05;
		saleRatio = 0.1;
		this.agentID = agentID;
		
		System.out.println("VIPCustomer(int, String) 호출");
	}
	
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;
		return price - (int)(price * saleRatio);	
	}
	
	public int getAgentID() {
		return agentID;
	}

	@Override
	public String showCustomerInfo() {
		return super.showCustomerInfo() + " 담당 상담원 아이디는 " + agentID + "번 입니다.";
	}
}

 

package witharraylist;

public class GoldCustomer extends Customer {
	double saleRatio;
	
	public GoldCustomer (int customerID, String customerName) {
		super(customerID, customerName);
		customerGrade = "GOLD";
		bonusRatio = 0.02;
		saleRatio = 0.1;
	}

	@Override
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;
		return price - (int)(price * saleRatio);
	}	
}

 

package witharraylist;
import java.util.ArrayList;
public class CustomerTest {
	public static void main(String[] args) {
		ArrayList<Customer> customerList = new ArrayList<Customer> ();
		
		Customer customer1 = new Customer(0001, "루팽구");
		VIPCustomer customer2 = new VIPCustomer(0002, "루꾸카", 001);
		GoldCustomer customer3 = new GoldCustomer(0003, "루이");
		GoldCustomer customer4 = new GoldCustomer(0004, "장");
		Customer customer5 = new Customer(0005, "히코리");
		
		customerList.add(customer1);
		customerList.add(customer2);
		customerList.add(customer3);
		customerList.add(customer4);
		customerList.add(customer5);
		
		System.out.println("===== 고객 정보 출력 =====");
		for(Customer customer : customerList) {
			System.out.println(customer.showCustomerInfo());
		}
		/*		 ===== 고객 정보 출력 =====
		루팽구님의 등급은 SILVER이며, 보너스 포인트는 0P 입니다.
		루꾸카님의 등급은 VIP이며, 보너스 포인트는 0P 입니다. 담당 상담원 아이디는 1번 입니다.
		루이님의 등급은 GOLD이며, 보너스 포인트는 0P 입니다.
		장님의 등급은 GOLD이며, 보너스 포인트는 0P 입니다.
		히코리님의 등급은 SILVER이며, 보너스 포인트는 0P 입니다.*/
		
		System.out.println("===== 할인률과 보너스 포인트 =====");
		int price = 10000;
		for(Customer customer : customerList) {
			int cost = customer.calcPrice(price);
			System.out.println(customer.getCustomerName() + "님이 " + cost + "원을 지불하셨습니다");
			System.out.println(customer.showCustomerInfo());
		}
		/*		 ===== 할인률과 보너스 포인트 =====
		루팽구님이 10000원을 지불하셨습니다
		루팽구님의 등급은 SILVER이며, 보너스 포인트는 100P 입니다.
		루꾸카님이 9000원을 지불하셨습니다
		루꾸카님의 등급은 VIP이며, 보너스 포인트는 500P 입니다. 담당 상담원 아이디는 1번 입니다.
		루이님이 9000원을 지불하셨습니다
		루이님의 등급은 GOLD이며, 보너스 포인트는 200P 입니다.
		장님이 9000원을 지불하셨습니다
		장님의 등급은 GOLD이며, 보너스 포인트는 200P 입니다.
		히코리님이 10000원을 지불하셨습니다
		히코리님의 등급은 SILVER이며, 보너스 포인트는 100P 입니다.*/
	}
}


다운 캐스팅-instanceof
하위 클래스가 상위 클래스로 형 변환되는 것은 묵시적으로 이루어짐
다시 원래 자료형인 하위 클래스로 형 변환하려면 명시적으로 다운 캐스팅을 해야 함
이 때 원래 인스턴스의 타입을 체크하는 예약어가 instanceof

Animal hAnimal = new Human();
if(hAnimal instanceof Human) { //hAnimal 인스턴스 자료형이 Human이라면
	Human human = (Human)hAnimal; //인스턴스 hAnimal을 Human형으로 다운캐스팅
}