JAVA 다형성

Dev.Shinny·2022년 9월 26일
0

자바의 정석

목록 보기
7/18

다형성(polymorphism)이란?

  • 하나의 객체가 여러 가지 타입을 가질 수 있는 것
  • 부모클래스 타입의 참조 변수로 자식클래스 인스턴스를 참조할수 있는 것.
    (반대로, 자식 타입의 참조 변수로 부모 타입의 인스턴스를 참조할 수는 없다.)

class Person {
    public void print() {
        System.out.println("Person.print");
    }
}

class Student extends Person {
    public void print() {
        System.out.println("Student.print");
    }

    public void print2() {
        System.out.println("Student.print2");
    }
}

class CollegeStudent extends Person {
    public void print() {
        System.out.println("CollegeStudent.print");
    }
}

public class Main {
    public static void main(String[] args) {
    	
        (1) 다형성
        Person p1 = new Person();
        Person p2 = new Student();
        Student s1 = new Student();
        Student s2 = new Person(); // (1) 에러 발생
        
        p1.print();	//	Person.print
        s1.print(); //	Student.print
        s1.print2(); //	Stuendt.print2
        p2.print(); //	Student.print (오버라이딩된 메서드로 실행)
        p2.print2(); //	(2) 에러 발생
        
    }
 }       

위 코드는 두 번의 에러가 발생한다. 자식클래스는 부모클래스의 인스턴스를 참조할수 없기 때문에 (1)에러가 발생했다. Person과 Student는 멤버변수가 다르다. 자식 타입의 참조변수로 부모타입의 인스터스를 참조하는 것은 존재하지 않는 멤버를 사용하고자 할 가능성이 있으므로 허용하지 않는 것이다. 참조변수가 사용할 수 있는 멤버의 개수는 인스턴스의 멤버 개수보다 같거나 적어야 한다. (2)에러로도 같은 이유이다. 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라지기 때문이다.

배열 사용하기

< 동일 코드 생략 ... > 
class Person { ... }
class Student extends Person { ... }
class CollegeStudent extends Person { ... }

public class Practice {
    public static void main(String[] args) {
    
        (1)
    	Person p1 = new Person();
    	Person p2 = new Student();
    	Person p3 = new CollegeStudent();
    	
    	p1.print();
    	p2.print();
    	p3.print();
    	
    	(2)
    	Person person1[] = {new Person(),new Student(),new CollegeStudent()};
    	
    	for(Person item:person1) {
    		item.print();
    	}
    }
}

(1)과 (2)은 결과적으로 같다. 부모 타입의 참조 변수 배열을 사용하면, 서로 다른 종류의 객체를 배열로 묶어서 다룰 수 있다.

참조 변수의 형변환

참조 변수도 형변환이 가능하지만, 서로 상속관계에 있는 클래스 사이여야만 한다.
다운 캐스팅은 명시적으로 해야한다.

자식 타입 → 부모 타입 ( Up - casting )    : 형변환 생략 가능
부모 타입 → 자식 타입 ( Down -casting )   : 형변환 생략 불가능

< 동일 코드 생략 ... > 
class Person { ... }
class Student extends Person { ... }
class CollegeStudent extends Person { ... }

public class Main {
    public static void main(String[] args) {
    	       
        (2) 형변환
        Person pp1 = null;
        Student ss1 = null;

        Person pp2 = new Person();
        Student ss2= new Student();
        Person pp3 = new Student(); // 업캐스팅 (묵시적)
        
        pp1 = pp2; // 부모 타입 참조 변수-인스턴스
        pp1 = ss2; // 부모 타입 참조 변수-자식 타입 인스턴스
        
        ss1 = ss2; // 같은 타입 참조변수와 인스턴스 
        ss1 = pp2; // 에러_자식 타입의 참조변수로 부모 타입 인스턴스 참조 불가.
        ss1 = (Student)pp3; // 다운캐스팅 (명시적)  
    }
}        

서로 상속관계에 있는 타입간의 형변환은 양방향 자유롭게 수행될 수 있으나, 참조 변수가 가라키는 인스턴스의 자손타입으로 형변환은 불가능하다.

형변환은 참조 변수의 타입을 변환하는 것인지 인스턴스를 변환하는 것은 아니기 때문에 참조 변수의 형변환은 인스턴스에 아무런 영향을 미치지 않는다. 단지 참조 변수의 형변환을 통해서, 참조하고 있는 인스턴스에서 사용할 수 있는 멤버의 범위를 조절하는 것뿐이다.

instanceof

해당 참조 변수의 인스턴스가 맞는지 체크 해주는 연산자.

참조변수 instanceof 타입(클래스명)
pp1 instanceof Person // true

어떤 타입에 대한 instanceof 연산의 결과가 true라는 것은 검사한 타입으로 형변환이 가능하다는 것을 뜻한다.

< 동일 코드 생략 ... > 
class Person { ... }
class Student extends Person { ... }
class CollegeStudent extends Person { ... }

public class Main {
    public static void main(String[] args) {   
    
        (3) instanceof
       	Person pe1 = new Person();
        Student st1 = new Student();
        Person pe2 = new Student();
        Person pe3 = new CollegeStudent();

        System.out.println(pe1 instanceof Person); 	//	true
        System.out.println(pe1 instanceof Student);	//	false
        
        System.out.println(st1 instanceof Student);	//	true
        System.out.println(st1 instanceof Person);	//	true
        
        System.out.println(pe2 instanceof Person);	//	true
        System.out.println(pe2 instanceof Student);	//	true
        
        System.out.println(pe3 instanceof Person);	//	true
        System.out.println(pe3 instanceof CollegeStudent); // true
        
        < 활용 > 
        if(pe1 instanceof Student) {
        	Student stu1 = (Student)pe1;
        }
        
        if(st1 instanceof Person) {
        	Person per1 = (Person)st1;
        }        
    }
}        

< instaneof 사용에 반대하는 개발자의 글 >
https://link-intersystems.com/blog/2015/04/25/instanceof-vs-polimorphism/
https://tecoble.techcourse.co.kr/post/2021-04-26-instanceof/ ( 한글 정리본 )

profile
Hello I'm Shinny. A developer who try to enjoy the challenge.

0개의 댓글