◆ 다형성 : 여러 가지 형태를 가질 수 있는 능력을 의미한다. 자바에서는 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 함으로써 다형성을 프로그램적으로 구현함
Tv t = new Tv();
CaptionTv c = new CaptionTv();
인스턴스의 타입과 일치하는 타입의 참조변수
조상 클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조하도록 하는 것도 가능
Tv t = new CaptionTv();
◈ Tv 타입의 참조변수로는 CaptionTv인스턴스 중에서 Tv클래스의 멤버들만 사용할 수 있다.
◈ 같은 타입의 인스턴스지만 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다.
CaptionTv c = new Tv();
if Caption이 Tv를 상속을 받고 있을 떄에 컴파일 에러가 발생 실제 인스턴스인 Tv의 멤버 개수보다 참조변수 c가 사용할 수 있는 멤버 개수가 더 많기 때문이다.
▼
자손타입의 참조변수로 조상타입의 인스턴스를 참조하는 것은 존재하지 않는 멤버를 사용하고자 할 가능성이 있으므로 허용하지 않는 것이다. 참조변수가 사용할 수 있는 멤버 개수는 인스턴스의 멤버 개수보다 같거나 적어야 한다.
자손타입 -> 조상타입 : 형변환 생략가능
자손타입 <- 조상타입: 형변환 생략불가
▼
형변환은 참조변수의 타입을 변환하는 것이지 인스턴스를 변환하는 것은 아니기 때문에 참조변수의 형변환은 인스턴스에 아무런 영향을 미치지 않는다.
class Car {
String color;
int door;
void drive(){
System.out.println("drive,Brrrr~");
}
void stop(){
System.out.println("stop!!");
}
}
class FireEngine extends Car{
void water(){
System.out.println("water!!!");
}
}
class CastingTest1{
public static void main(String args[]){
Car car = null;
FireEngine fe = new FireEngine();
FireEngine fe2 = null;
fe.water();
car = fe;
//car.water(); 컴파일 에러 car 타입으로는 못 부름
fe2 = (FireEngine)car;// 자손타입 <- 조상타입
fe2.water();
}
}
서로 상속관계에 있는 타입간의 형변환은 양방향으로 자유롭게 수행은 가능하지만, 참조변수가 가리키는 인스턴스의 자손타입으로 형변환은 허용되지 않는다.
그래서 참조변수가 가리키는 인스턴스의 타입이 무엇인지 확인하는 것이 중요하다.
Instanceof 연산자
(참조변수) instanceof 타입 / 클래스명
▼
참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof 연산자를 사용한다.
코드 예시
class InstanceofTest{
public static void main(String args[]){
FireEngine fe = new FireEngine();
if(fe instanceof FireEngine){
System.out.println("This is a FireEngine instance");
}
if(fe instanceof Car{
System.out.println("this is a Car instance");
}
System.out.println("이름 출력" + fe.getClass().getName());
}
}
출력 결과
This is a FireEngine instance.
This is a Car instance.
FireEngine
▼
어떤 타입에 대한 instanceof 연산의 결과가 true라는 것은 검사한 타입으로 형변환이 가능하다는 것이다.
class BindingTest3{
public static void main(String args[]){
Parent P = new Child();
Child C = new Child();
System.out.println("p.x="+ p.x);
p.method();
System.our.println();
System.our.println("c.x="+c.x);
c.method();
}
}
class Parent{
int x =100;
void method(){
System.our.println("Parent 함수");
}
}
class Child extends Parent{
int x =200;
void method(){
System.out.println("x=" + x);
System.out.println("super.x=" + super.x);
System.out.println("this.x+" + this.x);
}
}
실행 결과
p.x =100
x=200
super.x =100
this.x =200
c.x=200
x=200
super.x=100
this.x=200
▼
자손 클래스 child에 선언된 인스턴스변수 x와 조상 클래스 Parent로 부터 상속받은 인스턴스변수 x를 구분하는데 참조변수 super와 this가 사용된다.
child클래스에서 super.x는 조상 클래스의 parent에 선언된 인스턴스변수를 x를 뜻하면 this.x또는 x는 child클래스의 인스턴스변수 x 뜻함
spuer, this 예제
class Product{
int price;
int bounusPoint
Porduct(int price){
this.price = price;
bonusPoint = (int)(price/10.0);
}
}
class Tv extends Product{
Tv() {super(100);}
public String toString(){
return "TV";
}
}
class Computer extends Product{
Computer() {super(200);}
public String toString(){
return "Computer";
}
}
class Audio extends Product{
Audio() {super(50);}
public String toString(){
return "Audio";
}
}
class Buyer{
int money = 1000;
int bonusPoint =0;
Product[] item = new Product[10];
int i=0;
void buy(Product p){
if(money < p.price){
System.out.println("잔액이 부족해서 물건을 살 수 없습니다.");
return;
}
money -= p.price;
bonusPoint += p.bonusPoint;
item[p++] =p;
System.out.println(p+"을 구입하셨습니다.");
}
void summary(){
int sum =0;
String itemList = "";
for(int i =0; i < item.length;i++){
if(item[i] ==null){break;}
sum+=item[i].price;
itemList += item[i] + ", ";
}
System.out.println("구입하신 물품의 총금액은 " + sum + "만원입니다.");
System.out.println("구입하신 제품은 " + itemList + "입니다.");
}
}
class PolyArgumentTest2{
public static void main(String args[]){
Buyer b = new Buyer();
b.buy(new Tv());
b.buy(new Computer());
b.buy(new Audio());
b.summary();
}
}
추상 클래스
▼
미완성 설계도로 완성된 제품을 만들 수 없듯 추상클래스는 상속을 통해서 자손클래스에 의해서만 완성가능
abstract class (클래스명){
//......
}
abstract class Player{
abstract void play(int pos);
abstract void stop();
}
class AudioPlayer extends Player{
void play(int pos){} //추상메서드를 구현해야함 아래도 같음
void sotp(){}
}
abstract class AbstractPlayer extends Player{
void play(int pos){} // 추상 메서드 구현
}
인터페이스
▼
인터페이스는 일종의 추상클래스이다. 인터페이스는 추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 못가진다.
interface 인터페이스 이름{
public static final 타입 상수이름 = 값;
public static abstract 메서드이름(매개변수목록);
}
class FighterTest{
public static void main(String[] args){
Fighter f = new Fighter();
if(f instanceof Unit){
System.out.println("f는 Unit클래스의 자손입니다.");
}
if(f instanceof Fightable){
System.out.println("f는 Fightable의 인터페이스를 구현");
}
if(f instanceof Movable){
System.out.println("f는 Movable인터페이스를 구현했습니다.");
}
if(f instanceof Attackable){
System.out.println("f는 Attackable을 구현했습니다.");
}
}
}
class Fighter extends Unit implements Fightable{
public void move(int x, int y){};//인터페이스 상속 후 구현가능
public void attack(Unit u){}
}
class Unit{
int currentHp;
int x, y;
}
interface Fightable extends Movable,Attackable{}
interface Movable{void move(int x, int y);}
interface Attackable {void attack(Unit u};//인터페이스
인터페이스의 장점
-개발시간을 단축시킨다
-표준화가 가능하다.
-서로 관계없는 클래스들에게 관계 맺기 가능
-독립적인 프로그래밍이 가능