티스토리 뷰
1. 요약
- instanceof : 타입변환을 해야 될 때, 먼저 자식 타입인지 확인 후에 강제형변환을 시킬 때 사용한다.
- “ 객체 instanceof 타입 “ 형태로 사용되는데, parent instanceof child라고 하면 parent라는 매개변수가 참조하는 객체가 child인지 조사하는 것이다.
- Instanceof를 사용하기 위해서는 부모 / 자식 관계기 형성되어 있어야 한다.
2. 추상 클래스 ( Abstract Class )
- 추상 : 실체들 간에 공통되는 특성을 추출한 것이다.
- EX. 새, 강아지, 고양이, 햄스터 - > 동물 ( 추상 )
- 추상클래스 :
- 실체 클래스들의 공통되는 필드와 메소드를 정의한 클래스
- 추상 클래스는 실체 클래스의 부모 클래스 역할을 한다.
- 여러 실체들의 공통적인 부분을 추상한 것이기에, 객체 생성이 불가능 하다. ( 단독 객체 X )
- 단, 객체 생성이 불가능하다는 것이지 자식 클래스가 없다는 것이 아니다.
- 추상 클래스의 용도 :
- 1 ) 실체 클래스의 공통된 필드와 메소드의 이름을 통일할 목적으로 사용
- 2 ) 상속을 통해 실체 클래스를 작성할 때 시간을 절약이 가능
- 3 ) 실체 클래스 설계 규격을 만들고자 할 때 사용
- + 실체 클래스는 무조건 추상 클래스를 상속 받아 작성한다.
- 추상 클래스 선언 : 클래스 선언부에 public abstract class 클래스명으로 작성한다.
- 이를 통해서 New연산자로 객체를 생성하지 못하게 하고 상속을 통해 자식 클래스만 생성이 가능해진다.
3. 인터페이스 ( interface - 참조타입 중 하나 )
- 멤버 :
- 가. Static final 상수 선언
- 나. 추상메소드 선언
- 다. 디폴트 메소드 ( 인스턴스 메소드 )
- 라. 정적 메소드 ( clazz에 소속된 메소드 )
4. 인터페이스의 역할 p.346
- 인터페이스 : 개발 코드와 객체가 서로 통신하는 접점을 의미한다.
- 개발코드가 객체에 종속되지 않게 하여, 객체를 교체할 수 있도록 하는 역할
- 개발 코드 변경 없이 리턴값 또는 실행 내용이 다양해질 수 있다. ( 다형성 )
- 인터페이스의 선언 : [ public / default ] interface 인터페이스 명 { … }
- 인터페이스 선언 중괄호 { } 내에서는 static final 상수, 추상 메소드, 디폴트 메소드, default 타입과 static 타입의 메소드가 올 수 있다.
- 이를 통해 인터페이스가 부모 역할을 하고 있음을 알 수 있다.
5. 인터페이스의 구현
- 인터페이스의 추상 메소드에 대한 실체 메소드를 가진 객체를 구현 객체라고 부른다.
- 구현 객체를 생성하는 클래스를 구현 클래스라고 부른다.
- 구현 클래스는 implements 키워드로 명시한다.
- Ex. public class 구현클래스명 implements 인터페이스명 { // 인터페이스에 선언된 추상 메소드의 실체 메소드 선언 }
- 이용할 수 있다는 것이지 상속받는 것이 아니기에, this.을 활용할 수 없다.
- 인터페이스의 이름 앞에는 대문자 I를 붙이고, 구현 클래스에서는 Impl를 붙이는 것이 관례이다.
- 인터페이스의 경우, 상속과 다르게 다수상속이 가능하다!
- Ex. public class 구현클래스명 implements 인터페이스A, 인터페이스B {
- // 인터페이스 A에 선언된 추상 메소드의 실체 메소드 선언
- // 인터페이스 A에 선언된 추상 메소드의 실체 메소드 선언 }
- 이때 구현클래스명은 인터페이스A와 인터페이스B 모두 충족시켜야 한다.
- 이때 이름 충돌이 발생하게 된다면, import문이 다른 곳으로 지정될 수 있으니 컨트롤 키를 활용하여 잘 확인해야 한다.
- 만약 잘 못 연결되었을 경우, import문을 직접 작성하여 해결하는 방법도 있다.
6. 인터페이스 - 익명 구현 객체
- 익명 구현객체 : 명시적인 구현 클래스를 작성하는 것을 생략하고, 바로 구현 객체를 얻는 방법이다.
- 이름 없는 구현 클래스를 선언하는 동시에 객체를 생성한다.
- Ex. 인터페이스 변수 = new 인터페이스 ( ) { // 인터페이스에 선언된 추상 메소드의 실체 메소드 선언 } ;
- 익명 구현 객체는 주로 추상 메소드가 1-2개일 때, 사용된다.
- + 원래 인터페이스는 추상 클래스와 같이 객체 생성이 불가능 하다.
- 인터페이스의 추상 메소드들은 모두 재정의하는 메소드가 있어야 한다.
- 추가적인 필드와 메소드를 선언하는 것은 가능하지만, 익명 객체 내에서만 사용이 가능하다.
- 그리고 익명구현객체는 인터페이스 변수로 접근하는 것이 불가능하다.
7. 인터페이스 - 디폴트 메소드
- 디폴트 메소드는 인터페이스만으로는 사용이 불가능 하다.
- 구현 객체가 인터페이스에 대립되어야만 인스턴스 메소드인 디폴트 메소드를 호출할 수 있다.
- 디폴트 메소드는 필요에 따라 구현 클래스가 디폴트 메소드를 재정의해 사용한다.
디폴트 메소드는 “ public default void setMute(boolean mute) { } “와 같이 작성한다.
01. 추상 클래스
package obstract_class;
public abstract class Phone { // 추상 클래스 선언 (***)
// 1. 공통필드
public String owner;
// 2. 생성자
public Phone (String owner) {
this.owner = owner;
} // constructor
// 추상 클래스는 단독 객체, 객체 생성이 불가능 하여 생성자를 만들 수 있다는 것이 의문일 수는 있으나
// 자식 클래스는 실체가 있는 콘크리트 클래스이기에, 생성자를 만드는 것이 가능하다.
// 3. 공통 메소드
public void turnOn() {
System.out.println("폰 전원을 킵니다.");
} // turnOn
public void turnOff() {
System.out.println("폰 전원을 끕니다.");
} // turnOff
} // end class
package obstract_class;
public class SmartPhone extends Phone {
// 1. 생성자
public SmartPhone (String owner) {
super(owner); // 부모객체를 먼저 생성해야 한다. (***)
} // smartPhone constructor
// 2. 메소드
public void internetSearch() {
System.out.println("인터넷 검색을 합니다.");
} // internetSearch
} // end class
package obstract_class;
public class PhoneExample {
public static void main (String[] args) {
// Phone phone = new Phone // ( x ) - 객체를 생성할 수 없다는 오류 메세지가 발생한다.
// 위 코드는 오류가 발생하게 되는데, 그 이유는 추상클래스로부터 객체를 직접 생성할 수 없기 때문이다.
// 왜? 추상클래스이기에 실체가 없기 때문이다.
// 1. 자식객체 생성 - 추상 클래스는 자식객체를 생성하게 된다.
SmartPhone smartphone = new SmartPhone("홍길동");
// 2. 부모( 추상클래스 )로부터 물려받은 메소드 호출
smartphone.turnOn();
smartphone.internetSearch();
smartphone.turnOff();
} // main
} // end class
02. 추상 메소드
package obstract_class_Animal; // 추상 메소드 (*****)
// 추상 클래스를 통해 적어도 동물이라면, 반드시 가져야 할 속성과 기능을
// 필드와 메소드로 선언하여, 이를 규격화해서, 상속받는 자식 클래스가 반드시
// 이 규격을 지키도록 해준다. ( " 추상메소드 " )
public abstract class Animal {
public String kind;
public void breath() {
System.out.println("숨을 쉽니다.");
} // breath
// " 추상 메소드 " : 메소드의 시그니처만 있고 구현부 { }가 없다. (****)
// 이 추상크래스를 상속받는 모든 자식클래스에서는, 이 추상메소드를 반드시
// 구현 ( 즉, 메소드 오버라이딩(재정의) ) 해야 한다!!
// 만일, 구현하지 않으면, 해당 자식 클래스조차 추상클래스가 되어야 한다. ( 그렇지 않으면 컴파일 오류가 난다. )
public abstract void sound(); // 예 : 타이어의 구격을 자식 클래스에 강제화시킴. (*****)
} // end class
package obstract_class_Animal;
public class Cat extends Animal {
public Cat() {
this.kind = "포유류";
} // default constructor
@Override
public void sound() {
System.out.println("야옹 ~ ");
} // sound
// 부모인 추상 클래스에 선언된, 추상 케소드를 반드시 구형(재정의, 오버라이드) 해야 한다!! (**)
// 만일, 자식 클래스에서 구현(재정의)하지 않으면, 자식 클래스조차 abstract 키워드로
// 추상클래스화 해야 한다!! ( why? 강제사항인 구격을 지키지 않았기 때문이다. )
} // end class
package obstract_class_Animal;
public class Dog extends Animal {
public Dog() {
this.kind = "포유류";
// super.kind = "포유류"; // 이는 부모 클래스에 있는 값을 바꾼 것이다. 그러므로 this.을 사용하도록 하자!
} // default constructor
// 부모인 추상클래스에 선언된, 추상메소드( 강제 규격 )을 구현 ( 재정의 )
@Override
public void sound() {
System.out.println("멍멍!");
} // sound
} // end class
package obstract_class_Animal;
public class AnimalExample {
public static void main (String[] args ) { // 추상 클래스의 자동형변환
// 1. 객체 생성
Dog dog = new Dog();
Cat cat = new Cat();
// 2. 각 자식객체가 구현한 소리를 발생시킴
dog.sound();
cat.sound();
// 자식클래스의 객체를 단순하게 호출한 것이다. ( 다형성 X )
System.out.println("===== 사용(이용)관계로써, 자식객체 활용 =======");
// 변수의 자동 타입 변환 (******)
Animal animal = null; // 부모타입 변수 선언 (******)
animal = new Dog(); // 다형성 1 - 부모가 자식을 감싼다.
animal.sound(); // 다형성 2 - 오버라이딩 ( 재정의 )
animal = new Cat();
animal.sound();
System.out.println("================================================");
// 매개변수의 자동타입 변환 (****)
animalSound(new Dog());
animalSound(new Cat());
// 자식 클래스를 매개변수로 주고 있다.
// Animal animal = new Dog();와 같은 의미
} // main
public static void animalSound(Animal animal) {
// 자식 클래스를 매개변수로 주고 있기에, Animal animal = new Dog();와 같은 의미이다.
animal.sound(); // 다형성2
} // animalSound
// 출력 결과 :
//
// 멍멍!
// 야옹 ~
// ===== 사용(이용)관계로써, 자식객체 활용 =======
// 멍멍!
// 야옹 ~
// ================================================
// 멍멍!
// 야옹 ~
} // end class
03. 인터페이스
package Interface; // 인터페이스
public interface RemoteControl { // 리모콘이 반드시 공통적으로 가지고 있는 기능을 규격화시킨다. (***)
// 인터페이스의 모든 멤버는 반드시 public 접근제한자를 사용해야 한다!!!! (***)
// 1. 인터페이스에 선언할 수 있는 멤버로 static final 상수 선언
public static final int MAX_VOLUME = 10;
// int MIN_VOLUME = 0; // OK!! 인터페이스에서는 public static final를 자동으로 입력해 준다.
public static final int MIN_VOLUME = 0;
// 하지만 인터페이스에서는 public만 가능하다는 사실을 까먹을 수 있으니, public static final int를 모두 작성하도록 하자!
// 인터페이스는 추상 클래스와 같이 객체 생성이 불가능 하다.
// 2. 추상 메소드 ( 강제규격 ) - 자식 객체가 반드시 구현해야 할 기능을 선언 (***)
// 추상 메소드를 통해서 다형성 구현
// void turnOn(); // OK!! public abstract을 생략해도 자동으로 입력해 주지만, 가독성이 떨어지기에 지양해라!
public abstract void turnOn();
public abstract void turnOff();
public abstract void setVolume(int volume);
// =============================================== 자바 8 이후
// 3. 디폴트 메소드 ( 완전한 인스턴스 메소드이다! ) -> 객체없이는 사용이 불가능 하다!
// 어? 근데 인터페이스는 객체 생성이 불가능하다면서??!
// - > 그렇기에, 인터페이스를 활용하여 인터페이스에 있는 인스턴스 메소드를
// 인터페이스 규격을 지키고 있는 자식이 사용할 수 있게 해주고 있다.
public default void setMute(boolean mute) {
if(mute) {
System.out.println("무음 처리합니다.");
} else {
System.out.println("무음을 해제합니다.");
} // if - else
} // default method - setMute
// 4. 정적 메소드
public static void changeBattery() {
System.out.println("건전지를 교환합니다.");
}// changeBattery
} // end interface
package Interface;
import lombok.ToString; // Import를 꼭 적용시켜야 한다!!
@ToString // 실행클래스에서 출력할 때, 필드 내부를 볼 수 있도록 해준다! (*****)
public class Audio implements RemoteControl {
// 1. 인스턴스 필드
private int volume;
// -------------------- 인터페이스의 규격을 구현 ( 재정의 ) -----------------------
// 2. 추상 메소드의 실체 메소드
@Override
public void turnOn() {
System.out.println("Audio를 켭니다.");
} // turnOn
@Override
public void turnOff() {
System.out.println("Audio를 끕니다.");
} // turnOff
@Override
public void setVolume ( int volume ) {
if ( volume > RemoteControl.MAX_VOLUME) {
this.volume = RemoteControl.MAX_VOLUME;
} else if ( volume < RemoteControl.MIN_VOLUME) {
this.volume = RemoteControl.MIN_VOLUME;
} else {
this.volume = volume;
} // if - else if - else
System.out.println("현재 Audio 볼륨 : " + volume );
} // setVolume
} // end class
package Interface;
public class Television implements RemoteControl {
// 1. 인스턴스 필드
private int volume;
// -------------------- 인터페이스의 규격을 구현 ( 재정의 ) -----------------------
// 2. 추상 메소드의 실체 메소드
@Override
public void turnOn() {
System.out.println("TV를 켭니다.");
} // turnOn
@Override
public void turnOff() {
System.out.println("TV를 끕니다.");
} // turnOff
@Override
public void setVolume ( int volume ) {
if ( volume > RemoteControl.MAX_VOLUME) {
this.volume = RemoteControl.MAX_VOLUME;
} else if ( volume < RemoteControl.MIN_VOLUME) {
this.volume = RemoteControl.MIN_VOLUME;
} else {
this.volume = volume;
} // if - else if - else
System.out.println("현재 TV 볼륨 : " + volume );
} // setVolume
} // end class
package Interface;
public class RemoteControlExample {
public static void main (String [] args) {
RemoteControl rc; // 부모타입 ( 인터페이스 )
rc = new Television( ); // 다형성 1
System.out.println("rc1 : " + rc); // 출력 : rc1 : Interface.Television@2f92e0f4
// + 모를때는 일단 출력해보고 결과를 확인해 보자!!
rc.turnOn(); // 다형성 2 : 출력 - TV를 켭니다.
rc.turnOff(); // 다형성 2 : 출력 - TV를 끕니다.
rc = new Audio(); // 다형성 1
System.out.println("rc2 : " + rc); // 출력 : rc2 : Interface.Audio@5305068a
// Audio구현 클래스에 @ToString을 붙이자 " rc2 : Audio(volume=0) "로 출력이 되었다.
// 이는 출력 당시의 필드 내부를 출력해주는 것이다.
rc.turnOn(); // 다형성 2 : 출력 - Audio를 켭니다.
rc.turnOff(); // 다형성 2 : 출력 - Audio를 끕니다.
} // main
} // end class
04. 인터페이스 - 익명구현객체
package Interface02;
public interface RemoteControl {
public static final int MAX_VOLUME = 10;
public static final int MIN_VOLUME = 0;
public abstract void turnOff();
public abstract void setVolume(int volume);
public default void setMute(boolean mute) {
if(mute) {
System.out.println("무음 처리합니다.");
} else {
System.out.println("무음을 해제합니다.");
} // if - else
} // default method - setMute
public static void changeBattery() {
System.out.println("건전지를 교환합니다.");
}// changeBattery
} // end class
package Interface02;
import Interface.RemoteControl;
public class RemoteControlExample {
public static void main (String [] args) { // 익명구현객체 (*****)
RemoteControl rc = new RemoteControl() {
String name = "Yoseph"; // 필요시에 필드를 추가할 수 있다.
int age = 23;
public void instanceMethod() {
System.out.println("instanceMethod() invoked."); // 메소드도 만들 수는 있다.
} // instanceMethod
// 익명구현객체 선언시, 내부에 선언한 추가적인 필드와 메소드는
// 참조변수명.필드/메소드 형식으로 ( rc.turnOn(); )
// 사용불가! = > 추가적인 필드와 메소드는 익명구현객체 블록 내에서만 사용해라!!
@Override
public void turnOn() {
System.out.println("turnOn() invoked. name : " + this.name);
} // turnOn
@Override
public void turnOff() {
System.out.println("turnOff() invoked. age : " + this.age);
System.out.println("\t + this : " + this); // + this:Interface02.RemoteControlExample$1@2f92e0f4
// 이때 this는 익명 구현 객체인 자신임을 알 수 있다.
} // turnOff
@Override
public void setVolume(int volume) {
System.out.println("setVolume() invoked.");
} // setVolume
}; // 익명 구현 객체 생성
rc.turnOn();
rc.turnOff();
rc.setVolume(RemoteControl.MAX_VOLUME);
System.out.println("rc : " + rc); // 출력 : rc : Interface02.RemoteControlExample$1@2f92e0f4
// 이 중 $1은 익명구현객체라는 의미이며, 늘어날 때마다 $ 뒤의 숫자가 증가한다.
} // main
} // end class
05. 인터페이스 - 디폴트 메소드
package Interface03;
public interface RemoteControl {
public static final int MAX_VOLUME = 10;
public static final int MIN_VOLUME = 0;
public abstract void turnOn();
public abstract void turnOff();
public abstract void setVolume(int volume);
public default void setMute(boolean mute) {
if(mute) {
System.out.println("무음 처리합니다.");
} else {
System.out.println("무음을 해제합니다.");
} // if - else
} // default method - setMute
public static void changeBattery() {
System.out.println("건전지를 교환합니다.");
}// changeBattery
} // end class
package Interface03;
public interface Searchable {
public abstract void search(String url);
} // end class
package Interface03;
import Interface03.RemoteControl;
public class SmartTelevision implements RemoteControl, Searchable {
// RemoteControl과 Searchable을 상속 받고 있음을 알 수 있다. - 다중상속
// 첫번째 인터페이스인, RemoteControl에 선언된 추상메소드의 재정의
private int volume;
@Override
public void turnOn() {
System.out.println("TV를 켭니다.");
} // turnOn
@Override
public void turnOff() {
System.out.println("TV를 끕니다.");
} // turnOff
@Override
public void setVolume ( int volume ) {
if ( volume > RemoteControl.MAX_VOLUME) {
this.volume = RemoteControl.MAX_VOLUME;
} else if ( volume < RemoteControl.MIN_VOLUME) {
this.volume = RemoteControl.MIN_VOLUME;
} else {
this.volume = volume;
} // if - else if - else
System.out.println("현재 TV 볼륨 : " + volume );
} // setVolume
// 두번째 인터페이스인, Searchable에 선언된 추상메소드의 재정의
@Override
public void search(String url) {
System.out.println(url + "을 검색합니다.");
}
} // end class
package Interface03;
public class RemoteControlExample {
public static void main(String[] args) {
SmartTelevision tv = new SmartTelevision();
// 다형성 1
RemoteControl rc = tv;
Searchable searchable = tv;
// 다형성 2
rc.turnOn();
searchable.search("http://www.naver.com");
// 출력 : http://www.naver.com을 검색합니다.
// 디폴트 메소드 호출
rc.setMute(false);
// =========================================================
// RemoteControl rc2 = null; // 객체를 생성하고 있는 것이 아니라 단순히 변수를 선언하고 있는 것이다.
// rc2.setMute(false);
// 디폴트메소드( 인스턴스 메소드 )는 객체 없이는 사용할 수 없다.
// =========================================================
Searchable rc3 = new Searchable() {
@Override
public void search(String url) {
System.out.println("search(url) invoked.");
} // search
}; // rc3
rc3.search("http://www.daum.com"); // 다형성 2 - 오버라이드
// 출력 : search(url) invoked.
} // main
} // end class
'KH 정보교육원 [ Java ]' 카테고리의 다른 글
KH 18일차 - 예외처리코드 및 제네릭 (0) | 2022.03.24 |
---|---|
KH 17일차 - 인터페이스와 예외처리 (0) | 2022.03.22 |
KH 15일차 - protected 접근제한자 및 프로모션 (0) | 2022.03.18 |
KH 14일차 - 상속 (0) | 2022.03.17 |
KH 13일차 - 어노테이션 (0) | 2022.03.16 |