01. 업캐스팅과 instanceof 연산자
02. 메소드 오버라이딩
03. 추상 클래스
04. 인터페이스
# 객체의 타입 변환 : 업캐스팅
º 업캐스팅 (upcasting)
- 프로그램에서 이루어지는 자동 타입 변환
- 서브 클래스의 레퍼런스 값을 슈퍼 클래스의 레퍼런스에 대입
→ 슈퍼 클래스의 레퍼런스가 서브 클래스 객체를 가리키게 되는 현상
→ 슈퍼 클래스의 레퍼런스는 서브 클래스 객체 내에 있는 모든 멤버들을 접근할 수 없고, 슈퍼 클래스에서 정의된 멤버들만 접근 가능
# 업캐스팅 사례
class Persom {
String name;
String id;
public Person(String name) {
this.name = name;
}
}
class Student extends Person {
String grade;
String department;
public Student(String name) {
super(name);
}
}
public class UpcastingEx {
public static void main(String[] args) {
Person p;
Student s = new Student("김성철");
p = s; // 업캐스팅 발생
System.out.println(p.name); // 오류 없음
p.grade = 'A'; // 컴파일 오류
p.department = "CSE"; // 컴파일 오류
- 레퍼런스 p를 이용하면 Student 객체의 속성 중에서 오직 Person에서 정의된 속성들만 접근할 수 있다.
# 객체의 타입 변환 : 다운캐스팅
º 다운캐스팅(downcasting)
- 슈퍼 클래스 레퍼런스를 서브 클래스 레퍼런스에 대입하는 것
- 업캐스팅 된 것을 다시 원래대로 되돌리는 것
- 다운캐스팅 할 타입을 명시적으로 지정해야 함
# 다운캐스팅 사례
public class UpcastingEx {
public staitc void main(String[] args) {
Person p;
Student s = new Student("김성철");
p = s; // 업캐스팅
System.out.println(p.name);
Student s2 = (Student) p; // 다운캐스팅
s2.grade = "A";
s2.department = "CSE";
System.out.println(s2.name);
}
}
# instanceof 연산자와 객체 구별
º 업캐스팅 된 레퍼런스로 객체의 원래 타입을 구분하기 어려움
- 하나의 슈퍼 클래스는 여러 서브 클래스에 상속될 수 있기 때문 !
º instanceof 연산자
- instanceof를 이용하여 레퍼런스가 가리키는 객체의 원래 타입을 식별함
- 사용법 :
객체 레퍼런스 instanceof 클래스 타입 --> true/false의 불린 값
# 메소드 오버라이딩(Method Overriding)
- 슈퍼 클래스의 메소드를 서브 클래스에서 재정의하는 것
→ 슈퍼 클래스의 메소드를 이름, 메소드 인자 타입 및 개수, 리턴 타입 등 모든 것을 동일하게 정의한다.
(이 중에서 하나라도 다르면 메소드 오버라이딩이 실패한 것임)
- 슈퍼 클래스의 "메소드 무시하기"로 번역되기도 함
- 동적 바인딩 발생
→ 오버라이딩 된 메소드가 무조건 실행되도록 동적 바인딩이 된다.
- 슈퍼 클래스의 메소드를 무시하고 서브 클래스에서 새로 작성된 메소드가 실행된다.
# 메소드 오버라이딩 만들기
public class DObject { // 슈퍼 클래스
public DObject next;
public DObject() {next = nu11;}
public void draw() {
System.out.println("DObject draw");
}
}
public class Line extends DObject {
public void draw() { // method overriding
System.out.println("Line");
}
}
public class Rect extends DObject {
public void draw() { // method overriding
System.out.println("Rect");
}
}
public class Circle extends DObject {
public void draw() { // method overriding
System.out.println("Circle");
}
}
public class MethodOverridingDemo {
public static void main(String[] args) {
DObject obj = new DObject();
Line line = new Line();
DObject p = new Line(); // 업캐스팅
DObject r = line;
obj.draw(); //DObject.draw()
line.draw(); //Line.draw()
p.draw(); //Line.draw()
r.draw(); //Line.draw()
DObject rect = new Rect();
DObject circle = new Circle();
rect.draw(); //Rect.draw()
circle.draw(); //Circle.draw()
}
}
- 실행 시간에 객체 속에 오버라이딩 한 메소드가 있으면 동적 바인딩 되어 그 메소드가 실행됨
# 메소드 오버라이딩 조건
(1) 반드시 슈퍼 클래스 메소드와 동일한 이름, 동일한 호출 인자, 반환 타입을 가져야 한다.
(2) 오버라이딩 된 메소드의 접근 지정자는 슈퍼 클래스의 메소드 접근 지정자보다 좁아질 수 없다.
public > protected > default > private 순으로 지정 범위가 좁아진다.
(3) 반환 타입만 달라도 오류
(4) static, private 또는 final 메소드는 오버라이딩 될 수 없다.
# super 키워드
- super는 서브 클래스에서 슈퍼 클래스의 멤버를 접근할 떄 사용되는 슈퍼 클래스 타입의 레퍼런스
- 상속 관계에 있는 서브 클래스에서만 사용됨
- 오버라이딩 된 슈퍼 클래스의 메소드 호출 시 사용
- 필드와 메소드 접근 모두 가능
# this vs super, this() vs super() 사용
º this 레퍼런스 vs super 레퍼런스
레퍼런스 | this | super |
사용 | 현재 객체의 모든 멤버에 접근 | - 현재 객체 내에 있는 슈퍼 클래스 멤버를 접근 - super로 메소드 호출 시 정적바인딩 실행 |
사용법 | this.객체 내의 멤버 | super.객체 내의 슈퍼클래스의 멤버 |
º this() vs super()
메소드 | this() | super() |
사용 | 생성자에서 다른 생성자를 호출할 때 사용 |
서브 클래스의 생성자에서 슈퍼 클래스의 생성자를 호출할 떄 사용 |
# 오버라이딩 vs 오버로딩
비교 요소 | 메소드 오버로딩 | 메소드 오버라이딩 |
정의 | 같은 클래스나 상속 관계에서 동일한 이름의 메소드 중복 작성 |
서브 클래스에서 슈퍼 클래스에 있는 메소드와 동일한 이름의 메소드 재작성 |
관계 | 동일한 클래스 내 혹은 상속 관계 | 상속 관계 |
목적 | 이름이 같은 여러 개의 메소드를 중복 정의하여 사용의 편리성 향상 | 슈퍼 클래스에 구현된 메소드를 무시하고 서브 클래스에서 새로운 기능의 메소드를 재정의하고자 함 |
조건 | 메소드 이름은 반드시 동일함. 메소드의 인자의 개수나 인자의 타입이 달라야 성립 |
메소드의 이름, 인자의 타입, 인자의 개수, 인자의 리턴 타입 등이 모두 동일하여야 성립 |
바인딩 | 정적 바인딩. 컴파일 시에 중복된 메소드 중 호출되는 메소드 결정 |
동적 바인딩. 실행 시간에 오버라이딩 된 메소드 찾아 호출 |
# 추상 메소드와 추상 클래스
º 추상 메소드 (abstract method)
- 선언되어 있으나 구현되어 있지 않은 메소드
- 정의 : 접근 지정자 abstract 반환형 메소드 이름();
→ 추상 메소드는 서브 클래스에서 오버라이딩하여 구현한다.
º 추상 클래스 (abstract class)
- 추상 메소드를 하나라도 가지고 있으면 추상 클래스이다.
→ 클래스 앞에 반드시 abstract 라고 선언해야 한다.
- 추상 메소드를 가지고 있지는 않지만 클래스 앞에 abstract 로 선언한 경우
# 추상 클래스의 특성
º 추상 클래스의 객체는 생성할 수 없다.
º 추상 클래스의 필요성
- 계층적 상속 관계를 갖는 클래스 구조를 만들 때
- 설계와 구현 분리
→ 슈퍼 클래스에서는 개념적 특징을 정의하고, 서브 클래스에서 구체적 행위를 구현한다.
º 추상 클래스의 상속
- 추상 클래스를 상속받은 서브 클래스가 추상 메소드를 또 구현하지 않으면 서브 클래스도 추상 클래스가 된다.
→ abstract로 정의하여야 한다.
- 서브 클래스에서 추상 메소드를 구현하면 서브 클래스는 추상 클래스가 되지 않는다.
# 자바의 인터페이스 (interface)
º 인터페이스
- 모든 메소드가 추상 메소드인 "클래스"
- 인터페이스는 상수와 메소드만 갖는다.
º 인터페이스 정의
- interface 키워드로 정의된 클래스
ex) public interface SerialDriver { ... }
º 인터페이스의 특징
- 모든 메소드 : public abstract (생략 가능)
- 모든 상수 : public static final (생략 가능)
- 객체를 생성할 수 없음 → 생성자를 가질 수 없음.
- 레퍼런스 변수 타입으로 사용 가능
# 자바 인터페이스의 특징
º 멤버는 추상 메소드와 상수만으로 구성
- 필드는 가지지 않음
- 메소드는 모두 추상메소드이며, 메소드 선언 시 abstract 키워드 생략 가능
º 모든 메소드는 public 접근 지정자이며 생략 가능
º 상수도 public static final을 생략하여 선언 가능
- int ONEDAY = 24;
º 인터페이스의 객체를 생성할 수 없음(추상 메소드만 가질 수 있음)
º 다른 인터페이스에 상속될 수 있음
- 인터페이스는 다른 인터페이스를 상속할 수 있음
º 인터페이스도 레퍼런스 변수의 타입으로 사용가능
- Clock clock; // 인터페이스 Clock의 레퍼런스 변수 clock
- Car car; // 인터페이스 Car의 레퍼런스 변수 car
# 인터페이스의 필요성
º 인터페이스를 이용하여 다중 상속 구현
- 클래스는 다중 상속 불가
º 인터페이스는 명세서와 같음
- 구현은 블랙 박스와 같아 인터페이스의 사용자는 구현에 대해 알 필요 없음
º 인터페이스만 정의하고 구현을 분리하여, 작업자가 다양한 구현을 할 수 있음
# 인터페이스 상속
- 인터페이스 간에도 상속이 가능하다.
→ 인터페이스를 상속하여 확장된 인터페이스를 작성할 수 있다.
- 다중 상속을 허용한다.
# 인터페이스 구현
- implements 키워드를 사용한다.
- 여러 개의 인터페이스를 동시에 구현할 수 있다.
- 상속과 구현이 동시에 가능하다.
# 추상 클래스와 인터페이스 비교
º 추상 클래스
- 일반 메소드도 포함 가능
- 상수, 변수 필드 포함 가능
- 모든 서브 클래스에 공통된 메소드가 있는 경우, 추상 클래스가 적합
º 인터페이스
- 모든 메소드가 추상 메소드
- 상수 필드만 포함 가능
- 다중 상속 지원
# 요약
- 자바에서 상속은 부모 클래스의 필드와 메소드를 자식 클래스에게 물려주는 것으로 부모 클래스를 슈퍼 클래스, 자식 클래스를 서브 클래스라고 함.
- 자바는 클래스의 다중 상속을 지원하지 않음
- 자바에서 상속의 선언은 extends 키워드를 사용함
- 서브 클래스의 객체에는 슈퍼 클래스의 필드와 메소드가 포함되어 있으나 슈퍼 클래스의 private 멤버는 서브 클래스에서 접근할 수 없음. 슈퍼 클래스의 protected 멤버는 패키지 소속과 상관없이 서브 클래스에서 접근이 가능하며 동일한 패키지 내의 클래스에서도 접근이 가능
- 서브 클래스의 인스턴스가 생성되면 항상 서브 클래스의 생성자 한 개와 슈퍼 클래스의 생성자 한 개가 실행됨
- 서브 클래스 객체는 슈퍼 클래스 타입으로 자동 타입 변환이 가능하며 이를 업캐스팅(upcasting)이라고 하며, 다시 원래의 타입으로 강제 타입 변환하는 것을 다운캐스팅(downcasting)이라고 함.
- instanceof 연산자는 결과 값이 boolean 타입이며 객체가 어떤 클래스 타입인지 판별할 수 있음
- 슈퍼 클래스에 정의된 메소드를 서브 클래스에서 재정의하는 것을 메소드 오버라이딩(overriding)이라고 함
- 서브 클래스에서 슈퍼 클래스의 메소드를 오버라이딩하게 되면 서브 클래스의 인스턴스는 동일한 이름의 메소드를 두 개 가지게 됨. 이 때 오버라이딩된 서브 클래스의 메소드가 항상 실행됨.
- 호출된 메소드를 실행 시간에 찾아서 실행하는 것을 동적 바인딩이라고 부르며 오버라이딩 된 메소드는 동적 바인딩 방식으로 호출되고 실행됨.
- 추상 메소드(abstract method)는 메소드의 프로토타입만 있고 실행 코드를 작성하지 않은 미완성의 메소드임. 추상 메소드를 정의하려면 메소드 이름 앞에 abstract라고 선언하여야 함.
- 추상 클래스(abstract class)는 abstract 키워드로 선언된 클래스이며 한 개 이상의 추상 메소드(abstract)를 포함하는 경우 반드시 추상 클래스로 선언하여야 함.
- 추상 메소드를 하나도 가지고 있지 않은 경우라도 추상 클래스로 선언하는 것이 가능
- 추상 클래스의 객체 혹은 인스턴스는 생성될 수 없음
- 인터페이스(Interface)는 일종의 추상 클래스로서 변수 멤버를 가지지 못함
- 인터페이스를 정의하기 위해 interface라는 키워드를 사용함
- 클래스가 인터페이스를 구현할 때 implements 키워드를 사용함. 그리고 인터페이스에 정의된 모든 메소드를 구현하여야 함.
'JAVA > 자바 이론' 카테고리의 다른 글
Java | 7-1 제네릭과 컬렉션 (0) | 2021.06.10 |
---|---|
Java | 6 패키지 (0) | 2021.06.06 |
Java | 5-1 상속과 다형성 (0) | 2021.05.25 |
Java | 4-3 클래스와 객체 (0) | 2021.04.15 |
Java | 4-2 클래스와 객체 (0) | 2021.04.14 |