08인터페이스
08-1 인터페이스
- 코드와 객체가 서로 통신하는 접점 역할
- 개발 코드를 수정하지 않고 사용하는 객체를 변경할 수 있도록 하기 위해 사용
인터페이스 선언
- 물리적 형태는 클래스와 동일
- interface 키워드 사용
[public interface 인터페이스이름 {…}]
- 인터페이스는 상수, 필드, 추상 메소드 만을 구성 멤버로 가진다
- 객체를 생성할 수 없기 때문에 생성자를 가질 수 없다
interface 인터페이스이름{
// 상수
타입 상수이름 = 값;
// 추상 메소드
타입 메소드이름(매개변수, …);
}
상수 필드 선언
- 인터페이스는 데이터를 저장할 수 있는 인스턴스, 정적 필드를 선언할 수 없다
- 상수필드는 선언 가능하며 고정된 값으로 실행 시에 바꿀 수 없다
- public statc final로 선언, 생략해도 자동으로 붙음
- 관례적으로 상수 이름은 대문자로 작성하고 선언과 동시에 초기값 지정
추상 메소드 선언
- 리턴 타입, 메소드 이름, 매개 변수만 기술되고 중괄호{}를 붙이지 않는 메소드
- public abstract 키워드 사용, 생략해도 컴파일 과정에서 자동으로 붙음
인터페이스 구현
- 인터페이스는 구현 클래스가 있어야 하고, 구현 클래스에는 인터페스이에 정의된 추상 메소드와 동일한 메소드가 있어야 한다.
- 구현 클래스에 의해 성성되는 객체를 구현 객체라 한다
구현 클래스
- 인터페이스 타입으로 사용 가능함을 알려주는 implements 키워드를 추가하고 인터페이스 이름을 명시해야한다
- 추상 메소드의 실체 메소드를 선언해야 한다
public class 구현클래스이름 implements 인터페이스이름{
// 인터페이스에 선언된 추상 메소드의 실체 메소드 선언
}
- 인터페이스의 모든 메소드는 기본적으로 public 접근 제한을 갖기 때문에 public 보다 더 낮은 접근 제한으로 작성할 수 없다 public을 생략하면 컴파일 에러가 발생한다
- 구현클래스가 작성되면 new 연산자로 객체를 생성 할 수 있다
- 인터페이스로 구현 객체를 사용하려면 인터페이스 변수를 선언하고 구현 객체를 대입해야 한다
인터페이스 변수;
변수 = 구현객체;
인터페이스 변수 = 구현객체;
다중 인터페이스 구현 클래스
public class 구현클래스이름 implements 인터페이스A, 인터페이스B {
// 인터페이스 A에 선언된 추상 메소드의 실체 메소드 선언
// 인터페이스 B에 선언된 추상 메소드의 실체 메소드 선언
}
인터페이스 사용
- 인터페이스는 개발코드와 구현 객체 사이에서 접점 역할을 한다.
- 클래스를 선언할 때 인터페이스는 필드, 생성자 또는 메서드의 매개 변수, 생성자 또는 메소드의 로컬 변수로 선언될 수 있다.
- 개발 코드는 인터페이스에 선언된 추상 메소드를 호출하고 인터페이스는 구현 객체의 재정의 메소드를 호출한다
08-2 타입변환과 다형성
- 프로그램 개발할 때 인터페이스를 이용했다면, 프로그램 코드는 변함없이 구현 객체를 교체함으로써 실행결과가 다양해지는데 이것이 인터페이스의 다형성이다
자동 타입 변환
- 구현 객체가 인터페이스 타입으로 변환되는것은 자동 타입 변환에 해당한다
- 필드와 매개변수의 타입을 인터페이스로 선언하면 자동 타입 변환을 이용해 실행결과를 다양하게 만들 수 있다.
필드의 다형성
- 클래스 구성 시, 필드값으로 인터페이스의 구현 객체를 대입할 수 있다.
- 객체 생성 후, 초기값으로 대입한 구현 객체 대신 다른 구현 객체를 대입할 수도 있다.
- 이때 클래스 구성 시 필드값으로 넣은 구현 객체와 객체 생성시 대입한 구현 객체가 다르기 때문에 다른 메소드가 호출되어 다른 실행결과를 가지게 된다 이게 필드의 다형성이다
매개 변수의 다형성
- 메소드를 만들 때, 매개 변수를 인터페이스 타입으로 선언하고 호출할 때 구현 객체를 대입하면 대입되는 구현 객체에 따라 메소드 실행 결과가 다양해질 수 있다 이것이 매개 변수의 다형성이다
강제 타입 변환
- 구현 객체가 인터페이스 타입으로 자동 타입 변환하면 인터페이스에 선언된 메소드만 사용 가능하다는 제약 사항이 있다.
- 경우에 따라 구현 클래스에 선언된 필드와 메소드를 사용해야 하는 겅우도 있는데 이때 강제 타입 변환을 해서 다시 구현 클래스 타입으로 변환한 다음 구현 클래스의 필드와 메소드를 사용할 수 있다
객체 타입 확인
- instanceof 연산자를 사용
객체 instanceof 확인할 타입
if(vehicle instanceof Bus){
Bus bus = (Bus) vihicle;
}
09 중첩 클래스와 중첩 인터페이스
09-1 중첩 클래스와 중첩 인터페이스 소개
- 중첩 클래스 : 클래스 내부에 선언한 클래스
- 중첩 클래스를 사용하면 두 클래스의 멤버들을 쉽게 접근 할 수 있고, 다른 불필요한 관계로 인한 코드의 복잡성을 줄일 수 있다
중첩 클래스
- 멤버 클래스 : 클래스의 멤버로서 선언되는 중첩 클래스, 클래스나 객체가 사용 중이면 언제든지 재사용이 가능
- 로컬 클래스 : 생성자 또는 메소드 내부에서 선언되는 중첩 클래스, 메소드를 실행할 때만 사용되고 메소드가 종료되면 없어짐
- 중첩 클래스도 하나의 클래스이므로 컴파일 하면 바이트 코드 파일이 별도로 생성
멤버 클래스
A $ B .class
로컬 클래스
A $1 B .class
* A : 바깥 클래스, B : 멤버 혹은 로컬 클래스
인스턴스 멤버 클래스
- 인스턴스 멤버 클래스는 static 키워드 없이 중첩 선언된 클래스
- 인스턴스 멤버 클래스는 인스턴스 필드와 메소드만 선언이 가능하고 정적 필드와 메소드는 선언할 수 없다
정적 멤버 클래스
- 정적 멤버 클래스는 static 키워드로 선언된 클래스를 말한다. 모든 종류의 필드와 메소드를 선언할 수 있다
로컬 클래스
- 메소드 내에서 선언하는 중첩 클래스
- 접근 제한자(public, private) 및 static을 붙일 수 없다(메소드 내부에서만 사용되므로 접긎 제한이 필요 없음)
- 인스턴스 필드와 메소드만 선언 가능
중첩 클래스의 접근 제한
바깥 필드와 메소드에서 사용 제한
- 바깥 클래스에서 인스턴스 멤버 클래스를 사용할 때 제한이 있다
- static 초기화 블록이나 static 메소드에서는 static 중첩 클래스만 사용할 수 있다.
멤버 클래스에서 사용 제한
- 인스턴스 멤버 클래스 안에서는 바깥 클래스의 모든 필드와 모든 메소드에 접근 가능
- 정적 멤버 클래스 안에서는 바깥 클래스의 정적 필드와 정적 메소드에 접근 가능하지만 인스턴스 필드와 인스턴스 메소드에는 접근 불가능
로컬 클래스에서 사용 제한
- 로컬 클래스에서 메소드의 매개변수나 로컬 변수를 사용할 때, 그 값을 로컬 클래스 내부에 복사(메소드 실행이 끝나면 매개변수와 로컬 변수는 스택 프레임에서 사라지기 때문)해둔다.
- 이러한 이유료 자바7 이전에는 매개 변수나 로컬 변수를 final로 선언할것을 요구했지만 자바8부터는 final 선언하지 않아도 final의 특성을 부여하도록 바뀌었다
중첩 클래스에서 바깥 클래스 참조 얻기
- 중첩 클래스 내부에서 this 키워드를 사용하면 중첩 클래스의 객체 참조가 된다
- 중첩 클래스 내부에서 바깥 클래스의 필드와 메소드에 참조하기 위해서는 바깥클래스.this.필드 혹은 바깥클래스.this.메소드(); 이렇게 사용해야 한다
중첩 인터페이스
- 클래스의 멤버로 선언된 인터페이스를 중첩 인터페이스라 한다
- 인스턴스 멤버 인터페이스와 정적 멤버 인터페이스 모두 가능
09-2 익명 객체
- 익명 객체 : 이름이 없는 객체로 클래스를 상속하거나 인터페이스를 구현해야만 한다
부모클래스 변수 = new 부모클래스() { … };
인터페이스 변수 = new 인터페이스() { … };
익명 자식 객체 생성
- 자식 클래스가 재사용 되지 않는 경우 익명 자식 객체를 생성해서 사용
부모 클래스 [필드|변수] = new 부모클래스(매개값, …){
// 필드
// 메소드
};
- 익명 자식 객체에서 새롭게 정의된 필드와 메소드는 익명 자식 객체 내부에서만 사용되고, 외부에서는 접근할 수 없다
class A {
Parent field = new Parent() {
int childField;
void childMethod(){}
@Override
void patentMethod(){
childField = 3;
childMethod();
}
};
void method() {
field.childField = 3; ← X
field.childMethod(); ← X
field.parentMethod(); ← O
}
}
- 위 코드에서 childField와 childMethod()는 parentMethod() 내에서는 사용이 가능하지만 A클래스의 필드인 field로는 접근할 수 없다
익명 구현 객체 생성
- 특정 위치에서만 구현 클래스를 사용하는 경우에는 익명 구현 객체를 생성해서 사용하는 것이 좋은 방법이다
인터페이스 [필드|변수] = new 인터페이스() {
// 인터페이스에 선언된 추상 메소드의 실체 메소드 선언
// 필드
// 메소드
}
- 중괄호{}에는 인터페이스에 선언된 모든 추상 메소드의 실체 모스드를 작성해야 한다
* 추가로 필드와 메소드를 선언할 수 있지만, 실체 메소드에서만 사용 가능하고 외부에서는 사용불가
익명 객체의 로컬 변수 사용
- 메소드의 매개변수나 로컬 변수를 익명 객체 내부에서 사용할 때, 그 값을 익명 객체 내부에 복사(메소드 실행이 끝나면 매개변수와 로컬 변수는 스택 프레임에서 사라지기 때문)해둔다.
- 이러한 이유료 자바7 이전에는 매개 변수나 로컬 변수를 final로 선언할것을 요구했지만 자바8부터는 final 선언하지 않아도 final의 특성을 부여하도록 바뀌었다
과제
- 기본과제
클래스를 선언할 때 인터페이스는 어떻게 선언될 수 있는지 정리하기(코드 작성해보기)
public interface Book {
public int maxPage = 500;
public int minPage = 0;
public void bookOpen();
public void bookClose();
public void nextPage();
public void prevPage();
public void nowPage(int page);
}
public interface Note {
public void takeNote();
}
public class WepDevelop implements Book, Note{
public int page = 0;
public void bookOpen(){
System.out.println("책을 펼칩니다.");
}
public void bookClose(){
System.out.println("책을 덮습니다.");
}
public void nextPage(){
if(page >= maxPage){
System.out.println("마지막 페이지 입니다");
}else{
System.out.println("다음 페이지로 넘어갑니다.");
page++;
}
}
public void prevPage(){
if(page <= minPage){
System.out.println("첫번째 페이지 입니다");
}else{
System.out.println("이전 페이지로 돌아갑니다.");
page--;
}
}
public void nowPage(int page){
System.out.println("현재 " + page + "페이지 입니다");
}
public void takeNote() {
System.out.println("노트정리를 합니다.");
}
}