형식) public abstract class 클래스명 { }
형식) public abstract 반환형(자료형 변수명, 자료형 변수명, ...);
형식) public final class 클래스명 { }
형식) 접근제한자 final 자료형 필드명 = 초기값;
형식) 접근제한자 final 반환형 메소드명(자료형 변수명, 자료형 변수명, ) {
명령,
명령;
...
}
형식) public static final 자료형 상수필드명 = 값;
package inheritance;
//사원 급여 관리 프로그램 작성
public class EmployeeApp {
public static void main(String[] args) {
/*
//Employee 클래스가 추상클래스로 선언되어 있는 경우 객체 생성시 에러 발생
Employee employee=new Employee(1000, "홍길동");
System.out.println("사원번호 = "+employee.getEmpNo());
System.out.println("사원이름 = "+employee.getEmpName());
*/
/*
//추상클래스로 참조변수를 생성하여 자식클래스의 객체를 저장 가능
Employee employee1=new EmployeeRegular();
Employee employee2=new EmployeeTime();
Employee employee3=new EmployeeContract();
*/
//Employee 클래스를 상속받은 자식클래스의 객체를 저장할 수 있는 요소를 가진 배열 생성
Employee[] empArray=new Employee[5];
empArray[0]=new EmployeeRegular(1000, "홍길동", 96000000);
empArray[1]=new EmployeeTime(2000, "임꺽정", 50000, 150);
empArray[2]=new EmployeeContract(3000, "전우치", 7000000);
empArray[3]=new EmployeeTime(4000, "일지매", 20000, 100);
empArray[4]=new EmployeeRegular(5000, "장길산", 60000000);
for(Employee employee : empArray) {
System.out.println("사원번호 = "+employee.getEmpNo());
System.out.println("사원이름 = "+employee.getEmpName());
/*
//급여를 계산하여 반환하는 메소드를 호출해 급여를 반환받아 출력
// => 부모클래스로 생성된 참조변수이므로 부모클래스의 메소드만 호출 가능하지만
//자식클래스의 메소드 호출 불가능
// => 부모클래스의 참조변수로 자식클래스의 메소드를 호출하기 위해서는 객체 형변환 사용
//자식클래스가 여러개인 경우 부모클래스의 참조변수가 객체 형변환 가능한지를 확인하기
//위해 instanceof 연산자으로 비교한 후 명시적 객체 형변환 사용 - ClassCastException 발지
if(employee instanceof EmployeeRegular) {
System.out.println("사원급여 = "+((EmployeeRegular)employee).computeSalary());
} else if(employee instanceof EmployeeTime) {
System.out.println("사원급여 = "+((EmployeeTime)employee).computeTimePay());
} else if(employee instanceof EmployeeContract) {
System.out.println("사원급여 = "+((EmployeeContract)employee).computeConstract());
}
*/
//묵시적 객체 형변환에 의해 부모클래스의 참조변수가 일시적으로 자식클래스의 객체를
//참조하여 자식클래스의 오버라이딩 선언된 메소드를 호출
System.out.println("사원급여 = "+employee.computePay());
System.out.println("인센티브 = "+employee.computeIncentive());
System.out.println("==========================================================");
}
}
}
public abstract class Employee {
private int empNo;
private String empName;
// 상수필드(Constant Field): 값 대신 사용하기 위한 이름 제공 - 상수
public static final double INCENTIVE_RATE = 1.5;
// 부모클래스는 매개변수가 없는 생성자 생성해야됨
public Employee() {
}
public Employee(int empNo, String empName) {
this.empNo = empNo;
this.empName = empName;
}
public int getEmpNo() {
return empNo;
}
public void setEmpNo(int empNo) {
this.empNo = empNo;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
// 급여를 계산하여 반환하는 메소드
// => 자식클래스에서 무조건 오버라이딩 선언되도록 추상메서드로 작성
// 명령이 필요한게 아니라 메소드 이름만 동일시 하고싶을 때
public abstract int computePay();
// 모든 사원에게 사원듭여를 150%를 성과급으로 계산하여 반환하는 메소드
// 문제점) 자식클래스에서 메소드를 오버라이딩 선언할 경우 부모클래스의 메소드는 숨겨지고
// 자식클래스가 메소드가 호출되어 비정상적인 결과 발생
// 해결법) final 제한자를 사용하여 메소드를 작성하면 자식클래스에 오버라이딩 선언 불가능
public final int computeIncentive() {
// 추상메소드를 호출하면 자동으로 자식클래스의 오버라이딩 선언된 메소드 호출
return (int) (computePay() * INCENTIVE_RATE);
}
}
package inheritance;
// 정규직 사원정보(사원번호, 사원이름, 연봉)를 저장하기 위한 클래스
// => Employee 클래스를 상속받아 작성
// => 추상클래스를 상속받은 자식클래스는 추상클래스에 작성된 모든 추상메소드를 오버라이딩 선언
public class EmployeeRegular extends Employee {
private int annualSalary;
public EmployeeRegular(int empNo, String empName, int annualSalary) {
super(empNo, empName);
this.annualSalary = annualSalary;
}
public int getAnnualSalary() {
return annualSalary;
}
public void setAnnualSalary(int annualSalary) {
this.annualSalary = annualSalary;
}
// 급여를 계산하여 반환하는 메소드
// return 값이 있는 경우 void가 아닌 자료형으로 작성함
@Override
public int computePay() {
return annualSalary / 12;
}
// 부모클래스의 final 메소드를 오버라이딩 선언한 경우 에러 발생
/*
@Override
public int computeIncentive() {
return super.computeIncentive();
}
*/
}
package inheritance;
// 계약직 사원정보(사원번호, 사원이름, 계약급여)를 저장하기 위한 클래스
// => Employee 클래스를 상속받아 작성
public class EmployeeContract extends Employee {
private int contractPay;
public EmployeeContract(int empNo, String empName, int contractPay) {
super(empNo, empName);
this.contractPay = contractPay;
}
public int getContractPay() {
return contractPay;
}
public void setContractPay(int contractPay) {
this.contractPay = contractPay;
}
@Override
public int computePay() {
return contractPay;
}
}
package inheritance;
// 시간제 사원정보(사원번호, 사원이름, 시급, 근무시간)를 저장하기 위한 클래스
// => Employee 클래스를 상속받아 작성
public class EmployeeTime extends Employee {
private int moneyPerHour;
private int workedHour;
public EmployeeTime(int empNo, String empName, int moneyPerHour, int workedHour) {
super(empNo, empName);
this.moneyPerHour = moneyPerHour;
this.workedHour = workedHour;
}
public int getMoneyPerHour() {
return moneyPerHour;
}
public void setMoneyPerHour(int moneyPerHour) {
this.moneyPerHour = moneyPerHour;
}
public int getWorkedHour() {
return workedHour;
}
public void setWorkedHour(int workedHour) {
this.workedHour = workedHour;
}
// 급여를 계산하여 반환하는 메소드
@Override
public int computePay() {
return moneyPerHour * workedHour;
}
}