메소드 오버라이딩(Method Overriding, 메소드 재정의)
하위 클래스에서 상속받은 상위 클래스에 정의된 메소드를 다시 정의하는 것으로(재정의), 객체 지향 프로그래밍의 특징인 다향성을 나타낸다. 재정의(Overriding)는 반드시 상속 관계에 있어야 하며, 메소드의 이름, 리턴 타입, 매개변수의 갯수나 타입이 완전히 일치해야 한다.
- 상위 클래스의 메소드를 오버라이딩하면 기존의 메소드를 아예 ★덮어쓰기 한다는 것에 주의해야한다.
- 따라서 오버라이딩하면 어떤 방법으로 호출해도 이전의 메소드를 호출할 수 없다. 『super.메소드()』 이런거 안 통함
vs 메소드 오버로딩(Metho Overloading, 메소드 중복정의) - 자바 13 (2020.08.20)
오버로딩은 메소드의 이름을 같게하여 중복정의하는 것으로, 메소드의 매개변수(인자,인수,파라미터)의 자료형 또는 매개변수의 갯수를 다르게 하면 메소드의 이름이 같더라도 호출할 때 구분해서 호출할 수 있다. 반환형의 일치 여부는 오버로딩과 관련이 없다.
- 오버로딩은 상속과 관련이 없다. 반면에 오버라이딩은 반드시 상속 관계여야 재정의 가능하다.
※ 어노테이션(annotation)
- 메타데이터로써 사용되며 JDK 1.5 부터 지원하는 기능이다. 여러 종류가 있지만 일단 『@Override』 어노테이션만 짚고 넘어간다.
* 메타데이터(metadata) : 실행에 영향력은 없고 설명하는 용도의 코드
- 어노테이션을 붙이므로써 상속받은 메소드와 이름이 겹친 것이 실수가 아니라 의도적임을 알릴 수 있다.
- 주석과 어노테이션의 차이
주석은 컴파일 과정에서 제거되지만 어노테이션(annotation)은 컴파일해도 사라지지 않으며 문법적으로 자바에게 노출된다. (자바도 알 수 있는 일종의 주석)
@Override // 오버라이딩 어노테이션
public void write()
{
System.out.println("w : "+ w + ", h : " + h);
System.out.println("사각형 - " + area);
}
메소드 오버라이딩(Method Overriding)의 특징
- 메소드 이름, 리턴타입, 파라미터 수나 타입이 완전히 일치해야 한다.
- 반드시 상속 관계가 있어야 한다.
- 재정의된 하위 클래스의 메소드 접근제어지시자는 상위 클래스의 메소드 접근제어지시자보다 범위가 크거나 같아야 한다.
예를 들어, 상위 클래스 메소드의 접근제어지시자가 『protected』인 경우 하위 클래스가 이 메소드를 오버라이딩(Overriding)하는 경우 접근제어지시자는 『protected』 또는 『public』 이어야 한다.
- 『static』, 『final』, 『private』 메소드는 오버라이딩(Overriding)할 수 없다.
- Exception(예외)의 추가가 불가능하다. 즉, 상위 클래스의 메소드가 가지고 있는 기존 예외 사항에 새로운 Exception 을 추가하는 것은 불가능하다. (메소드를 상속받아서 썼으면 그 의미에 맞게 써야지, 의미가 변질될 정도로 변경해서 쓰지 않도록 해야 한다.)
※ final 키워드
- final 변수 : 변수의 상수화. 변수였지만 변할 수 없는 수가 된다. (C언어의 const 역할)
- final 메소드 : 최종적으로 정의된 메소드. 더이상의 변경은 불가능. 따라서 상위 클래스의 final 메소드는 오버라이딩 할 수 없다.
메소드 오버라이딩 예제
/*=================================
■■■ 클래스 고급 ■■■
- 상속(Inheritance)
=================================*/
class SuperTest119 // 부모 클래스
{
private int a = 5;
protected int b = 10;
public int c = 20;
public void write()
{
System.out.println("Super write() 메소드 : " + a + " : " + b + " : " + c);
}
}
class SubTest119 extends SuperTest119 // 자식 클래스
{
protected int b = 100;
public void print()
{
//System.out.println("Sub print() 메소드 : " + a + " : " + b + " : " + c);
//-- 에러 발생(컴파일 에러), 슈퍼클래스에서 선언된 변수 a 에는 접근할 수 없다.
// → private 변수이기 때문에...
System.out.println("Sub print() 메소드 : " + b + " : " + c);
System.out.println("Sub print() 메소드 : " + b);
System.out.println("Sub print() 메소드 : " + this.b);
System.out.println("Sub print() 메소드 : " + super.b);
//-- 변수 b 는 접근 방법에 따라
// 다른 b 로 접근 및 출력이 이루어진다.
// 슈퍼클래스에서 선언된 b, 서브클래스에서 선언된 b
//System.out.println("Sub print() 메소드 : " + c);
//System.out.println("Sub print() 메소드 : " + this.c);
//System.out.println("Sub print() 메소드 : " + super.c);
//-- 변수 c 는 접근하는데 아무런 제약과 제한이 없다.
// 슈퍼클래스에서 선언된 public c
}
@Override
public void write()
{
//System.out.println("Sub write() 메소드 : " + a + " : " + b + " : " + c);
//-- 에러 발생(컴파일 에러), 슈퍼클래스에서 선언된 변수 a 에는 접근할 수 없다.
// → private 변수이기 때문에...
System.out.println("Sub write() 메소드 : " + b + " : " + c);
}
}
// main() 메소드를 포함하고 있는 외부의 다른 클래스(동일 패키지)
public class Test119
{
public static void main(String[] args)
{
// 하위 클래스(SubTest119) 인스턴스 생성
SubTest119 ob = new SubTest119();
ob.print();
//--==>> Sub print() 메소드 : 100 : 20
ob.write();
//--==>> Sub write() 메소드 : 100 : 20
// write() 메소드를 Override 하지 않았다면 아래와 같이 출력됐을 것이다.
// Super write() 메소드 : 5 : 10 : 20
System.out.println("---------------------------------------------------- 구분선");
System.out.println(ob.b);
//--==>> 100
// ob 를 통해 부모 클래스의 변수 b 에 접근해보기
//System.out.println(ob.super.b); //-- (Ⅹ) 잘못된 접근 방법
System.out.println(((SuperTest119)ob).b); //-- (○)
//--==>> 10
// ※ 형변환을 통해 슈퍼 부름
// ob 를 통해 부모 클래스의 write() 메소드에 접근해보기
((SuperTest119)ob).write();
//--==>> Sub write() 메소드 : 100 : 20
// 형변환을 하여 접근했지만 부모 클래스의 write() 메소드에 접근하지 못했다.
// → 메소드 오버라이딩을 통해 슈퍼클래스의 write()를 완전히 덮어씌웠으므로
// 원래 슈퍼클래스의 write()는 호출할 수 없다.
// ※ 상속관계의 메소드와 변수를 꼭! 구분하여 정리할 것~~!!!
}
}
추상클래스(Abstarct)
교재 375p 참고
추상 메소드(abstract method) - 미완성 메소드
- 선언만 있고 정의가 없는 메소드.
[접근제어지시자] abstract 자료형 메소드명([매개변수], ...); // 정의하지 않기 때문에 세미콜론(;)
추상클래스(abstract class) - 미완성 설계도
- 하나 이상의 메소드(또는 추상 메소드)를 갖는 클래스.
- 하위 클래스에서 오버라이딩(Overriding)할 것으로 예상되는 메소드에 대해 메모리 낭비 없이 미리 호출 계획을 세워두기 위해 만든다.
- 클래스가 적어도 하나 이상의 추상 메소드를 포함할 때 그 클래스는 class 앞에 『abstract』 키워드를 붙여 추상 클래스로 명시해야 하며, 추상 클래스로 선언한 경우에는 불완전한 형태의 클래스이므로 ★객체를 생성할 수 없다.
- 추상 메소드가 존재하지 않아도 abstract 키워드를 붙여 추상 클래스로 만들 수 있으며 이 마저도 객체를 생성할 수 없다.
[접근제어지시자] abstract class 클래스명
{
[접근제어지시자] abstract 자료형 메소드명([매개변수], ...);
}
추상 클래스의 특징
- 추상 클래스는 독립적으로 존재할 수 없으며 상속을 위해서만 존재한다.
- 추상 클래스에서 상속받은 하위 클래스에서는 반드시 추상 메소드를 오버라이딩(Overrideing)해야 한다.
- 하위 클래스가 상속받고 추상 메소드들을 구현(정의)하지 않는다면 그 하위 클래스 또한 추상 클래스이다. (일단 상속받으면 추상클래스인 상태로 시작 → 추상 메소드를 모두 구현하면 일반적인 클래스가 된다.)
※ 『abstract』 키워드는 클래스와 메소드에서만 사용할 수 있으며 멤버 변수나 로컬 변수등 변수에는 사용 불가능하다.
추상 클래스 예제 코드
/*=================================
■■■ 클래스 고급 ■■■
- 추상 클래스(Abstract)
=================================*/
// 추상 클래스
abstract class SortInt120
{
private int[] value;
protected void sort(int[] value)
{
this.value = value;
sorting();
}
// 추상 메소드
protected abstract void sorting();
protected int dataLength()
{
return value.length;
}
// 『final』 키워드로 인해, 이 클래스 SortInt120 을 상속받는 클래스에서
// 이 메소드를 재정의(오버라이딩, Method Overriding)할 수 없다.
protected final int compare(int i, int j)
{
int x = value[i];
int y = value[j];
if(x==y)
return 0;
else if(x>y)
return 1;
else
return -1;
}
// 『final』 키워드로 인해, 이 클래스 SortInt120 을 상속받는 클래스에서
// 이 메소드를 재정의(오버라이딩, Method Overriding)할 수 없다.
protected final void swap(int i, int j)
{
int temp = value[i];
value[i] = value[j];
value[j] = temp;
}
}
// SortInt120 클래스(추상 클래스)를 상속받은 클래스 → 일단 상속받을 때는 추상 클래스
// 하지만 추상 메소드 『sorting()』 을 Overriding 하면 일반 정상 클래스가 된다.
//public abstract class Test120 extends SortInt120
public class Test120 extends SortInt120 // 상속 후 abstract 메소드를 구현하면 정상화 됨
{
/* 상속 받은 속성, 기능
protected void sort(int[] value) { ... }
protected abstract void sorting(); // 추상 메소드
protected int dataLength() { ... }
protected final int compare(int i, int j) { ... }
protected final void swap(int i, int j) { ... }
*/
int i, j;
static int[] data = {7, 10, 3, 8, 7};
@Override
//protected abstract void sorting() // 원래 상속받은 추상 메소드
protected void sorting()
{
// 정의하므로써 일반 메소드로 완성
// selection sort(선택 정렬)
for(i=0; i<dataLength()-1; i++)
{
for (j=i+1; j<dataLength(); j++)
{
// 크기 비교 및 자리 바꿈
if (compare(i, j)>0)
swap(i, j);
}
}
}
public static void main(String[] args)
{
Test120 ob = new Test120();
System.out.print("Source Data : ");
for(int n : data)
System.out.print(n + " ");
System.out.println();
ob.sort(data);
System.out.print("Sorted Data : ");
for(int n : data)
System.out.print(n + " ");
System.out.println();
}
}
// 실행 결과
/*
Source Data : 7 10 3 8 7
Sorted Data : 3 7 7 8 10
계속하려면 아무 키나 누르십시오 . . .
*/
* 다음 수업(포스팅)에서 다루는 『인터페이스』는 추상클래스보다 더 추상적인 버전이라고 볼 수 있다. 인터페이스 내에는 모든 메소드가 추상 메소드로 이루어져 있다. 추상 클래스의 연장선??
* 인터페이스(모든 메소드가 추상적) - 추상클래스(일단 추상적) - 일반적인 클래스(구체적)
'자바 풀스택 과정 수업 정리 > 자바' 카테고리의 다른 글
자바 16-2 (2020.08.25) : 인터페이스 (0) | 2020.09.05 |
---|---|
자바 16-1 (2020.08.25) : 상속 관계의 형변환, 업캐스팅, 다운캐스팅, 인터페이스, 중첩클래스(중첩 내부클래스, 내부클래스, 로컬클래스, 익명클래스) (0) | 2020.09.04 |
자바 15-1 (2020.08.24) : 상속, super (0) | 2020.08.29 |
자바 14 (2020.08.21) : 정렬 알고리즘(선택, 버블, 삽입, 향상된 버블) (0) | 2020.08.28 |
자바 13 (2020.08.20) : 메소드 오버로딩, 만년 달력, 주민번호 유효성 검사 (0) | 2020.08.24 |
최근댓글