오버라이딩을 통한
묵시적 객체형변환
명시적 객체 형변환
오버라이딩 - 부모꺼이상하면 자식꺼로 쓰기
참조 - 부모
객체 - 자식
367p
AcdemyApp
// 학원인적자원(강사, 학생, 직원) 관리 프로그램
public class AcademyApp {
public static void main(String[] args) {
/*
// 학생정보를 저장하기 위한 요소들이 존재하는 배열 생성
AcademyStudent[] student = new AcademyStudent[300]; // 학생 300명x, 학생정보를 300개 저장할수있는 요소
// 강사정보를 저장하기 위한 요소들이 존재하는 배열 생성
AcdemyInstructor[] instructors = new AcdemyInstructor[100]; // 강사정보를 100개 저장할수있는 요소
// 직원정보를 저장하기 위한 요소들이 존재하는 배열생성
AcdemyStaff[] staffs = new AcdemyStaff[100];
*/
//사람정보(AcademyPerson 객체)를 저장하기 위한 요소들이 존재하는 배열 생성
// > 배열 요소에 학생정보(AcademyStudent 객체), 강사정보(AcademyInstructor 객체), 직원정보(AcademyStaff 객체) 저장 가능
// > 부모클래스의 참조변수에는 자식클래스의 생성자로 객체를 생성하여 저장 가능
AcademyPerson[] persons = new AcademyPerson[5];
// 자식클래스의 생성자로 객체를 생성하면 부모클래스의 객체를 먼저 생성한 후 자식클래스의 객체를 생성
// > 배열 요소에는 부모클래스의 객체가 저장되어 부모클래스의 메소드 호출
// > 객체 형변환을 이용하면 배열 요소에 자식클래스의 객체를 일시적으로 저장하여 자식클래스의 메소드 호출 가능
persons[0] = new AcademyStudent(1000, "홍길동", "웹개발자 과정");
persons[1] = new AcademyInstructor (2000, "임꺽정", "Java 과목");
persons[2] = new AcademyStaff(3000, "전우치", "운영관리팀");
persons[3] = new AcademyStudent(4000, "일지매", "웹디자인 과정");
persons[4] = new AcademyStaff(5000, "장길산", "경영회계팀");
// 배열 요소에 저장된 객체를 하나씩 제공받아 참조변수에 저장하여 일괄처리
for (AcademyPerson person : persons) {
//오버라이드 선언되지 않은 자식클래스의 메소드를 호출하기 위해서는 명시적 객체
//형변환을 이용하여 참조변수에 자식클래스의 객체를 일시적으로 저장하여 자식
//클래스의 메소드 호출
//문제점)상속관계가 아닌 클래스로 명시적 객체 형변환 할 경우 ClassCastException 발생
//해결법)참조변수로 객체 형변환 가능한 클래스를 확인한 후 명시적 객체 형변환 이용
// => instanceof 연산자를 사용하여 참조변수의 객체 형변환 가능 클래스 검사
//형식) 참조변수 instanceof 클래스
// => 참조변수로 참조 가능한 클래스를 확인하여 [false] 또는 [true]를 제공하는 연산자
if (person instanceof AcademyStudent) {
System.out.println(((AcademyStudent) person).getCourse() + "의 학생정보 >> ");
} else if (person instanceof AcademyInstructor) {
System.out.println(((AcademyInstructor) person).getSubject() + "의 강사정보 >> ");
} else if (person instanceof AcademyStaff) {
System.out.println(((AcademyStaff) person).getDepart() + "의 직원정보 >> ");
}
// 오버라이드 선언된 자식클래스의 메소드는 묵시적 객체 형변환에 의해 부모클래스의 메소드를 호출하지 않고 자식클래스의 메소드 호출
// 참조변수에 저장된 자식클래스의 객체에 의해 자식클래스의 메소드가 선택 호출
// > 오버라이드에 의한 다형성 : 객체 형변환에 의해 참조변수에 저장된 객체에 따라 다른 자식클래스의 메소드를 선택 호출
person.display();
System.out.println("-----------------------------------------------");
}
}
}
웹개발자 과정의 학생정보 >>
학생번호 = 1000
학생이름 = 홍길동
수강 과목 = 웹개발자 과정
-----------------------------------------------
Java 과목의 강사정보 >>
강사번호 = 2000
강사이름 = 임꺽정
강의과목 = Java 과목
-----------------------------------------------
운영관리팀의 직원정보 >>
직원번호 = 3000
직원이름 = 전우치
근무부서 = 운영관리팀
-----------------------------------------------
웹디자인 과정의 학생정보 >>
학생번호 = 4000
학생이름 = 일지매
수강 과목 = 웹디자인 과정
-----------------------------------------------
경영회계팀의 직원정보 >>
직원번호 = 5000
직원이름 = 장길산
근무부서 = 경영회계팀
-----------------------------------------------
AcdemyStudemt
// 학생정보(학생번호, 학생이름, 수강과목)를 저장하기 위한 클래스
// > 학생번호와 학생이름 관련 속성과 행위는 person 클래스를 상속받아 작성
public class AcademyStudent extends AcademyPerson {
private String course;
public AcademyStudent() {
// TODO Auto-generated constructor stub
}
public AcademyStudent(int num, String name, String course) {
super(num, name);
this.course = course;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
public void display() {
System.out.println("학생번호 = " + getNum());
System.out.println("학생이름 = " + getName());
System.out.println("수강 과목 = " + course);
}
}
AcdemyInstructor
public class AcademyInstructor extends AcademyPerson {
private String subject;
public AcademyInstructor() {
// TODO Auto-generated constructor stub
}
public AcademyInstructor(int num, String name, String subject) {
super(num, name);
this.subject = subject;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public void display() {
System.out.println("강사번호 = " + getNum());
System.out.println("강사이름 = " + getName());
System.out.println("강의과목 = " + subject);
}
}
AcademyPerson
// 사람정보(번호, 이름)를 저장하기 위한 클래스
// > 학생, 강사, 직원에 대한 공통적인 속성과 행위를 표현하기위한 클래스
// > 한원인적자원 관련 클래스가 반드시 상속받아야 되는 부모클래스
public class AcademyPerson {
private int num;
private String name;
public AcademyPerson() {
// TODO Auto-generated constructor stub
}
public AcademyPerson(int num, String name) {
super();
this.num = num;
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void display() {
System.out.println("번호 = "+num);
System.out.println("이름 = "+name);
}
}
AcademyStaff
// 직원정보 (직원정보, 직원이름, 근무부서)를 저장하기 위한 클래스
// > 직원번호와 직원이름 관련 속성과 행위는 AcademyPerson 클래스를 상속받아 사용
// F2 파일바꾸기 / alt + shift + R 식별자 바꾸기
public class AcademyStaff extends AcademyPerson {
private String depart;
public AcademyStaff() {
// TODO Auto-generated constructor stub
}
public AcademyStaff(int num, String name, String depart) {
super(num, name);
this.depart = depart;
}
public String getDepart() {
return depart;
}
public void setDepart(String depart) {
this.depart = depart;
}
public void display() {
System.out.println("직원번호 = " + getNum());
System.out.println("직원이름 = " + getName());
System.out.println("근무부서 = " + depart);
}
}
Car
// 자동차정보 (모델명, 소유자명)를 저장하기 위한 클래스
// > 클래스 선언시 상속받은 부모클래스가 없는 경우 기본적으로 Object 클래스를 자동으로 상속
// > 모든 Java 클래스는 무조건 Object 클래스를 상속받아 사용 가능
// Object 클래스 - 모든 Java 클래스의 최선조 클래스
// > Object 클래스로 생성된
public class Car /* extends Object */ {
private String modelName;
private String userName;
public Car() {
}
public Car(String modelName, String userName) {
this.modelName = modelName;
this.userName = userName;
}
public String getModelName() {
return modelName;
}
public void setModelName(String modelName) {
this.modelName = modelName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
// Object 클래스의 toString() 메소드를 오버라이드 선언
// > Object 클래스의 toString() 메소드는 숨겨지고 Car 클래스의 toString() 메소드 호출
// > VO 클래스에서는 필드값을 문자열로 변환하여 반환하는 명령 작성 - 필드값 확인
public String toString() {
return super.toString();
}
}
CarApp
public class CarApp {
public static void main(String[] args) {
Car car = new Car("싼타페" , "홍길동");
System.out.println("모델명 = " + car.getModelName());
System.out.println("소유자 = " + car.getUserName());
System.out.println("--------------------------------");
/*
// Object.toString() : 참조변수에 저장된 객체를 참조하여 "클래스명@메모리주소" 형식의 문자열로 변환하여반환하는 메소드
System.out.println("car.toString() = " + car.toString() );
// 참조변수를 출력할 경우 자동으로 toString() 메소드 호출
System.out.println("car = " + car);
*/
// Object 클래스의 toString() 메소드가 아닌 Car클래스의 toString() 메소드 자동 호출
System.out.println("car = " + car );
System.out.println("-------------------------------------------------");
// 문자열이 저장된 String 객체를 생성하여 객체의 메모리주소를 참조변수에 저장
String name = "홍길동";
// String 클래스에 오버라이드 선언된 toString() 메소드 호출
// > String 객체에 저장된 문자열을 반환하는 메소드
System.out.println("name = " + name.toString());
// String 클래스의 참조변수를 출력할 경웅 자동으로 String 클래스의 toString() 메소드 호출
System.out.println("name = " + name);
System.out.println("-------------------------------------------------");
}
}
모델명 = 싼타페
소유자 = 홍길동
--------------------------------
car = inheritcance.Car@1a407d53
-------------------------------------------------
name = 홍길동
name = 홍길동
-------------------------------------------------
// static 제한자 : 클래스, 메소드, 필드에 사용하는 제한자
// > 객체가 아닌 클래스로 접근하여 사용하기 위한 제한자
// final 제한자 : 클래스, 메소드, 필드에 사용하는 제한자
// 1.final 제한자를 필드에 사용하여 선언 - final 필드
// 형식) 접근제한자 final 자료형 필드명 = 초기값;
// > 필드값을 변경하지 못하도록 제한하는 기능 제공 - 필드에 저장된 값을 변경할 경우 에러 발생
// > 필드를 선언할 때 반드시 초기값을 필드에 저장
// 2.final 제한자를 메소드에 사용하여 선언 - final 메소드
// 형식) 접근제한자 final 반환형 메소드명(자료형 매개변수명, ...) { }
// > 자식클래스에 메소드를 오버라이드 선언하지 못하도록 제한하는 기능 제공
// 3.final 제한자를 클래스에 사용하여 선언 - final 클래스
// 형식) 접근제한자 final class 클래스명 { }
// > final 클래스를 상속 받지 목하도록 제한하는 기능 제공
// 사원정보 (사원번호, 사원이름, 연봉)를 저장하기 위한 클래스
// > 모든 사원 관련 클래스가 상속받아야 되는 부모클래스
// > 객체 생성이 목적이 아닌 상속을 목적으로 작성된 클래스 - 추성클래스로 선언하는것을 권장
// 추상클래스(Abstract Class) - abstract 제한자를 사용하여 선언된 클래스
// > 객체 생성 불가능 - 상속 전용 클래스
// 형식) public abstract class 클래스명 { }
// > abstract 제한자 : 클래스, 메소드에 사용하는 제한자
// > 객체가 아닌 클래스로 접근하여 사용하기 위한 제한자
// final 제한자 : 클래스, 메소드, 필드에 사용하는 제한자
// 1.final 제한자를 필드에 사용하여 선언 - final 필드
// 형식) 접근제한자 final 자료형 필드명 = 초기값;
// > 필드값을 변경하지 못하도록 제한하는 기능 제공 - 필드에 저장된 값을 변경할 경우 에러 발생
// > 필드를 선언할 때 반드시 초기값을 필드에 저장
// 2.final 제한자를 메소드에 사용하여 선언 - final 메소드
// 형식) 접근제한자 final 반환형 메소드명(자료형 매개변수명, ...) { }
// > 자식클래스에 메소드를 오버라이드 선언하지 못하도록 제한하는 기능 제공
// 3.final 제한자를 클래스에 사용하여 선언 - final 클래스
// 형식) 접근제한자 final class 클래스명 { }
// > final 클래스를 상속 받지 목하도록 제한하는 기능 제공
// 사원정보 (사원번호, 사원이름, 연봉)를 저장하기 위한 클래스
// > 모든 사원 관련 클래스가 상속받아야 되는 부모클래스
// > 객체 생성이 목적이 아닌 상속을 목적으로 작성된 클래스 - 추성클래스로 선언하는것을 권장
// 추상클래스(Abstract Class) - abstract 제한자를 사용하여 선언된 클래스
// > 객체 생성 불가능 - 상속 전용 클래스
// 형식) public abstract class 클래스명 { }
// > abstract 제한자 : 클래스, 메소드에 사용하는 제한자
Employee
public abstract class Employee {
private int empNo;
private String empName;
// 상수필드 (Constant Field) - 프로그램에서 값대신 사용하기 위한 단어로 제공되는 필드 값
// 형식) public static final 자료형 변수명 = 초기값;
// > 상수명은 대문자로 작성하여 스네이크 표기법을 이용하여 작성하는 것을 권장
public static final double INCENTIVE_RATE = 1.5;
public Employee() {
// TODO Auto-generated constructor stub
}
public Employee(int empNo, String empName) {
super();
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 int computePay() {
return 0;
}
*/
// 자식클래스에서 부모클래스의 메소드를 무조건 오버라이드 선언하도록 설정하기 위해
// abstract 제한자를 사용하여 추상 메소드로 선언
// 추상메소드(Abstract Method) - abstract 제한자를 사용하여 선언된 메소드
// > 메소드의 머릿부만 작성하고 몸체부는 작성하지 않는 미완성된 메소드
// 형식) 접근제한자 abstract 반환형 메소드명(자료형 매개변수명, ...);
// > 추상메소드가 선언된 클래스는 반드시 추상클래스로 선언
// 추상메소드가 선언된 클래스를 상속받은 자식클래스는 무조건 모든 추상메소드를 오버라이드 선언
// > 자식클래스에서 추상메소드를 오버라이드 선언하지 않으면 자식클래스도 추상클래스로 설정되어 객체를 생성할 경우 에러 발생
public abstract int computePay();
// 인센티브를 계산하여 반환하는 메소드
// > 모든 사원에게 급여의 150%를 인센티브로 제공되도록 계산
// 자식클래스에서 메소드를 오버라이드 선언하면 비정상적인 결과값 반환
// > 자식클래스에서 메소드를 오버라이드 선언하지 못하도록 final 메소드로 선언
public final int computeIncentive() {
//추상메소드를 호출한 경우 묵시적 객체 형변환에 의해 자식클래스의 메소드 호출
//return (int)(computePay()*1.5);
//값 대신 상수를 사용 - 유지보수의 효율성 증가
return (int)(computePay() * INCENTIVE_RATE);
}
}
EmployeeApp
// 사원 급여 관리 프로그램
public class EmployeeApp {
public static void main(String[] args) {
//추상클래스로 객체를 생성할 경우 에러 발생
// > 추상클래스로 참조변수 생성 가능
//Employee employee=new Employee();
/*
//부모클래스로 참조변수를 생성하여 자식클래스로 객체를 생성하여 저장 가능
Employee employee1 = new EmployeeRegular();
Employee employee2 = new EmployeeTime();
Employee employee3 = new EmployeeContract();
*/
Employee[] empArray = new Employee[5];
empArray[0] = new EmployeeRegular(1000, "홍길동", 96000000);
empArray[1] = new EmployeeTime(2000, "임꺽정", 50000, 150);
empArray[2] = new EmployeeTime(3000, "전우치", 700000);
empArray[3] = new EmployeeTime(4000, "일지매", 20000, 100);
empArray[4] = new EmployeeTime(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).computeContract());
}
*/
//자식클래스에서 부모클래스의 메소드를 오버라이드 선언하면 묵시적 객체 형변환에
//의해 자동으로 참조변수가 자식클래스로 형변환되어 자식클래스의 메소드 호출 가능
System.out.println("사원급여 = " +employee.computePay());
//사원의 인센티브를 반환받아 출력
System.out.println("인센티브 = "+employee.computeIncentive());
System.out.println("-------------------------------------------------------");
}
}
}
사원번호 = 1000
사원이름 = 홍길동
사원급여 = 8000000
인센티브 = 12000000
-------------------------------------------------------
사원번호 = 2000
사원이름 = 임꺽정
사원급여 = 7500000
인센티브 = 11250000
-------------------------------------------------------
사원번호 = 0
사원이름 = null
사원급여 = 0
인센티브 = 0
-------------------------------------------------------
사원번호 = 4000
사원이름 = 일지매
사원급여 = 2000000
인센티브 = 3000000
-------------------------------------------------------
사원번호 = 0
사원이름 = null
사원급여 = 0
인센티브 = 0
-------------------------------------------------------
EmployeeContract
// 계약직 사원정보(사원번호, 사원이름, 계약급여)를 저장하기 위한 클래스
// > Employee 클래스를 상속받아 작성
public class EmployeeContract extends Employee {
private int contractPay;
public EmployeeContract() {
// TODO Auto-generated constructor stub
}
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;
}
//급여를 계산하여 반환하는 메소드
public int computeContract() {
return contractPay;
}
@Override
public int computePay() {
return contractPay;
}
}
EmployeeRegular
// 정규직 사원정보 (사원번호, 사원이름, 연봉)를 저장하기 위한 클래스
// > Employee 클래스를 상속받아 작성
public class EmployeeRegular extends Employee {
private int anuualSalary;
public EmployeeRegular() {
// TODO Auto-generated constructor stub
}
public EmployeeRegular(int empNo, String empName, int anuualSalary) {
super(empNo, empName);
this.anuualSalary = anuualSalary;
}
public int getAnuualSalary() {
return anuualSalary;
}
public void setAnuualSalary(int anuualSalary) {
this.anuualSalary = anuualSalary;
}
//급여를 계산하여 반환하는 메소드
public int computeSalary() {
return anuualSalary/12;
}
public int computePay() {
return anuualSalary/12;
}
/*
// 부모클래스의 final 메소드를 오버라이드 선언하여 에러 발생
@Override
public int computeIncentive() {
return 100000000;
}
*/
}
EmployeeTime
// 시간제 사원정보(사원번호, 사원이름, 시급, 근무시간)를 저장하기 위한 클래스
// > Employee 클래스를 상속받아 작성
public class EmployeeTime extends Employee {
private int moneyPerHour;
private int workedHour;
public EmployeeTime() {
// TODO Auto-generated constructor stub
}
public EmployeeTime(int empNo, String empName, int moneyPerHour, int workedHour) {
super(empNo, empName);
this.moneyPerHour = moneyPerHour;
this.workedHour = workedHour;
}