[ 클래스의 관계 ]
1. Has-A 관계(포함 관계)
=> A has a B = A 가 B 를 가지고 있다 = B가 A에 포함되어 있다.
=> 일반적인 클래스의 관계이며, 특정 클래스 내에
다른 클래스를 포함시켜 사용하는 관계
ex) class A {
B b = new B();
}
2. Is-A 관계(상속 관계)
=> A is a B = A 는 B 이다 = A 는 B 를 상속받은 관계이다. (자신 포함)
=> 초등학생은 학생이다 = 초등학생 is a 학생(O)
컴퓨터는 기계장치이다 = 컴퓨터 is a 머신(O)
학생은 학생이다 = 학생 is a 학생(O)
=> 스파이더맨은 사람이다(O)
사람은 스파이더맨이다(X)
ex) class A extends B {}
[ instanceof 연산자 ]
- 좌변의 객체(참조변수)가 우변의 클래스 타입(상속관계)인지 판별하는 연산자
- 주로 if문에 결합하여 판별하는데 사용되며
판별 결과가 true 이면 형변환이 가능한 관계(업캐스팅 또는 다운캐스팅)
판별 결과가 false 이면 절대로 형변환 불가능
< 기본 문법 >
if(A instanceof B) {}
=> A는 참조변수(인스턴스), B는 클래스명
public class Ex {
public static void main(String[] args) {
SmartPhone sp = new SmartPhone();
// 참조변수 sp 로 접근 가능한 SmartPhone 객체의 메서드 : 3개
sp.call();
sp.sms();
sp.kakaoTalk();
if (sp instanceof SmartPhone) {
System.out.println("sp is a smartphone");
}
System.out.println("=========================");
if (sp instanceof HandPhone) {
System.out.println("sp is a HandPhone");
HandPhone hp = sp;
hp.call();
hp.sms();
}
else {
System.out.println("sp is not a HandPhone");
}
System.out.println("=========================");
HandPhone hp = new HandPhone();
hp.call();
hp.sms();
if (hp instanceof HandPhone) {
System.out.println("hp is a HandPhone");
HandPhone handPhone = hp;
}
System.out.println("=========================");
if (hp instanceof SmartPhone) {
System.out.println("hp is a SmartPhone");
}
else {
System.out.println("hp is not a SmartPhone");
// SmartPhone sp2 = (SmartPhone)hp;
}
HandPhone hp2 = new SmartPhone();
hp2.call();
hp2.sms();
if (hp2 instanceof HandPhone) {
System.out.println("hp2 is HandPhone");
}
if (hp2 instanceof SmartPhone) {
System.out.println("hp2 is SmartPhone");
SmartPhone sp2 = (SmartPhone) hp2;
sp2.sms();
sp2.kakaoTalk();
}
else {
System.out.println("hp2 is not a SmartPhone");
}
System.out.println("==========================");
Child c = new Child();
// Parent p = c;
// p.parentPrn();
if (c instanceof Parent) {
System.out.println("c is a Parent");
Parent p = c;
p.parentPrn();
}
Parent p2 = new Parent();
if (p2 instanceof Child) {
System.out.println("p2 is a Child");
} else {
System.out.println("p2 is not a Child");
}
}
}
// HandPhone 과 Battery 의 관계는 has-a 관계이다.
class Battery {}
class HandPhone {
Battery better = new Battery();
public void call() {
System.out.println("전화!");
}
public void sms() {
System.out.println("문자!");
}
}
// HandPhone 과 SmartPhone 의 관계는 상속관계이다.
class SmartPhone extends HandPhone {
public void kakaoTalk() {
System.out.println("카톡!");
}
}
class Parent {
public void parentPrn() {
System.out.println("parentPrn");
}
}
class Child extends Parent {
public void childPrn() {
System.out.println("childPrn");
}
}
상속관계의 오버라이딩
- 슈퍼클래스의 메서드를 서브클래스에서 오버라이딩 하는 경우
슈퍼클래스의 메서드는 은닉됨
동적 바인딩 (Dynamic Binding)
- 상속 관계에서 업캐스팅 후 상속된 메서드를 호출하여 실행할 때
컴파일(번역) 시점에서의 실행 대상과 실제 실행 단계에서의 실행 대상이 달라지는 것(동적으로 변하는 것)
- 참조 변수의 데이터타입과 무관하게 실제 인스턴스에 따라 실행되는 메서드가 달라짐
public class Ex2 {
public static void main(String[] args) {
Parent2 p = new Parent2();
p.parentPrn();
p = new Child2(); // 업캐스팅
// 참조변수 p 는 Parent2 클래스 타입의 변수이지만
// 저장된 인스턴스 주소는 Child2 클래스 타입의 인스턴스이다.
// 따라서, 참조변수 p 를 통해 접근하는 실제 인스턴스는 Child2 이므로
// p.parentPrn() 메서드를 호출하면 실행되는 메서드도 Child2 의 메서드이다!
p.parentPrn();
}
}
class Parent2 {
public void parentPrn() {
System.out.println("슈퍼클래스의 parentPrn()");
}
}
class Child2 extends Parent2 {
public void childPrn() {
System.out.println("서브클래스의 childPrn()");
}
@Override
public void parentPrn() {
System.out.println("서브클래스에서 오버라이딩 된 parentPrn()");
}
}
다형성(Polymorphism)
- 하나의 참조변수로 여러 인스턴스를 참조하는 것
= 인스턴스를 다양한 형태로 변환하는 것
= 인스턴스를 업캐스팅하여 슈퍼클래스 타입으로 서브클래스의 멤버 접근
public class Ex3 {
public static void main(String[] args) {
Circle c = new Circle();
c.circleDraw();
Rectangle r = new Rectangle();
r.paint();
Triangle t = new Triangle();
t.design();
System.out.println("===================");
c.draw();
r.draw();
t.draw();
System.out.println("===================");
Shape s;
s = c;
s.draw();
s = r;
s.draw();
s = t;
s.draw();
}
}
class Shape { // 도형 클래스
// 공통적으로 도형을 그릴 수 있는 draw() 메서드 정의
public void draw() {
System.out.println("도형 그리기!");
}
}
class Circle extends Shape {
public void circleDraw() {
System.out.println("원 그리기!");
}
@Override
public void draw() {
System.out.println("원 그리기!");
}
}
class Rectangle extends Shape {
public void paint() {
System.out.println("사각형 그리기!");
}
@Override
public void draw() {
System.out.println("사각형 그리기!");
}
}
class Triangle extends Shape {
public void design() {
System.out.println("삼각형 그리기!");
}
@Override
public void draw() {
System.out.println("삼각형 그리기!");
}
}
Output :
원 그리기!
사각형 그리기!
삼각형 그리기!
===================
원 그리기!
사각형 그리기!
삼각형 그리기!
===================
원 그리기!
사각형 그리기!
삼각형 그리기!
ex) 다형성은 아래와 같이 메소드의 파라미터를 통해서도 활용할 수 있다.
: 파라미터로 Circle, Rectangle, Triangle 인스턴스 전달 -> Shape 타입으로 업캐스팅됨
public class Ex3 {
public static void main(String[] args) {
drawShape(new Circle());
// drawShape(new Rectangle());
polymorphismDrawShape(new Circle());
polymorphismDrawShape(new Rectangle());
polymorphismDrawShape(new Triangle());
}
public static void drawShape(Circle c) {
c.draw();
}
public static void polymorphismDrawShape(Shape s) {
s.draw();
}
}
class Shape { // 도형 클래스
// 공통적으로 도형을 그릴 수 있는 draw() 메서드 정의
public void draw() {
System.out.println("도형 그리기!");
}
}
class Circle extends Shape {
@Override
public void draw() {
System.out.println("원 그리기!");
}
}
(...)
ex) 다형성을 배열에 활용하는 경우 (업캐스팅)
Circle[] cArr = new Circle[3];
cArr[0] = new Circle();
// cArr[1] = new Rectangle();
Shape[] sArr = new Shape[3];
sArr[0] = new Circle();
sArr[1] = new Rectangle();
sArr[2] = new Triangle();
for (Shape shape : sArr) {
shape.draw();
}
'Study > Java' 카테고리의 다른 글
[JAVA] 추상(abstract) (0) | 2021.03.09 |
---|---|
[JAVA] final 키워드 / 상수(constant) (0) | 2021.03.09 |
JAVA - getter, setter (0) | 2021.02.09 |
JAVA - 파일 내 특정 문자열이 포함된 행을 제거 (0) | 2021.02.04 |
JAVA에서의 데이터 타입 (0) | 2021.01.11 |