1. 마크 인터페이스(=마커 인터페이스)
: 공통된 클래스들을 하나로 묶어주는 기능(그룹화)
영역 안에는 비워놓는다.
2. 다중 상속
: jdk8버전부터는 다중 상속이 사실상 지원된다.
인터페이스에서 바디가 있는 메소드를 선언할 수 있기 때문이다.
** 인터페이스의 다중 지정을 통해 다중 상속이 된다고 보면 된다.
3. 다중 지정에서 발생하는 모호성 해결방법
1) 2개의 인터페이스에 같은 이름의 메소드가 있다면
지정받은 클래스에서 반드시 재정의하고 사용한다.
2) 부모 클래스와 부모 인터페이스에 같은 이름의 메소드가
있다면 부모 클래스에 있는 메소드가 사용된다.
4. 오늘 실습코드
1) 인터페이스 예제
** Soldier 인터페이스 **
package inter;
public interface Soldier {
final static int ARM = 2;
int LEG = 2;
abstract void work();
void eat();
void sleep();
void salute();
}
** 인터페이스 Soldier을 인터페이스 받은 SoldierAdapter 추상클래스**
package inter;
public abstract class SoldierAdapter implements Soldier{
@Override
public void work() {}
@Override
public void sleep() {}
@Override
public void eat() {}
@Override
public void salute() {}
}
** 인터페이스 Soldier을 인터페이스 받은 Private, Pfc, Corporal, Sergeant 클래스 **
package inter;
public class Private implements Soldier {
@Override
public void work() {
System.out.println("열심히 뛰지만 결과물이 없다. 그리고 어딜 간다.");
}
@Override
public void eat() {
System.out.println("허리를 90도로 펴고 직각 식사를 한다. 그리고 어디 간다.");
}
@Override
public void sleep() {
System.out.println("고향 생각에 잠이 잘 안온다. 울다가 어디 간다.");
}
@Override
public void salute() {
System.out.println("충!!!!!!!!!!!!!!!!!!!!!!!!!!!!!성!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
}
package inter;
public class Pfc implements Soldier{
@Override
public void work() {
System.out.println("어느 정도 결과물이 나온다. 후임들에게 알려준다.");
}
@Override
public void eat() {
System.out.println("후임들 식판과 선임들의 식판을 보며 식사한다.");
}
@Override
public void sleep() {
System.out.println("잘 잔다. 그러다 어디 간다.");
}
@Override
public void salute() {
System.out.println("충!성!");
}
}
package inter;
public class Corporal implements Soldier{
@Override
public void work() {
System.out.println("후임들에게 지시한다.");
}
@Override
public void eat() {
System.out.println("경치를 보며 식사한다.");
}
@Override
public void sleep() {
System.out.println("잘 잔다.");
}
@Override
public void salute() {
System.out.println("ㅊㅅ");
}
}
package inter;
public class Sergeant extends SoldierAdapter{
void cloak() {
System.out.println("숨기");
}
@Override
public void eat() {
System.out.println("PX로 달려간다.");
}
@Override
public void sleep() {
System.out.println("잘 잔다.");
}
}
** 메인메소드 Army 클래스 **
package inter;
public class Army {
public static void main(String[] args) {
//업캐스팅
Soldier s = new Corporal();
SoldierAdapter sa = new Sergeant();
s.eat();
sa.eat();
/*
Soldier soldier = new Soldier() {
@Override
public void work() {}
@Override
public void sleep() {}
@Override
public void salute() {}
@Override
public void eat() {}
};
//에러
//다운캐스팅은 기존에 업캐스팅된 것만 가능
//자식 클래스 타입으로 부모 생성자를 호출할 수 없음
//부모의 범위가 더 큼, 큰 범위가 작은 범위를 담을 수 없기 때문
// Corporal c = (Corporal)soldier;
*/
//다운캐스팅
//cloak()를 사용하려면 다운캐스팅 필요
Sergeant ser = (Sergeant) sa;
ser.cloak();
//Sergeant는 타입이 4개라는 것을 보여주는 예제
Sergeant 한동석 = new Sergeant();
System.out.println(한동석 instanceof Sergeant);
System.out.println(한동석 instanceof Object);
System.out.println(한동석 instanceof SoldierAdapter);
System.out.println(한동석 instanceof Soldier);
}
}
** 인터페이스 Soldier를 받게 되면 vork(), eat(), sleep(), salute() 4개의 메소드를 반드시 재정의 필요!!
[그러나] Sergeant 클래스는 eat(), sleep()만 필요!!
[그래서] 필요한 eat(), sleep()만 재정의 > 에러가 발생!!
[왜??] implements Soldier을 함으로써 반드시 재정의해야하는 메소드를 누락했기 때문
[에러에 대한 해결책] 중간에 SoldiorAdapter라는 추상클래스를 만든다!
[SoldiorAdapter라는 추상클래스를 만들게 되면?] 사용해도 되고 사용 안해도 되는 일반 메소드 이용
[이 추상클래스의 일반메소드를 이용하면] 필요한 메소드만 선언할 수 있게 됨
[실제로 사용해보기] 필요한 eat(), sleep()만 재정의만 했음 > 에러 발생 없이 생성 가능해짐!
** Sergeant는 4개의 타입이다
(모든 클래스의 조상 Object, 인터페이스 Soldier, Soldier을 implements한 추상클래스 SoldierAdapter, 그리고 본인)
2) upcasting, downcasting, 추상클래스, 인터페이스 사용 예제
package inter;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class Test extends Frame{
public Test() {
super("GUI 테스트");
setSize(500, 500);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int x = (d.width - getWidth()) / 2;
int y = (d.height - getHeight()) / 2;
setLocation(x, y);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setBackground(Color.ORANGE);
setVisible(true);
}
public static void main(String[] args) {
new Test();
}
}
2) instanceof 예제
** TV 메인메소드 클래스 **
package mark;
public class TV {
void checkAni(Video[] arVideos) {
for(int i = 0; i < arVideos.length; i++) {
if(arVideos[i] instanceof Animation) {
System.out.println(arVideos[i] + "애니메이션 입니다.");
} else {
System.out.println(arVideos[i] + "애니메이션이 아닙니다.");
}
}
}
public static void main(String[] args) {
TV tv = new TV();
//arVideos > 마커 인터페이스
//공통된 클래스들을 하나로 묶어주는 기능(그룹화)
Video[] arVideo = {
new Zzangu(),
new Dizimon(),
new Pokemon(),
new Avengers()
};
tv.checkAni(arVideo);
}
}
** Animation 인터페이스 **
[개발자들끼리 약속] {;} 일부러 비워뒀으니깐 건들면 안돼요란 뜻
package mark;
//마크 인터페이스(==마커 인터페이스)
//공통된 클래스들을 하나로 묶어주는 기능(그룹화)
//영역 안에는 비워놓는다.
public interface Animation {;}
** Video 클래스 **
package mark;
public class Video {
}
** Video를 상속 받고 Animation을 인터페이스 받은 Zzangu, Dizimon, Pokemon 클래스 **
> 마커 인터페이스, Animation을 이용하여 아래의 3개의 클래스들을 묶어줌 <
package mark;
public class Zzangu extends Video implements Animation {
}
package mark;
public class Dizimon extends Video implements Animation {
}
package mark;
public class Pokemon extends Video implements Animation {
}
** Video를 상속받은 Avengers 클래스 **
package mark;
public class Avengers extends Video {
}
3) toString() 재정의 예제
package mark;
public class Car {
String brand;
String color;
int price;
public Car() {}
public Car(String brand, String color, int price) {
super();
this.brand = brand;
this.color = color;
this.price = price;
}
@Override
public String toString() {
return brand + "," + color + "," + price;
}
public static void main(String[] args) {
Car myCar = new Car("페라리","빨강",30000);
System.out.println(myCar);
}
}
4) toString()을 재정의, 클래스 이름과 함께 출력될 수 있도록 기존 코드에서 변경하기
** TV 메인메소드 클래스**
package mark;
public class TV {
void checkAni(Video[] arVideos) {
for (int i = 0; i < arVideos.length; i++) {
if(arVideos[i] instanceof Animation) {
System.out.println(arVideos[i] + "애니메이션 입니다.");
}else {
System.out.println(arVideos[i] + "애니메이션이 아닙니다.");
}
}
}
@Override
public String toString() {
return "티비";
}
public static void main(String[] args) {
TV tv = new TV();
//arVideos -> 마크 인터페이스
//공통된 클래스들을 하나로 묶어주는 기능(그룹화)
Video[] arVideos = {
new Zzangu(),
new Dizimon(),
new Pokemon(),
new Avengers()
};
tv.checkAni(arVideos);
System.out.println();
System.out.println("객체명으로 syso를 이용해 화면 출력하면 "
+ "객체명.toString()으로 출력한 값과 일치");
System.out.println("즉, 객체명으로 출력할 때 toString이 생략되어 있음을 알기");
System.out.println(tv);
System.out.println(tv.toString());
}
}
** Animation 인터페이스 **
[개발자들끼리 약속] {;} 일부러 비워뒀으니깐 건들면 안돼요란 뜻
package mark;
//마크 인터페이스(==마커 인터페이스)
//공통된 클래스들을 하나로 묶어주는 기능(그룹화)
//영역 안에는 비워놓는다.
public interface Animation {;}
** Video 클래스**
package mark;
public class Video {
}
** Video를 상속 받고 Animation을 인터페이스 받은 Zzangu, Dizimon, Pokemon 클래스 **
> 마커 인터페이스, Animation을 이용하여 아래의 3개의 클래스들을 묶어줌 <
package mark;
public class Dizimon extends Video implements Animation{
@Override
public String toString() {
return "디지몬은";
}
}
package mark;
public class Pokemon extends Video implements Animation{
@Override
public String toString() {
return "포켓몬은";
}
}
package mark;
public class Zzangu extends Video implements Animation{
@Override
public String toString() {
return "짱구는";
}
}
** Video를 상속받은 Avengers 클래스**
package mark;
public class Avengers extends Video{
@Override
public String toString() {
return "어벤져스는";
}
}
[Tip] toString() 재정의하기 전 출력값
4) 다중상속 예제
** D를 상속받고 B를 인터페이스 받은 A 메인 메소드 클래스 **
package inter2;
//부모 클래스와 부모 인터페이스에 같은 이름의 메소드가 있다면
//부모 클래스에 있는 메소드가 출력된다
public class A extends D implements B{
public static void main(String[] args) {
new A().printData(10);
}
}
//printData()는 B와 C의 인터페이스 두 군데 모두 존재
//모호성 발생 > 이를 해결하기 위해 반드시 재정의를 해야 함
//이미 컴파일러상 재정의 하도록 설정되어 있음 > 재정의를 안하면 오류 발생!!
//public class A implements B, C{
// @Override
// public void printData(int data) {
// System.out.println("재정의 됨" + data);
//// B.super.printData(data);
// }
// public static void main(String[] args) {
// new A().printData(10);
// }
//}
** B 인터페이스 **
package inter2;
public interface B {
default void printData(int data) {
System.out.println(data);
}
}
** C 인터페이스 **
package inter2;
public interface C {
default void printData(int data) {
System.out.println(data);
}
}
** D 클래스 **
package inter2;
public class D {
public void printData(int data) {
System.out.println("부모클래스");
System.out.println(data);
}
}
** jdk8버전부터는 다중 상속이 사실상 지원
> 인터페이스에서 바디가 있는 메소드를 선언할 수 있기 때문
즉, 인터페이스의 다중 지정을 통해 다중 상속이 된다고 보면 된다
** 2개의 인터페이스에 같은 이름의 메소드가 있다면 반드시 재정의 해야 함
> 재정의를 하지 않는다면 오류 발생
** 2개의 인터페이스에 같은 이름의 메소드가 있다면 지정받은 클래스에서 반드시 재정의하고 사용
** 부모 클래스와 부모 인터페이스에 같은 이름의 메소드가 있다면 부모 클래스에 있는 메소드가 사용
'웹_프론트_백엔드 > 단과' 카테고리의 다른 글
[단과_JAVA] 2020.02.21 (0) | 2020.02.22 |
---|---|
[단과_C] 2020.02.20 (0) | 2020.02.21 |
[단과_C] 2020.02.19 (0) | 2020.02.19 |
[단과_JAVA] 2020.02.19 (0) | 2020.02.19 |
[단과_C] 2020.02.18 (0) | 2020.02.19 |