국비/Java

[11-1] Java 오버라이딩(Overriding), 다형성 맛보기

제발 취업하게 해주세요 2022. 4. 21. 23:39
오버라이딩(Overriding)
   - 상속 받고 있는 부모클래스의 메소드를 자식클래스에서 재정의(재작성) 하는 것
   - 부모클래스가 제공하고 있는 메소드를 자식이 일부 고쳐서 사용하겠다는 의미
   - 자식클래스의 오버라이드 된 메소드가 우선권을 가져서 호출된다.
 
 * 오버라이딩의 성립조건
  1. 부모메소드의 메소드명과 동일
  2. 매개변수의 자료형, 갯수, 순서가 동일(매개변수명과는 무관)
      ex) publi cint result(int a, int b){int a + int b;} // 부모
           public int result(int a, int b, int c){int a + int b + int c} //자식 갯수가 달라서 오버라이딩xxxxx 이건 오버로딩!
  3. 반환형이 동일해야한다
  4. 부모메소드의 접근제한자보다 공유 범위가 넓거나 같아야 함 >> 규약의 개념

 *  @Override
 *  어노테이션 (annotation)
 *  일종의 주석
 *   - 생략 가능 => 명시를 안해도 부모메소드와 형태가 같으면 오버라이딩 된 것으로 판단.
 *   - 어노테이션을 붙이는 이유?
 *    => 실수를 줄이자/
 *    => 누가 봐도 오버라이딩
 *   
 *   개발자들끼리의 약속
 *   생략은 가능하지만 작성하는 습관을 들이자!
 * 부모클래스에게 상속받는 것
 * => ★★★★★타입(자료형)★★★★★★
 * => 메소드, 필드
// 부모꺼는 내꺼 내꺼도 내꺼

1. 부모타입 자료형으로 부모 객체를 다루는 경우
Parent p1 = new Parent();
p1.printParent();
// p1.printChild(); // 자식꺼는 내꺼가 아냐
//p1으로는 Parent에만 접근 가능

2. 자식타입 자료형으로 자식 객체를 다루는 경우
Child1 c1 = new Child1();
c1.printChild1(); // 내꺼는 내꺼
c1.printParent(); // 부모님것도 내꺼
//c1으로는 Parent, Child1에 둘 다 접근 가능

 3. 부모타입 자료형으로 자식 객체를 다루는 경우 => 다형성이 적용된 개념

Parent p2 = /*(Parent)*/new Child1();
// Child1이 (Parent)로 자동형변환
p2.printParent();
// p2.printChild1(); 자식거는 부모가 사용 x
//p2로는 Parent만 접근 가능

// 양쪽 자료형이 다름에도 오류가 나지 않는 이유??
// Parent형으로 자동형변환이 되었으니까
// 상속구조에서는 클래스 형변환이 가능하다!!!!!!!!!!!

// 부모는 자식으로 형변환이 될까?
((Child1)p2).printChild1();


 * 클래스간의 형변환
  - "상속구조"일 경우에만 클래스간의 형변환이 가능하다!!
 
 * 1.UpCasting
 
 * 자식타입 => 부모타입으로 변환
 * 생략 가능, 자동형변환
 * ex) 자식.부모메소드();

 * 2.DownCasting
 
 * 부모타입 => 자식타입
 * 생략이 불가능하다.
 * ((자식)부모).자식메소드();

다형성을 사용하는 이유는?
* 배열을 써보자
* 배열의 특징은?? == 한 종류의 자료형인 값들을 묶어서 관리가 가능하다


// 다형성을 배우기 전...
// Child1 객체 2개와 Child2 객체 2개를 관리해야 됨

 Child1[] arr1 = new Child1[2];
 arr1[0] = new Child1(1, 2, 3);
 arr1[1] = new Child1(4, 5, 6);
 
 Child2[] arr2 = new Child2[2];
 arr2[0] = new Child2(1, 2, 3);
 arr2[1] = new Child2(1, 2, 3);

* 다형성을 접목한 배열

 // 부모타입의 객체 배열을 만든 다음
 // 자식들을 부모 배열에 묶어보자
 
 Parent[] arr = new Parent[4];
 arr[0] = /*(Parent)*/new Child1(1, 2, 3);
 arr[1] = /*(Parent)*/new Child2(4, 5, 6);
 arr[2] = /*(Parent)*/new Child1(7, 8, 9);
 arr[3] = /*(Parent)*/new Child2(10, 11, 12);
 
 
 // PrintParent 메소드 호출
 for(int i = 0; i < arr.length; i++) {
 arr[i].printParent();
 }
*  Child1을 Child2로 강제형변환을 한다면??
   >> ((Child2)arr[0]).printChild2();
   >>>>ClassCastException이 발생 // 클래스간에 형변환이 잘못되었을 경우 발생함
* 원래 Child1인 애를 Child2로 바꾸려니까 에러가 났다
* 클래스간의 형변환은 !!상속!!(부모자식) 관계에서만 가능하다
* 자식-자식 x
 * instanceof 연산자 => true / false
  :  현재 레퍼런스가 실질적으로 어떤 클래스타입을 참조하는지 확인할 때 사용
ex) arr[ 0 ] instanceof Child1 => 결과는 true or false

 * 동적바인딩 : 프로그램 실행되기 전에는 컴파일 되면서 정적바인딩(자료형의 메소드를 가리킴)
    단, 실질적으로 참조하는 자식클래스에 해당 메소드가 오버라이딩 되어 있다면
    프로그램 실행 시 동적으로 자식클래스의 오버라이딩 된 메소드를 찾아서 실행
  
 
 // 오버라이딩 특징 : 오버라이딩 개념이 적용된 메소드 호출 시 원조 메소드보다 새롭게 정의된 메소드가 우선순위가 높기 때문에 먼저 호출
 
 // 우리가 앞으로 객체 배열을 쓸 때 오버라이딩을 이용하면 굳이 강제 형변환을 하지 않아도 된다!!