캡슐화(Encapsulation) : 객체의 필드, 메소드를 하나로 묶고, 실제 구현 내용을 감추는 것.
캡슐화하여 보호하는 이유는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록!
접근제한자를 이용하여 캡슐화함.
상속(Inheritance) : 부모 객체의 필드와 메소드를 하위 객체에게 물려주는 행위.
상속 대상 : 필드, 메소드
상위 객체를 재사용하여 하위 객체를 빨리 개발 가능, 반복된 코드의 중복을 줄임, 유지 보수의 편리성 제공

UML에서 generation : 상속이다.
다형성(Polymorphism) : 하나의 타입에 여러 가지 객체 대입해 다양한 실행 결과를 얻는 것.
의미는 같지만 표현되어지는 것은 다르다!
다형성을 구현하기 위한 전제조건은 상속이다.
ex) draw()도형 <- draw()원, draw()삼각형, draw()사각형

package calculator;
public class Ui {
public static void main(String[] args) {
Calculator cal = new Calculator();
int result = 0;
result = cal.sum(10, 20);
System.out.println(result);
cal.save(result);//save는 void니깐 화면에서 리턴받을 게 없다. 너는 저장 해 끝!
System.out.println("OK");//하지만 이 코드는 문제가 생긴지 안생긴지를 모른다.
//문제가 발생했을 때 오류를 출력해주는 것을 '예외처리'라고 한다!
}
}
package calculator;
public class Calculator {
public int sum(int a, int b) {
int result = 0;
result = a + b;
return result;
}
public void save(int a){
//뭔가 저장됨.
}
}

package inherit;
public class Employee {
private String id;
private String name;
private double salary;
//getter, setter
public double getSalary() {
return salary;
}
//constructor
public Employee() {
}
public Employee(String id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
//method
public double getAnnSalary() {
double result = 0.0;
result = this.salary * 12;
return result;
}
@Override
public String toString() {
return id + " " + name + " " + salary;
}
}
package inherit;
public class Manager extends Employee {
private double bonus;
public Manager() {
super();// 위에 있는 컨스트럭터 코드를 사용한다. 상속이 아님.
} // 컨스트럭터는 불러서 사용하고 getter setter로 bonus만 불러와서 추가 컨스트럭터 생성 없이 이용도 가능.
public Manager(String id, String name, double salary) {
super(id, name, salary);
}
// constructor using field에서 Employee(String, String, double)을 선택하여 추가할 수 있다.
public Manager(String id, String name, double salary, double bonus) {
super(id, name, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
//함수의 재정의(overriding). 상속받은 함수를 그대로 쓸 수도 있다. 하지만 필요에 의해 오버라이딩할 수 있다.
@Override//anotation주석이 붙는다.
public double getAnnSalary() {
double result = 0.0;
result = (this.getSalary() + this.bonus) * 12;//private이라서 접근이 안됨. protected로 바꾸면 접근 가능
//또는 getter를 설정하여 가져오게 할 수 있음.
//result = super.getAnnSalary() + (this.bonus * 12);
//상위에 있는 getAnnSalary를 불러와서 계산할 수도 있다.
return result;
}
@Override
public String toString() {
return super.toString() + " " + bonus;//상속받은 Employee의 toString을 super로 가져옴.
}
//source에서 toString을 누르면 inherited를 설정할 수 있다.
}
package inherit;
public class Sales extends Employee {
private String loc;
private double rate;
public Sales() {
}
//기본 Employee 생성자를 source constructor from super에서 불러옴
public Sales(String id, String name, double salary) {
super(id, name, salary);
}
public Sales(String id, String name, double salary, String loc, double rate) {
super(id, name, salary);
this.loc = loc;
this.rate = rate;
}
@Override
public String toString() {
return super.toString() + " " + loc + " " + rate;
}
@Override
public double getAnnSalary() {
double result = 0.0;
result = super.getAnnSalary() + this.getIncentive() * 12;
return result;
}
public double getIncentive() {
double result = 0.0;
result = getSalary() * this.rate;
return result;
}
}
package inherit;
public class App {
public static void main(String[] args) {
Employee e = new Employee("100", "james", 500);
System.out.println(e);
System.out.println(e.getAnnSalary());
Manager m = new Manager("200", "Kim", 500, 50);
System.out.println(m);//출력 시 Employee[]로 정보가 나옴.
//M is a E 의 관계가 성립한다. E is a M은 성립 안함.
//toString을 오버라이딩하는 경우 Manager로 정보를 나오게 할 수 있음.
System.out.println(m.getAnnSalary());
}
}
package inherit;
public class App2 {
public static void main(String[] args) {
//Manager is a Employee
Employee e = new Manager("100", "james", 500, 50);
//Manager m = new Employee("100", "james2", 550);//m은 e이지만 e는 m이 아니다.
Employee ea[] = new Employee[5];
ea[0] = new Employee("100", "james2", 500);
ea[1] = new Employee("200", "james3", 500);
ea[2] = new Manager("100", "james1", 500, 50);
ea[3] = new Manager("100", "james4", 500, 50);
ea[4] = new Sales("300", "jamess", 500, "seoul", 0.35);
//배열을 생성할 때도, Manager는 Employee의 상속을 받았기 때문에 같은 배열로 들어갈 수 있다!
for(Employee data : ea) {
System.out.println(data);//출력 시 manager는 오버라이딩한 toString으로 출력됨.
System.out.println(data.getAnnSalary());
//연봉 가져와. Employee는 연봉만 가져오고 Manager는 bonus까지 합쳐서 연봉 산출해줌.
//출력하는 것이 달라! 이것이 다형성. 상속을 활용하고 상속받은 것 내에서 오버라이딩을 하였음.
if(data instanceof Sales) {
Sales s = (Sales)data;
//객체의 타입캐스팅; data 인스턴스 중 Sales인 것을 골라서 타입을 Sales로 변경해준다.
System.out.println(s.getIncentive());
}
//data.getIncentive();//다형성에서 Sales 내 specialized된 함수는 보이지 않는다.
//Sales가 Employee[]내에 선언되었기 때문에 Employee에 정의된 함수들만 data객체에서 확인할 수 있다.
//다형성을 구현하기 위해선 상위 클래스의 함수를 잘 이용하여야 한다. 따라서 상위 클래스 함수를 잘 설계해야 한다!!!
//database나 객체 설계를 하는 사람들은 원론적으로 설계를 하지만, 프로그래밍 할 때는 버거울 수가 있음.
//따라서 위의 if문처럼 조건문과 객체의 타입캐스팅을 통해 인스턴스가 Sales인 것을 선별하고 형변환.
//새로 형변환한 객체에서는 원래 Sales의 메소드 getIncentive를 사용할 수 있다.
}
}
}

Employee 메소드에 getIncentive가 없어서 다형성 구현이 어려웠지만 위처럼 Employee에 빈 메소드를 넣고 Sales에서 Override를 하는 방법으로도 다형성을 구현 가능!(Override안하고 getIncentive를 새로 만들 수 있지만 Override를 하여 상위 클래스와 같은 글자인지 확인할 수 있다.(@Override인데 메소드명 변경하면 빨간줄 나옴.)

자바에서는 오로지 하나의 클래스에서만 상속을 받을 수 있다.(단일 상속)
super(매개값) : 부모생성자 호출할 경우, 가장 윗줄에서 호출
부모 메소드 사용 : super
메소드 재정의는 부모 메소드 숨기는 효과!
메소드 재정의 : @Override => 이를 통해 폴리머피즘을 구현할 수 있다.
override한 경우 접근제어자를 부모보다 좁게 설정이 불가능하다.
(public -> private 불가능.)
final 키워드 : 더이상 재정의가 불가능하게 막는다!
다형성 - 상위 클래스의 함수를 알고 있으면 하위 클래스의 변경을 통해 다양한 효과를 만들어낼 수 있음. 하위 클래스에서 각 함수명을 통일해서 사용 가능(오버라이드)
Promotion(자동타입변환) : 자식클래스를 부모클래스 변수에 넣을 수 있다. 자동으로 타입 변환이 일어남. ex) Employee e = new Manager() 가능. 아래 예시.
package inherit2;
public class TaxCal {
public double getTax(Employee e) {
double result = 0.0;
result = e.getAnnSalary() * 0.17;
return result;
}
}

Employee e라고 선언된 부분은 Manager Sales 다 들어갈 수 있다.
객체 타입 확인(instanceof) :
부모 타입이면 모두 자식 타입으로 강제 타입 변환할 수 있는 것은 아님.
먼저 자식 타입인지 확인 후 강제 타입 실행해야함.
if(parent instanceof Child){Child child = (Child) parent;
강제 타입 변환(Casting) : p.187
부모 타입을 자식 타입으로 변환하는 것
(조건 : 자식타입을 부모타입으로 자동변환 후, 다시 자식타입으로 변환할 때. ex) Manager -> Employee -> Manager)
Manager가 Employee로 선언이 되면 부모타입의 선언된 필드와 메소드만 사용이 가능한데, 자식타입에 선언된 필드와 메소드를 다시 사용해야 할 경우 Casting을 함.