본문 바로가기

BackEnd/Java

1005 JAVA - Polymorphism 다형성 (2)

728x90
반응형

Contents

     

     

    코드의 통일성을 더 향상시키기 위한 방법 : 업캐스팅 활용

     

     

    실습 1


    Circle 인스턴스 (C) 생성

    Circle c = new Circle();
    c.circlePaint();
    c.draw();
    
    System.out.println("--------------------------");
    // Rectangle 
    Rectangle r = new Rectangle();
    r.rdraw();
    r.draw();
    
    System.out.println("--------------------------");
    
    //Triangle
    Triangle t = new Triangle();
    t.design();
    t.draw();

     

    여러 도형의 특징을 공통적으로 포함하는 슈퍼클래스 Shape 정의 

    class Shape {
    //여러 도형의 공통점인 '그리다' 기능을 수행하는 draw () 메서드 정의
    public void draw() {
    System.out.println("도형 그리기!");
    }
    }
    
    //Shape 클래스를 상속받는 Circle 클래스 정의
    class Circle extends Shape {
    public void circlePaint() {
    System.out.println("원 그리기!");
    }
    }
    
    //Shape 클래스를 상속 받는 Rectangle 클래스 정의
    class Rectangle extends Shape{
    public void rdraw() {
    System.out.println("사각형 그리기");
    }
    }
    
    //Shape 클래스를 상속받는 Triangle 클래스 정의
    class Triangle extends Shape {
    public void design() {
    System.out.println("삼각형 그리기");
    }
    }

     

     


    circle, rectangle, triangle 의 공통 슈퍼 클래스인  Shape 타입 s 으로 세 인스턴스를 컨트롤 가능 


     Circle -> Shape 업캐스팅 

    Shape s = new Circle();
    s.draw(); //동적바인드에 의해 Circle 인스턴스의 draw() 메서드 호출
    
    //Rectangle -> Shape 업캐스팅
    s = new Rectangle();
    s.draw(); // Rectangle 인스턴스의 draw() 메서드 호출 
    
    //Triangle -> Shape 업캐스팅
    s = new Triangle();
    s.draw();

     

     

    다형성을 배열에 적용시키는 경우


     

    슈퍼클래스 타입으로 배열을 생성해서 배열의 각 인덱스에 각 각 서브클래스 인스턴스를 저장 가능

    shape 타입 배열을 생성 (크기가 3)

    Shape[] sArr = new Shape[3];

     

     

    0번 인덱스에 Circle 인스턴스를 생성하여 저장 

    sArr[0] = new Circle();

    Circle -> Shape에 업캐스팅을 한 것. 

     

     

    1번 인덱스에 Rectangle 인스턴스를 생성하여 저장 

    sArr[1] = new Rectangle();

     

    2번 인덱스에 Triangle 인스턴스를 생성하여 저장 

    sArr[2] = new Triangle();

     

     

     

    위의 3코드를 하기 코드로 나타낼 수 있다. 

    Shape[] sArr = {new Circle(), new Rectangle(), new Triangle()};
    
    sArr[0].draw();
    sArr[1].draw();
    sArr[2].draw();

    배열의 각 인덱스에는 인스턴스 주소가 저장되므로, 참조변수와 마찬가지로 

     

     

    배열명[인덱스].메서드명() 형태로 호출 가능 

    for(int i =0;  i <sArr.length; i++){
        sArr[i].draw();
    }

     

     

    메서드 - 다형성 활용 


     

    1. 이미 다형성이 적용된 배열을 메서드 파라미터로 전달

    
    Ex2 ex = new Ex2();
    ex.polymorphismDraw();
    
    } //main()
    
    public void polymorphismDraw() {
    
    } // Ex2

     

    static이 설정되지 않은 인스턴스 메서드를 호출 하는 경우

    먼저 인스턴스를 생성하고 호출 할 수 있다. 

     

    반면, static 설정되어 있는 '클래스(정적) 메서드'를 호출하는 경우 

    인스턴스를 생성하지 않아도클래스명.메서드 형태로 호출이 가능!

    이 때, 자신의 클래스 내부에서 정의한 '클래스(정적) 메서드' 라면 클래스명은 생략도 가능하다. 

     

    public static void polymorphismDraw(Shape[] sArr) {
    
        for (int i = 0; i < sArr.length; i++) {
            sArr[i].draw();
        }
    
    }

    반복문을 사용하여 배열 내의 모든 인스턴스의 draw() 메서드 호출

     

     

     

     

    2. 메서드 파라미터로 인스턴스를 전달 

    	//2. 메서드 파라미터로 인스턴스를 전달 
    	
    	polymorphismDraw2(new Circle());
    	polymorphismDraw2(new Rectangle());
    	polymorphismDraw2(new Triangle());
    	
    	
    	}//main
    
    public static void polymorphismDraw2(Shape s) {
    		//어떤 인스턴스가 전달 되더라도 draw() 메서드는 공통이므로 호출 가능! 
    		s.draw();
    	}

     

     

    전체

    package polymorphism;
    
    public class Ex2 {
    	public static void main(String[] args) {
    
    		// Circle 인스턴스 (C) 생성
    		Circle c = new Circle();
    		c.circlePaint();
    		c.draw();
    		
    	System.out.println("--------------------------");
    		// Rectangle 
    		Rectangle r = new Rectangle();
    		r.rdraw();
    		r.draw();
    
    	System.out.println("--------------------------");
    		
    		//Triangle
    		Triangle t = new Triangle();
    		t.design();
    		t.draw();
    		
    	System.out.println("--------------------------");
    		
    	
    	//코드의 통일성을 더 향상시키기 위한 방법 : 업캐스팅 활용
    	// => circle, rectangle, triangle 의 공통 슈퍼 클래스인 
    	// Shape 타입 s 으로 세 인스턴스를 컨트롤 가능 
    	// Circle -> Shape 업캐스팅 
    	Shape s = new Circle();
    	s.draw(); //동적바인드에 의해 Circle 인스턴스의 draw() 메서드 호출
    	
    	//Rectangle -> Shape 업캐스팅
    	s = new Rectangle();
    	s.draw(); // Rectangle 인스턴스의 draw() 메서드 호출 
    	
    	//Triangle -> Shape 업캐스팅
    	s = new Triangle();
    	s.draw();
    	
    	System.out.println("---------------------------------------");
    	
    //	다형성을 배열에 적용시키는 경우
    //	슈퍼클래스 타입으로 배열을 생성해서 배열의 각 인덱스에 각 각 서브클래스 인스턴스를 저장 가능
    	Shape[] sArr = new Shape[3]; //shape 타입 배열을 생성 (크기가 3)
    	
    	//0번 인덱스에 Circle 인스턴스를 생성하여 저장 
    	sArr[0] = new Circle();
    	sArr[1] = new Rectangle();
    	sArr[2] = new Triangle();
    	
    //	sArr[0].draw();
    //	sArr[1].draw();
    //	sArr[2].draw();
    	
    
    	for(int i =0;  i <sArr.length; i++){
    		sArr[i].draw();
    	}
    	//이미 다형성이 적용된 배열을 메서드 파라미터로 전달 
    	polymorphismDraw2(sArr);
    	
    	//2. 메서드 파라미터로 인스턴스를 전달 
    	
    	polymorphismDraw2(new Circle());
    	polymorphismDraw2(new Rectangle());
    	polymorphismDraw2(new Triangle());
    	
    	
    	}//main
    	
    	public static void polymorphismDraw2(Shape[] sArr) {
    
    		for (int i = 0; i < sArr.length; i++) {
    			sArr[i].draw();
    		}
    
    	}
    	public static void polymorphismDraw2(Shape s) {
    		//어떤 인스턴스가 전달 되더라도 draw() 메서드는 공통이므로 호출 가능! 
    		s.draw();
    	}
    
    }//Ex2 
    
    
    
    //여러 도형의 특징을 공통적으로 포함하는 슈퍼클래스 Shape 정의 
    class Shape {
    	//여러 도형의 공통점인 '그리다' 기능을 수행하는 draw () 메서드 정의
    	public void draw() {
    		System.out.println("도형 그리기!");
    	}
    }
    
    //Shape 클래스를 상속받는 Circle 클래스 정의
    class Circle extends Shape {
    	public void circlePaint() {
    		System.out.println("원 그리기!");
    	}
    }
    
    //Shape 클래스를 상속 받는 Rectangle 클래스 정의
    class Rectangle extends Shape{
    	public void rdraw() {
    		System.out.println("사각형 그리기");
    	}
    }
    
    //Shape 클래스를 상속받는 Triangle 클래스 정의
    class Triangle extends Shape {
    	public void design() {
    		System.out.println("삼각형 그리기");
    	}
    }

     

     

     

     

     

     

     

    실습 2


    package polymorphism;
    
    public class Ex3 {
    
    	public static void main(String[] args) {
    		Employee emp = new Employee("홍길동",3000);
    		System.out.println("Employee 정보 : " + emp.getEmployee());
    		emp.salaryCalculation();
    		
    		Manager man = new Manager("이순신",4000,"개발팀",3);
    		System.out.println("Manager 정보 : " + man.getManager());
    		System.out.println("Manager 정보 : " + man.getEmployee());
    		man.salaryCalculation();
    		
    		Engineer eng = new Engineer("강감찬", 5000, 5);
    		System.out.println("Engineer 정보 : " + eng.getEngineer());
    		System.out.println("Engineer 정보 : " + eng.getEmployee());
    		eng.salaryCalculation();
    		
    		System.out.println("================================================");
    		
    		//다형성 적용시키기
    		//각 인스턴스의 salaryCalculationAll() 메서드를 호출하여 
    		//자신의 인스턴스를 파라미터로 전달 
    		emp.salaryCalculationAll(emp);
    		// => emp.salaryCalculation(new Employee("홍길동",3000)); 이렇게 써도 됨.
    		man.salaryCalculationAll(emp);
    		eng.salaryCalculationAll(eng);
    	}
    
    }
    
    //직원 클래스 정의
    class Employee{
    	String name;
    	int salary;
    	public Employee(String name, int salary) {
    		super(); //Object 클래스의 Object() 생성자 호출 
    		this.name = name;
    		this.salary = salary;
    	}
    	
    	public String getEmployee() {
    		return name + ", " + salary;
    	}
    	
    	//일반 직원의 연봉 계산(기본 연봉을 그대로 적용)
    	public void salaryCalculation() {
    		System.out.println("연봉 : " + salary);
    	}
    	
    	//전 직원의 연봉을 슈퍼클래스인 Employee 클래스에서 모두 계산 하고싶다면, 다형성이 필요하다. 
    	//(employee, Manager, Engineer 인스턴스 모두 처리)
    	// 따라서, 메서드 파라미터로 다형성을 적용한 Employee 타입 필요. 
    	
    	public void salaryCalculationAll(Employee emp) { //업캐스팅됨
    		int salaryResult = 0; //연봉 계산 결과를 저장할 변수 
    		
    //*******************************************************************************************************************
    	
    //참조 영역의 축소로 인해 각 서브클래스 타입 멤버변수는 보이지 않음
    //=> Employee를 제외한 Manager, Engineer 의 경우
    //   다시 다운캐스팅을 통해 각 클래스에서 정의한 멤버에 접근해야 한다! 
    //=> 단, 무작정 다운캐스팅을 수행할 경우 오류가 발생할 수 있으므로
    //   반드시 instanceof 연산자를 통한 타입 판별 후 다운캐스팅 필요
    
    //=> 주의! 반드시 하위타입부터 판별을 수행해야 한다. 
    		
    //*******************************************************************************************************************	
    
    //가장 큰 개념인 Employee를 맨 마지막에 써줘야한다?
    				
    //*******************************************************************************************************************
    		
    		if(emp instanceof Manager) { //Manager 타입인가?
    			//Employee -> Engineer 타입으로 다운캐스팅 가능
    			System.out.println("Employee -> Engineer 로 다운캐스팅");
    		
    //			Manager man = emp; //자동 형변환 불가, 강제형변환 해야햄 
    			
    			Manager man = (Manager) emp;
    			
    			//업캐스팅으로 축소됐던 참조영역이 다운캐스팅으로 확대되었으므로
    			//다운캐스팅 된 Manager 타입 인스턴스를 통해 모든 멤버변수 접근 가능
    			//기본 영본과 관리 ㅣㅇㄴ원 수에 따른 인센티브를 더해서 계산 
    			salaryResult = man.salary + man.manageEmployeeCount * 10;
    		} else if(emp instanceof Engineer) { //Engineer 타입인지?
    //			Engineer eng = emp; //자동 형변환 불가, 강제형변환 해야햄 
    			
    			Engineer eng = (Engineer) emp;
    			salaryResult = eng.salary + eng.numOfCertificate * 20;
    			
    		}else if(emp instanceof Employee) { //Employee 타입인지?
    			System.out.println("Employee 그대로 사용!");
    			salaryResult = salary;
    			
    		}
    		
    		//각 직원의 계산된 연봉 출력
    		System.out.println("연봉 : " + salaryResult + "만원 입니다!");
    		
    	}
    	
    }
    
    //관리자 Manager 클래스 정의 - Employee 상속 
    class Manager extends Employee{
    	String depart; //부서명
    	int manageEmployeeCount; //관리하는 직원 수 
    	
    	//슈퍼클래스 기본생성자가 없으므로 파라미터 생성자를 호출하는 생성자 정의
    	public Manager(String name, int salary, String depart, int manageEmployeeCount) {
    		super(name, salary);
    		this.depart = depart;
    		this.manageEmployeeCount = manageEmployeeCount;
    	}
    	
    	public String getManager() {
    //		return name + ", " + salary + ", " + depart + ", " + manageEmployeeCount + "명";
    		return getEmployee() + ", " + depart + ", " + manageEmployeeCount + "명";
    	}
    
    	@Override
    	public void salaryCalculation() {
    		int salaryResult = salary + manageEmployeeCount * 10;
    		System.out.println("연봉 : " + salaryResult);
    	}
    
    	// Employee 의 연봉 계산 메서드를 오버라이딩
    	// => 매니저 연봉은 기본 연봉 + (관리직원 수 * 10만원) 
    }
    
    //엔지니어(Engineer) 클래스 정의 - Employee 상속 
    class Engineer extends Employee {
    	int numOfCertificate; //자격증 개수
    
    	public Engineer(String name, int salary, int numOfCertificate) {
    		super(name, salary);
    		this.numOfCertificate = numOfCertificate;
    	}
    	
    	public String getEngineer() {
    		return getEmployee() + ", " + numOfCertificate + "개";
    		
    	}
    	//Employee 의 연봉 계산 메서드를 오버라이딩
    	// 엔지니어 연봉은 기본 연봉 + (자격증 수 * 20만원)
    
    	@Override
    	public void salaryCalculation() {
    		int salaryResult = salary + (numOfCertificate * 20);
    		System.out.println("연봉 : " + salaryResult);
    	}
    	
    }
    728x90
    반응형