[java] 다형성과 추상클래스

young-gue Park·2023년 7월 24일
0

Java

목록 보기
6/11
post-thumbnail

⚡ 다형성과 추상클래스


📌 다형성(polymorphism)

  • 다형을 가질 수 있는 성질
  • 상속 관계에 있을 때 조상 클래스의 타입으로 자식 클래스 객체를 참조할 수 있다.
Object ob = new Person(); // O
Person per = new Student(); // O

Student stu = new Person(); // X
  • 메모리에 있더라도 참조하는 자료형에 따라서 접근 범위가 달라진다.
Object ob = new Student(); // Object의 영역까지만 접근 가능
Person per = new Student(); // Person의 영역까지 접근 가능
Student st = new Student(); // Student의 모든 영역 접근 가능

⭐ 참조 변수의 형 변환

  • 자손타입 -> 조상타입 (묵시적 형 변환)
  • 형 변환 생략 가능
Student st = new Student();
person p = st;
  • 조상타입 -> 자손타입 (명시적 형 변환)
  • 형 변환 생략 불가능
Person p = new Person();
Student st = (Student)p;

Person p2 = new Student();
Student st2 = (Student)p2;

Student() 생성자로 생성해도 컴파일러는 이를 Person으로 인식하기 때문에 형 변환이 필요하다.

🌟 ClassCastException
자손타입으로 형 변환을 거친 참조 변수가 조상타입에는 없는 속성을 가져오려 할때 발생하는 예외

  • instanceof 연산자
  • 참조변수가 참조하고 있는 인스턴스의 타입을 확인 하기 위해서 사용
  • 결과를 boolean으로 반환
  • true가 반환이 되면 해당 타입으로 형 변환 가능
Person per = new Student();

if(per instanceof Student) {
	System.out.println("학생 맞음");
    ((Student)per).study();
}

.이 우선 순위가 높기 때문에 괄호 사용이 필수적이다.

⭐ 동적 바인딩

  • 상속관계에서 멤버변수가 중복이 되면 참조 변수 타입에 따라 연결이 달라진다.
  • 🌟 메서드가 중복될 때 무조건 자식 클래스의 메서드가 호출된다.
  • static 메서드는 참조변수 타입의 영향을 받기 때문에 이를 방지하고자 클래스 이름으로 메서드 호출
class Parent {
	String x = "parent";
    
    public String method() {
    	return "아빠임";
    }
}

class Child extends Parent {
	String x = "Child";
    
    @Override
    public String method() {
    	return "아들임";
    }
}

public class Test {
	public static void main(String[]args) {
    	Parent p = new Child();
        
        p.x; // parent
        p.method(); // 아들임
    }
}
  • 🌟 조상타입으로 반환하는 메서드가 매개변수로 자식타입을 받으면 그 안에서 사용되는 메서드는 모두 자식타입의 메서드로 사용된다. 이것이 동적 바인딩.

📌 추상 클래스

  • 조상 클래스의 메서드 중 자손 클래스에서 반드시 재정의해서 사용되는 메서드는 조상의 구현이 무의미하다.
  • 이 때, 메서드의 선언부만 남기고 구현부는 ;(세미콜론)으로 대체
  • 구현부가 없으므로 abstract 키워드를 메서드 선언부에 추가
  • 객체를 생성할 수 없는 클래스라는 의미로 클래스 선언부에 abstract를 추가
public abstract class Chef {
	String name;
    int age;
    String speciality;
    
    public void eat() {
    	System.out.println("야무지게 먹어야지");
    }
    
    public abstract void cook();
}

🤷‍♂️ 구현부에 빈 괄호만 남겨놓으면 되는거 아님?

  • 강제성이 사라져 재작성의 필요가 사라져버린다. abstract는 자식클래스의 오버라이딩에 강제성을 부여한다. 그리고 부모가 구현하고 싶은 내용이 없다고 해서 구현 자체를 빼버리면 동적바인딩에 의해 자식의 오버라이딩된 함수가 실행되는 기회를 없애게 된다.

⭐ 추상 클래스의 특징

  • abstract 클래스는 상속 전용의 클래스
  • 클래스에 구현부가 없는 메서드가 있으므로 객체를 생성할 수 없음.
  • 상위 클래스 타입으로 자식을 참조할 수는 있음.
Chef chef1 = new Chef(); // X
Chef chef2 = new KFoodChef(); // O
  • 조상 클래스에서 상속 받은 abstract 메서드를 재정의 하지 않은 경우, 클래스 내부에 abstract 메서드가 있으므로 자식 클래스는 abstract 클래스가 되어야 한다.

  • 추상 클래스도 익명 클래스 문법을 이용해서 1회 한정으로 구현하고 인스턴스를 만들 수 있다.

Chef c2 = new Chef() {
	@Override
    public void cook() {
    	System.out.println("신이라 뭐든 요리해요.");
    }
}
  • 🌟 추상 클래스는 구현의 강제를 통해 프로그램의 안정성을 향상한다.
profile
Hodie mihi, Cras tibi

1개의 댓글

comment-user-thumbnail
2023년 7월 24일

좋은 글 감사합니다. 자주 올게요 :)

답글 달기