인터페이스는 객체로 생성할 수 없기에 생성자를 가질 수 없다. (/자식 클래스는 객체를 생성할 수 있다.)
자식 클래스에서 추상 메서드를 재정의 해주어야 된다.
🔗 인터페이스 선언
인터페이스 선언은 class 키워드 대신에 interface 키워드를 사용한다.
[public] interface 인터페이스 이름 {...}
public interface RemoteControl{
//상수(static, final)
public int MAX_VOLUME = 10;
public int MIN_VOLUME = 0;
//추상 메소드(abstract로 생성)
public void turnOn();
public void turnOff();
public void setVolume(int volume);
}
🔗 인터페이스 구현
public class 구현클래스이름 implements 인터페이스이름{
//인터페이스에 선언된 추상 메소듸의 실체 메소드 선언
}
① implments로 인터페이스를 구현시킨다.
public class Television implements RemoteControl{ //인터페이스 생성
//상수
private int volume;
//추상 메소드 오버라이드
public void turnOn() {
System.out.println("TV를 켭니다.");
}
public void turnOff() {
System.out.println("TV를 끕니다.");
}
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;
}
System.out.println("현재 TV 볼륨 : "+this.volume);
}
}
② 인터페이스를 구현 후 추상 메소드를 재정의 해준다.
public static void main(String[] args) {
Television tv = new Television();
Audio audio = new Audio();
tv.turnOff();
tv.turnOn();
tv.setVolume(5);
System.out.println();
③ 재정의한 메소드를 호출해준다!
🔗 인터페이스 사용
클래스를 선언할 때 인터페이스는 필드, 생성자, 또는 메소드의 매개 변수, 생성자, 또는 메소드의 로컬 변수로 선언될 수 있다.
public class HkTire implements Tire {
public void roll() {
//Tire 인터페이스 구현
System.out.println("한국 타이어가 굴러갑니다.");
}
}
public class GhTire implements Tire {
public void roll() {
//Tire 인터페이스 구현
System.out.println("금호 타이어가 굴러갑니다.");
}
}
구현 클래스 (roll메소드를 재정의 해준다)
public class Car {
//4개의 HkTire 타입 필드를 가짐
Tire frontLeftTire = new HkTire();
Tire frontRightTire = new HkTire();
Tire backLeftTire = new HkTire();
Tire backRightTire = new HkTire();
void run() {
// 인터페이스에서 설명된 roll() 메소드 호출
frontLeftTire.roll();
frontRightTire.roll();
backLeftTire.roll();
backRightTire.roll();
}
}
필드 타입으로 타이어 인터페이스를 선언하면 필드값으로 한국 타이어 또는 금호 타이어 객체를 대입할 수 있다.
public class CarMain {
public static void main(String[] args) {
Car mycar = new Car();
mycar.run(); //HkTire
//초기갑으로 대입한 구현 객체 대신 다른 구현 객체를 대입할 수 있다.
mycar.frontLeftTire = new GhTire();
mycar.frontRightTire = new GhTire();
mycar.run();
}
}
mycar.frontLeftTire = new GhTire();
mycar.frontRightTire = new GhTire();
GhTIre로 교체된 후에는 GhTire 객체의 roll() 메소드가 호출된다. Car의 run()메소드를 수정하지 않아도 다양한 roll() 메소드의 실행결과를 얻을 수 있다. 이게 바로 필드의 다형성이다.!
🔗 매개 변수의 다형성
매개 변수의 다형성 1) 매개 변수의 타입이 인터페이스일 경우 어떠한 구현 객체도 매개값으로 사용가능 2) 어떤 구현 객체가 제공되느냐에 따라 메소드의 실행결과는 다양해진다.
public class Driver {
public void drive(Vehicle vehicle) { //인터페이스 타입 매개 변수
vehicle.run();
}
}
매개 변수의 인터페이스화
// 인터페이스 생성
public interface Vehicle {
public void run();
}
//구현 클래스 생성
public class Bus implements Vehicle {
public void run() {
System.out.println("버스가 달립니다.");
}
}
public class Taxi implements Vehicle{
public void run() {
System.out.println("택시가 달립니다.");
}
}
public class DriveMain {
public static void main(String[] args) {
Driver driver = new Driver();
Bus bus = new Bus();
Taxi taxi = new Taxi();
driver.drive(bus); //자동 타입 변환 : Vehicle vehicle = bus;
driver.drive(taxi); //자동 타입 변환 : Vehicle vehicle = taxi;
}
}
이렇게 매개 변수를 이용하여 다양한 메소드를 실행할 수 있도록 한다.
🔗 강제 타입 변환
구현클래스 변수 = (구현클래스) 인터페이스변수;
인터페이스 변수를 구현 클래스 변수로 강제타입 변환 시킨다.
public interface Excercise {
public void run();
}
public class Jumprope implements Excercise{
public void run() {
System.out.println("줄넘기를 합니다."); //메소드 오버라이딩
}
public void checkFar() {
System.out.println("심박수를 확인합니다.");
}
}
public class ExcrciseMain {
public static void main(String[] args) {
Excercise ex = new Jumprope();
ex.run();
//jr.checkFar();
Jumprope jr = (Jumprope)ex; //강제 타입 변환
jr.run();
jr.checkFar();
}
}
인터페이스 변수를 구현 클래스 변수로 강제 타입 시켰다.
🔗 중첩 클래스
클래스 내부에 선언한 클래스
두 클래스의 멤버들을 서로 쉽게 접근
코드의 복잡성을 줄임
중첩 클래스는 멤버 클래스와 로컬 클래스로 분류 된다.
멤버 클래스
인스턴스 멤버 클래스
class A{ class B{ ... } }
A객체를 생성해야만 사용할 수 있는 B 클래스
정적 멤버 클래스
class A{ static class B{...} }
A 클래스로 바로 접근할 수 있는 B 클래스
로컬 클래스
class A{ void method(){ class B {...} } }
🔗 인스턴스 멤버 클래스
static 키워드 없이 중첩 선언된 클래스
인스턴스 필드와 메소드만 선언이 가능하다
정적 필드와 메소드는 선언할 수 없다.
class A{
class B{
B() {} //생성자
int field1; //인스턴트 필드
void method(); //인스턴트 메소드
}
}
A 클래스 외부에서 객체 생성하는 법
A a = new A();
A.B b = a.new B();
b.field1 = 3;
b.method();
A 클래스 내부에서 객체 생성하는 법
class A{
class B{...}
void methodA(){
B b = new B();
b.field1 = 3;
b.method1();
}
}
🔗 정적 멤버 클래스
정적 멤버 클래스 : static 키워드로 선언된 클래스, 모든 종류의 필드와 메소드를 선언할 수 있다.
class A{
static class C{
C(){}//생성자
int field; //인스턴스 필드
static int field2; //정적 필드
void method1(){} //인스턴스 메소드
static void methoc2(){} //정적 메소드
}
}
A 클래스 외부에서 정젖ㄱ 멤버 클래스 C의 객체를 생성하려면 A 객체를 생성할 필요가 없다.⬇️⬇️
A.C c = new A.C();
c.field1 = 3; //인스턴스 필드 사용
c.method1(); //인스턴스 메소드 호출
A.C.field2 = 3; //정적 필드 사용
A.C.method2(); //정적 메소드 호출
🔗 로컬 클래스
로컬 클래스 : 중첩 클래스의 메소드 내에서도 선언할 수 있는 클래스 - 접근 제한자 및 static을 붙일 수 없다( 메소드 내부에서만 사용죄기 때문) - 인스턴스 필드와 메소드만 선언가능 - 정적 필드와 메소드는 선언 X
void methoid(){
//로컬 클래스
class D{
D() {} //생성자
int field1;
void method1() {}
} //class D
D d = new D(); //메소드 내에서 객체 생성 및 사용
d.field1 = 3;
d.method1();
}
로컬 클래스는 메소드가 실행될 때 메소드 내에서 객체를 생성하고 사용해야 한다.
🔗 중첩 클래스의 접근 제한
바깥 필드와 메소드에서 사용 제한 - 바깥 클래스에서 인스턴스 멤버 클래스를 사용할 때 제한이 있다.