1. 상속
(1) 상속의 정의와 장점
상속이란 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것이다.
장점 : 코드의 추가 변경이 용이하여 코드의 재사용성을 높이고 중복을 제거하여 생산성과 유지보수에 큰 기여를 한다.
class 새로 작성하고자 하는 클래스(자손클래스) extends 상속받고자 하는 클래스(조상클래스)
조상클래스 - 부모클래스, 상위클래스, 기반클래스
자손클래스 - 자식클래스, 하위클래스, 파생된 클래스
class Parent { . . . } class Child extends Parent { . . . } |
Child클래스는 Parent클래스의 맴버들을 모두 포함한다.
-> 자손클래스는 조상클래스의 모든 맴버를 상속받는다.
반대로 자손클래스가 변경되는 것은 조상클래스에 아무런 영향을 주지 않는다.
- 생성자와 초기화 블럭은 상속되지 않는다. 맴버만 상속된다.
- 자손클래스의 맴버 개수는 조상클래스보다 항상 같거나 많다.
class Parent { . . . } class Child extends Parent { . . . } class Child2 extends Parent { . . . } |
Child와 Child2 는 Parent와 서로 상속관계에 있지만 Child와 Child2 사에이는 서로 아무런 관계도 성립되지 않는다.
만일 Child와 Child2에 동시에 추가할 맴버(맴버변수나 메서드)가 있다면 공통조상인 Parent에 넣자
class Parent { . . . } class Child extends Parent { . . . } class Child2 extends Parent { . . . } class GrandChild extends Child { . . . } |
GrandChild는 Child클래스의 모든 맴버와 Parent클래스의 맴버까지 상속받는다.
(2) 포함관계 : 클래스간의관계
포함관계란 한 클래스의 맴버변수로 다른 클래스를 선언하는 것이다.
class Circle { int x; //원점의 x좌표 int y; // 원점의 y좌표 int r; // 반지름 } class Point { int x; // x좌표 int y; //y좌표 } |
위의 코드를 포함관계를 이용하여 재정의하면
class Circle { Point c = new Point(); // 원점 int r; //반지름 } |
(3)클래스간의 관계 결정하기
class Circle { Point c = new Point(); // 원점 int r; //반지름 } |
포함관계 : Circle은 Point를 가지고 있다.
class Circle extends Point { int r; //반지름 } |
상속관계 : Circle은 Point이다.
-toString
(4) 단일상속
자바는 다중상속이 불가하기에 2개 이상의 조상클래스를 상속할 수 없다.
따라서 상속과 포함을 사용하여 코드를 진행한다.
(5) Object클래스
Object클래스는 모든 클래스 상속계층도의 제일 위에 위치하는 조상클래스이다.
2. 오버라이딩
(1) 오버라이딩이란?
오버라이딩이란 조상클래스로부터 상속받은 메서드의 내용을 변경하는 것이다.
상속받은 메서드를 그대로 사용하지만 자손클래스에 맞개 변경할 경우 오버라이딩을 사용한다.
class Point { int x; int y; String getLocation() { return "x:" + x + ", y :" + y; } } class Point3D extends Point { int z; String getLocation() { //오버라이딩 return "x : " + x + ", y : " + y + ", z : " + z; } } |
(2) 오버라이딩의 조건
조상클래스의 메서드와 - 이름이 같아야 한다 - 매개변수가 같아야 한다 - 리턴타입이 같아야한다. 즉 ,선언부가 같아야한다. |
조상클래스의 메서드를 자손클래스에서 오버라이딩 할 때,
1. 접근 제어자는 조상 클래스의 메서드보다 좁은 범위로 변경 할 수 없다.
- 만일 조상클래스에 정의된 메서드의 접근제어자가 protected라면 오버라이딩하는 자손클래스의 메서드는 접근 제어자가 protected/public이어야 한다.
public | protected | default | private |
접근제어자의 접근범위(+ ~ - )
2. 조상클래스의 메서드보다 많은 수의 예외를 선언 할 수 없다.
3. 인스턴스 메서드를 static메서드로 또는 그 반대로 변경할 수 없다.
(3) 오버로딩 vs 오버라이딩
오버로딩 : 기존에 없는 새로운 메서드를 정의하는 것(new)
오버라이딩 : 상속받은 메서드의 내용을 변경하는 것(change)
(4) super
super는 자손클래스에서 조상클래스로부터 상속받은 맴버를 참조하는데 사용되는 참조변수이다.
상속받은 맴버와 자신의 클래스에 정의된 맴버의 이름이 같을 때 super을 이용하여 구별
static메서드에서는 사용할 수 없고 인스턴스메서드에서만 사용할 수 있다.
메서드에서도 super를 호출할 수 있다. 특히 조상클래스의 매서드를 자손클래스에서 오버라이딩하는 경우 사용된다.
class Point { int x; int y; String getLocation() { return "x:" + x + ", y :" + y; } } class Point3D extends Point { int z; String getLocation() { //오버라이딩 return super.getLocation()+ ", z : " + z; } } |
(5) super() : 조상클래스의 생성자
조상클래스의 생성자를 호출하는데 사용된다.
자손클래스의 인스턴스가 조상클래스의 맴버들을 사용할 때,
조상클래스 맴버의 생성과 초기화 작업이 수행되어야한다. 따라서 자손클래스의 생성자에서 조상클래스의 생성자가 호출된다.
생성자의 첫 줄에서 조상클래스의 생성자를 호출한다. WHY? 자손 클래스의 맴버가 조상클래스의 맴버를 사용할 수 있기에 먼저 초기화되어야한다.
3. package 와 import
(1) 패키지 (package)
패키지란 클래스의 묶음이다.
- 하나의 소스파일에는 첫번재 문자응로 단 한 번의 패키지 선언만을 허용한다. - 모든 클래스는 반드시 하나의 패키지에 속해야한다 - 패키지는 점(.)을 구분자로 하여 계층구조를 구성할 수 있다. - 패키지는 물리적으로 클래스 파일을 포함하는 하나의 디렉토리이다. |
(2) 패키지의 선언
package 패키지명;
패키지 선언문은 반드시 소스파일에서 주석과 공백을 제외한 첫 번째 문장이어야 하며, 하나의 소스파일에 단 한번만 선언될 수 있다.
패키지명은 소문자로 하는 것을 원칙으로 한다.
(3) import문
사용하고자하는 클래스의 패키지를 미리 명시해주면 사용되는 클래스 이름에서 패키지명은 생략할 수 있다.
import문의 역할은 컴파일러에게 소스파일에 사용된 클래스의 패키지에 대한 정보를 제공하는 것이다.
(4) import문의 선언
소스파일(.java)안의 구성
package문 - import문 - 클래스 선언 순으로 되어있다.
import 패키지명.클래스명;
import 패키지명.*;
4. 제어자
(1) 제어자란?
제어자는 클래스, 변수, 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다.
제어자의 종류
접근제어자 | public | protected | default | private |
그 | static | final | abstract | native |
외 | transient | syschronized | volatile | strictfp |
하나의 대상에 여러 제어자를 조합하여 사용하는 것이 가능하나, 접근제어자는 한번에 네가지 중 하나만 쓸 수 있다.
(2) static : 클래스의, 공통적인
제어자 | 대상 | 의 미 |
모든 인스턴스에 공통적으로 사용되는 클래스변수가 된다. | ||
맴버변수 | 클래스변수는 인스턴스를 생성하지 않고도 사용 가능하다 | |
static | 클래스가 메모리에 로드될 때 생성된다. | |
메서드 | 인스턴스를 생성하지 않고도 호출이 가능한 static메서드가 된다 | |
static메서드 내에서는 인스턴스맴버들을 직접 사용할 수 없다. | ||
초기화 블럭 |
인스턴스 맴버를 사용하지 않는 메서드는 static을 붙여서 static메서드로 선언하는 것을 고려하라.
(3) final : 마지막의, 변형될 수 없는.
변수 - 변경할 수 없는 상수가 된다.
메서드 - 오버라이딩 불가
클래스 - 자신을 확장하는 자손클래스 정의 불가
(4) 생성자를 이용한 final 맴버변수 초기화
final이 붙는 변수는 상수이기에 일반적으로 선언과 초기화를 동시에 한다.
그러나 인스턴스 변수의 경우 생성자에서 초기화를 한다
클래스 내에 매개변수를 갖는 생성자를 선언하여, 인스턴스를 생성할 때 final이 붙은 맴법변수를 초기화하는데 필요한 값을 생성자의 매개변수로부터 제공받는 것이다.
- 각 인스턴스마다 final이 붙은 맴버변수가 다른 값을 갖도록 하는 것이 가능하다.
(5) abstract : 추상의, 미완성의
메서드의 선언부만 작성하고 실제 수행내용은 구현하지 않은 추상메서드를 선언하는데 사용된다.
(6) 접근제어자
접근제어자는 맴버 또는 클래스에 사용되어, 해당하는 맴버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.
접근제어자는 클래스, 맴버변수, 메서드, 생성자에서 사용될 수 있다.
(7) 접근제어자를 이용한 캡슐화
접근제어자를 사용하는 이유는 클래스 내부에 선언된 데이터의 보호를 위해서이다.
데이터가 유효한 값을 유지하도록, 혹은 외부에서 함부로 변경하지 못하도록 하기 위해서는 외부로부터의 접근을 제한하는 것이 필요하기 때문
따라서 이를 캡슐화라고 한다.
(8) 생성자에서의 접근제어자
생성자에 접근제어자를 사용함으로써 인스턴스의 생성을 제한할 수 있다.
private을 이용한 생성자는 외부에서 생성자에 접근할 수 없으므로 인스턴스를 생성할 수 없게 된다. 그래도 클래스 내부에서는 인스턴스 생성이 가능하다.
대신 인스턴스를 생성해서 반환해주는 public메서드과 static메서드를 제공함으로써 외부에서 이 클래스의 인스턴스를 사용하도록 할 수 있다.
class Singleton { // . . . private static Singleton s = new Singleton(); // getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야 한다. private Singleton() { . . . } // private를 사용한 생성자 //인스턴스를 생성하지 않고도 호출할 수 있어야 하므로 static이어야 한다. public static Singleton getInstance() { return s; } } |
생성자가 private인 클래스는 다른 클래스의 조상이 될 수 없다.
WHY? 자손클래스의 인스턴스를 생성할 때 조상클래스의 생성자를 호출해야하는데 접근이 불가능하기에
따라서 클래스 앞에 final를 추가하여 상속이 불가한 클래스임을 명시
public final class Math { private Math() { . . .} } |
(9) 제어자의 조합
제어자를 조합해서 사용할 때 주의할 점
1. 메서드에서 static과 abstract를 함께 사용할 수 없다
- static메서드는 몸통이 있는 메서드에서만 구현가능
2. 클래스에서 abstract과 final를 동시에 쓸 수 없다.
- final은 클래스를 확장할 수 없다는 의미 abstract은 상속을 통해 완성된다는 의미 (모순)
3. abstract메서드의 저븐 제어자가 private일 수 없다.
- abstract메서드는 자손클래스에서 구현해주어야 하는데 접근이 불가능하기에
4. 메서드에 private과 final을 같이 사용할 필요는 없다.
-의미는 동일하기에
5. 다형성
(1) 다형성이란?
여러가지 형태를 가질 수 있는 능력
한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 하는 것
= 조상 클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 하는 것
class Tv { boolean power; int channel; void power() { power =! power; } void channelUp() { ++channel; } void channelDown { --channel; } } class CaptionTv extends Tv { String text; void caption() { . . . .} } |
상속관계의 두 클래스를 정의하였을 때, 이 두 클래스의 인스턴스를 생성하기 위해
Tv t = new Tv(); CaptionTv c = new CaptionTv(); |
인스턴스 타입과 일치하는 참조변수를 사용하였다.
그러나 상속관계에 있을 경우, 조상클래스 타이븨 참조변수로 자손 클래스의 인스턴스를 참조하도록 하는 것도 가능하다.
Tv t = new CaptionTv(); |
인스턴스 타입이 일치하는 참조변수 & 조상타입의 참조변수를 이용해 참조한 경우의 차이점
CaptionTv c = new CaptionTv(); Tv t = new CaptionTv(); |
조상타입의 참조변수 t의 경우 CaptionTv의 모든 인스턴스의 사용이 불가하다.
오직 CaptionTv인스턴스 안에 포함된 조상타입(Tv)의 인스턴스만 사용가능하다.
(t.text, t.caption()은 사용불가)
= 같은 타입의 인스턴스이지만 참조변수의 타입에 따라 사용할 수 있는 맴버의 개수가 다르다
CaptionTv c = new Tv(); |
그렇다면 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수 있을까?
- > NOPE!
WHY? 실제 인스턴스인 Tv의 맴버개수 보다 참조변수 c가 사용할 수 있는 맴버 개수가 더 많기 때문
= 참조변수가 사용할 수 있는 맴버의 개수는 인스턴스의 맴버 개수보다 같거나 적어야 한다.
(2) 참조변수의 형변환
참조변수의 형변환은
1. 자손타입의 참조변수 -> 조상타입의 참조변수 (업캐스팅)
2. 조상타입의 참조변수 -> 자손타입의 참조변수 (다운캐스팅)
로 형변환이 가능하다.
작은 자료형에서 큰자료형의 형변환은 생략 가능하듯, 1번의 경우 생략 가능하다.
캐스트연산자를 사용하여 괄호안에 변환하고자 하는 타입의 이름(클래스명) 을 적어주면 된다.
class Car { String dolor ; int door; void drive() { . . . . } void stop() { . . . } } class FireEngine extends Car { void water() { . . . } } class Ambulance extends Car { void siren() { . . . } } |
위와 같은 클래스를 정의 했을 떄.
Car타입의 참조변수(조상클래스) & FireEngine타입의 참조변수 / Ambulance타입의 참조변수 (자손클래스) 간의 형변환은 가능하지만
FireEngine타입의 참조변수 & Ambulance타입의 참조변수 즉, 자손클래스 간의 형변환은 불가능하다
Car car = null; FIreEngine fe = new FIreEngine(); FireEngine fe2 = null; car = fe; fe2 = (FireEngine)car; |
* 은선 's 이해
car는 Car인스턴스를 가르키는 참조변수이다. 그런데 참조변수 car가 FireEngine인스턴스를 가르킬때, fe가 FireEngine타입 아닌 Car타입의 fe가 됨을 명시해주어야한다.
why? 맴버의 사용개수때문..
형변환은 참조변수의 타입을 변하는 것이지 인스턴스를 변환하는 것이 아니다. 따라서 참조변수의 형변환은 인스턴스에 아무런 영향을 미치지 않는다.
단지 참조변수의 형변환을 통해서, 참조하고 있는 인스턴스에서 사용할 수 있는 맴버의 범위(개수)를 조절하는 것
(3) instanceof연산자
참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof연산자를 사용
주로 조건문에서 이용, 참조변수 instnaceof 타입(클래스명) 형태로 쓰인다.
결과가 ture라면 참조변수가 형변환이 가능함을 의미한다.
void doWork(Car c) { if ( c instanceof FireEngine) { . . . } else ( c instanceof Ambulance) { . . . } } |
(4) 참조변수와 인스턴스의 연결
조상클래스에 선언된 맴버변수와 같은 이름의 인스턴스변수를 자손 클래스에 중복으로 정의했을 때,
1. 조상타입의 참조변수로 자손 인스턴스를 참조하는 경우와
= 조상클래스에 선언된 맴버변수가 사용
2. 자손타입의 참조변수로 자손 인스턴스를 참조하는 경우는 서로 다른 결과를 얻는다.
= 자손클래스에 선언된 맴버변수가 사용
(5) 매개변수의 다형성
참조변수의 다형적인 특징은 메서드의 매개변수에도 적용된다.
void buy(Tv t) { //Buyer가 가진 돈(money)에서 제품의 가격(t.price)를 뺀다. money -= t.price; //Buyer의 보너스 점수(bonusPoint)에 제품의 보너스점수(t.bonusPoint)를 더한다. bonusPoint += t.bonusPoint; } |
void buy(Computer c) { //Buyer가 가진 돈(money)에서 제품의 가격(t.price)를 뺀다. money -= c.price; //Buyer의 보너스 점수(bonusPoint)에 제품의 보너스점수(t.bonusPoint)를 더한다. bonusPoint += c.bonusPoint; } |
void buy(Audio a) { //Buyer가 가진 돈(money)에서 제품의 가격(t.price)를 뺀다. money -= a.price; //Buyer의 보너스 점수(bonusPoint)에 제품의 보너스점수(t.bonusPoint)를 더한다. bonusPoint += a.bonusPoint; } |
이처럼 상황에 따라 새로운 메서드를 추가해야하는 번거로움을 매개변수의 다형성을 사용하면
void buy(Product p) { money -= p.price; bonusPoint += p.bonusPoint; } /* 사전 정의 */ class Product { int price; int bonusPoint; } class Tv extends Product { . . .} class Computer extends Product { . . .} class Audio extends Product { . . .} class Buyer { int money = 1000; int bonusPoint = 0; } |
하나의 매서드로 처리가 가능하다.
(6) 여러종류의 객체를 하나의 배열로 다루기
Product p1 = new Tv(); Product p2 = new Computer(); Product p3 = new Audio(); |
위와 같은 코드를 Product타입의 참조배열로 처리하면 아래와 같다.
Product p[] = new Product[3]; p[0] = new Tv(); p[1] = new Computer(); p[2] = new Audio(); |
조상타입의 참조변수 배열을 사용하면, 공통의 조상을 가진 서로 다른 종류의 객체를 배열로 묶어서 사용가능
또한, 묶어서 다루고자하는 객체들의 상속관계를 따져서 가장 가까운 공통조상 클래스 타입의 참조변수 배열을 생성해서 객체들을 저장하면 된다.
class Buyer { //고객, 물건을 사는 사 int money = 1000; //소유금 int bonusPoint = 0; //보너스 점 Product[] item = new Product[10]; //구입한 제품을 저장하기 위한 배열 int i = 0; //product배열에 사용될 카운터 void buy(Product p) { if(money < p.price) { System.out.println("잔액이 부족하여 물건을 살수 없습니다."); return; } money -= p.price; //가진 돈에서 구입한 제품의 가격을 뺀다. bonusPoint += p.bonusPoint; //제품의 보너스 점수를 추가한다. item[i++] = p; //제품을 Product[] item에 저장한다. 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 +"입니다."); } } |
배열의 크기 설정에 있어 Vector클래스를 사용하면 더 편리하게 이용가능.
- Object타입의 배열을 가지고 있기에, 배열에 객체를 추가/제거가 가능
- 배열의 크기를 알아서 관리
주요 메서드
[사진]
class Buyer { //고객, 물건을 사는 사 int money = 1000; //소유금 int bonusPoint = 0; //보너스 점 Vector item = new Vector(); //구입한 제품을 저장하는데 사용될 Vector객체 void buy(Product p) { if(money < p.price) { System.out.println("잔액이 부족하여 물건을 살수 없습니다."); return; } money -= p.price; //가진 돈에서 구입한 제품의 가격을 뺀다. bonusPoint += p.bonusPoint; //제품의 보너스 점수를 추가한다. item.add(p); //제품을 Vector에 저장한다. System.out.println(p + "을/를 구입하셨습니다."); } void refund(Product p) { //구입한 제품을 환불한다 if(item.remove(p)) { //제품을 Vector에서 제거한 money += p.price; bonusPoint -= p.bonusPoint; System.out.println(p+"을/를 반품하셨습니다."); } else { //제거에 실패할 경 System.out.println("구입하신 제품 중 해당 제품이 없습니다."); } } void summary() { int sum = 0; String itemList=""; if(item.isEmpty()) { System.out.println("구입하신 제품이 없습니다."); return; } //반복문을 이용해서 구입한 물품의 총 가격과 목록을 만든다. for(int i=0; i<item.size();i++) { Product p = (Product)item.get(i); // Vector의 i번째 객체를 가져온다. sum += p.price; itemList += p + ", "; } System.out.println("구입하신 물품의 총금액은" +sum+"만원입니다."); System.out.println("구입하신 제품" + itemList +"입니다."); } } |
6. 추상클래스
(1) 추상클래스란?
추상클래스 = 미완성 설계도
-미완성 매서드를 포함한다
추상클래스로 인스턴스 생성 불가
상속을 통해서 자손클래스에 의해서만 완성 가능
새로운 클래스를 작성하는 데 있어서 바탕이 되는 조상클래스로서 의미가 있음 (틀의 역할)
abstract class 클래스이름 { . . . }
-생성자, 맴버변수, 메서드를 갖는다.
(2) 추상메서드
추상메서드는 선언부만 작성하고 구현부는 작성하지 않고 남겨둔 메서드이다.
구현부를 남겨놓는 이유는 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있기 때문
따라서 조상클래스에서 선언부만 작성, 상속받는 클래스에서 실제내용을 구현
/* 주석을 통해 어떤 기능을 수행할 목적으로 작성하였는지 설명 */
abstract 리턴타입 메서드이름()
추상클래스로부터 상속 받는 자손클래스는 오버라이딩을 통해 추상클래스의 추상메서드를 모두 구현해야한다.
If not , 자손클래스 역시 추상클래스로 지정해야한다.
(3) 추상클래스의 작성
보통 1. 여러 클래스에서 공통저긍로 사용될 수 있는 클래스로 바로 작성하거나
2. 기존의 클래스의 공통적인 부분을 뽑아서 추상클래스로 만들어 상속하도록 하는 경우가 있다.
추상화는 기존의 클래스의 공통부분을 뽑아내서 조상클래스를 만드는 것
구체화는 상속을 통해 클래스를 구현, 확장하는 작업
굳이 추상화를 쓰는 이유는 자손클래스에서 추상메소드를 반드시 구현하도록 강요하기 위해
class Marin { int x, y;//현재 위치 void move(int x, int y) { /* 지정된 위치로 이동 */ } void stop(){/* 현재위치에 정지 */ } void stimPack() { /* 스침팩을 사용한다.*/ } } class Tank { int x, y;//현재 위치 void move(int x, int y) { /* 지정된 위치로 이동 */ } void stop(){/* 현재위치에 정지 */ } void changeMode(){/*공격모드를 변환한다 */ } } class Dropship { int x, y;//현재 위치 void move(int x, int y) { /* 지정된 위치로 이동 */ } void stop(){/* 현재위치에 정지 */ } void load(){/* 선택된 대상을 태운다.*/ } void unload(){ /* 선택된 대상을 내린다.*/} } |
기존 클래스에서 공통된 부분을 추상클래스로 만들어보장.
abstract class Unit { int x, y; abstract void move(int x, int y); void stop(){/* 현재 위치에 정지 */} } class Marin extends Unit { void move(int x, int y){ /* 지정된 위치로 이동 */ } void stimPack() { /* 스침팩을 사용한다.*/ } } class Tank extends Unit { void move(int x, int y){ /* 지정된 위치로 이동 */ } void changeMode(){/*공격모드를 변환한다 */ } } class Dropship extends Unit { void move(int x, int y) { /* 지정된 위치로 이동 */ } void load(){/* 선택된 대상을 태운다.*/ } void unload(){ /* 선택된 대상을 내린다.*/} } |
7. 인터페이스
(1) 인터페이스란?
인터페이스는 추상화 정도가 높은 일종의 추상클래스이다.
메서드/맴버변수를 구성원으로 가질 수 없으며 오직 추상메서드와 상수만을 맴버로 가질 수 있다.
인터페이스 = 기본 설계도
다른 클래스의 작성을 위해 사용
(2) 인터페이스의 작성
interface 인터페이스이름 {
public static final 타입 상수이름 = 값;
public abstract 메서드이름(매개변수목록);
}
- class 대신 interface를 사용
- 접근제어자 사용 가능 (public/static)
- 모든 맴버변수는 public static final이어야 하며, 생략가능
- 모든 메서드는 public abstract 이어야 하며, 생략가능
(3) 인터페이스의 상속
인트페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와 달리 다중상속이 가능하다.
interface Movable { void move (int z, int y); } interface Attackable { void attack(Unit u); } interface Fightable extends Moveable, Attackable { } |
인터페이스의 상속 역시 자손인터페이스는 조상인터페이스의 정의된 맴버를 모두 상속받는다.
(4) 인터페이스의 구현
인터페이스도 인터페이스만으로 인스턴스를 생성할 수 없으며, 자신에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야한다.
그 방법은 추상클래스가 자신을 상속받는 클래스를 정의하는 것돠 다르지 않음.(키워드의 차이)
class 클래스이름 implements 인터페이스이름 {
// 인터페이스에 정의된 추상메서드를 구현해야한다
}
class Fighter implement Fightable { public void move ( int x, int y) { . . . } public void attack (Unit u) { . . . } } |
만일 구현하는 인터페이스의 메서드 중 일부만 구현하면, 추상클래스로 선언되어야 한다.
abstract class Fighter implement Fightable { public void move ( int x, int y) { . . . } // public void attack (Unit u) { . . . } } |
상속과 구현을 동시에 할 수 있다.
class Fighter extends Unit implement Fightable { public void move ( int x, int y) { . . . } public void attack (Unit u) { . . . } } |
[Ex_7_23.java]
public class Ex_7_23 { 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 Moveable){ System.out.println("f는 Moveable인터페이스를 구현했습니다."); } if (f instanceof Attackable){ System.out.println("f는 Attackable인터페이스를 구현했습니다."); } if (f instanceof Object){ System.out.println("f는 Object클래스의 자손입니다."); } } } class Fighter extends Unit implements Fightable { public void move(int x, int y) { /* */ } public void attack(Unit u){ /* */ } } class Unit { int currentHP; int x; int y; } interface Fightable extends Moveable, Attackable { } interface Moveable { void move(int x, int y); } interface Attackable { void attack(Unit u); } |
여기서 주의할 부분은 Moveable인터페이스에 정의된 내용을 FIghter클래스에서 구현할 때, 접근제어자 public를 사용했다는 것이다!
= 오버라이딩 할 떄, 조상의 메서드보다 넓은 범위의 접근제어자를 지정해야한다.
interface Moveable { void move(int x, int y); } |
class Fighter extends Unit implements Fightable { public void move(int x, int y) { /* */ } public void attack(Unit u){ /* */ } } |
(5) 인터페이스를 이용한 다중상속
skip해도 무방
(6) 인터페이스를 이용한 다형성
인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있으며,
인터페이스 타입으로 형변환도 가능
Fightable f = (Fightable) new Fighter(); or Fightable f = new Fighter(); |
따라서 인터페이스는 메서드의 매개변수의 타입으로 사용 가능
void attack (Fightable f) { . . . } |
이는 메서드 호출시, 해당 인터페이스르 구현한 클래스의 인스턴스를 매개변수로 제공해야한다는 것을 의미
class Fighter extends Unit implements Fightable { public void attack (Fightable f) { . . . } } |
이렇게 정의되어야 attack메서드의 매개변수로 Fighter의 인스턴스를 넘겨 줄 수 있다.
void attack (new Fighter()) { . . . } |
또한 메서드의 리턴타입으로 인터페이스의 타입 지정도 가능
Fightable method() { . . . .return new Fighter(); } |
리턴타입이 인터페이스라는 것은
메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 봔환한다는 것을 의미한다.
(7) 인터페이스의 장점
1. 개발시간을 단축시킬 수 있다.
2. 표준환가 가능하다
3. 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
4. 독립적인 프로그래밍이 가능하다.
'Studynote > Computer Science 12' 카테고리의 다른 글
11.11.제11장 컬렉션 프레임윅과 유용한 클래스 (0) | 2018.11.05 |
---|---|
[정리]Java chapter11 컬렉션 프레임웍과 유용한 클래스 (0) | 2018.11.05 |
[정리] Java Chapter 6 객체지향프로그래밍1 (0) | 2018.11.05 |
10.14 제 10장 내부클래스 실습 (0) | 2018.11.05 |
10.14 제 10장 내부클래스 (0) | 2018.11.05 |
댓글