본문 바로가기

3월 ~ 5월) 자바

11Day - AcdemyApp & AcdemyStudent & AcdemyInstructor & AcdemyPerson & AcdemyStaff / Car & CarApp / Employee & EmployeeApp & EmployeeContract & EmployeeRegular & EmployeeTime

오버라이딩을 통한
묵시적 객체형변환
명시적 객체 형변환

오버라이딩 - 부모꺼이상하면 자식꺼로 쓰기

참조 - 부모
객체 - 자식

 

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 제한자 : 클래스, 메소드에 사용하는 제한자

 

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