자바의 인터페이스에 대해 학습
1. 인터페이스 정의하는 방법
2. 인터페이스 구현하는 방법
3. 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
4. 인터페이스 상속
5. 인터페이스의 기본 메소드 (Default Method), 자바 8
6. 인터페이스의 static 메소드, 자바 8
7. 인터페이스의 private 메소드, 자바 9
Java에서 인터페이스는 클래스가 구현해야 할 메서드의 집합을 정의하는 일종의 계약입니다. 인터페이스를 사용하면 클래스의 기능을 규격화하고 다형성을 구현할 수 있습니다.
public interface 인터페이스이름 {
// 상수 (static final 생략 가능)
타입 상수이름 = 값;
// 추상 메서드 (abstract 생략 가능)
반환타입 메서드이름(매개변수);
// 디폴트 메서드 (Java 8 이후)
default 반환타입 메서드이름(매개변수) {
// 메서드 구현
}
// 정적 메서드 (Java 8 이후)
static 반환타입 메서드이름(매개변수) {
// 메서드 구현
}
// private 메서드 (Java 9 이후)
private 반환타입 메서드이름(매개변수) {
// 메서드 구현
}
}
public interface Animal {
// 상수
int LEGS = 4;
// 추상 메서드
void sound();
// 디폴트 메서드
default void sleep() {
System.out.println("Sleeping...");
}
// 정적 메서드
static void printLegs() {
System.out.println("This animal has " + LEGS + " legs.");
}
// private 메서드 (Java 9 이후)
private void breathe() {
System.out.println("Breathing...");
}
}
클래스는
implements키워드를 사용하여 인터페이스를 구현할 수 있습니다. 인터페이스의 모든 추상메서드를 구현해야만 합니다.
public class 클래스이름 implements 인터페이스이름 {
// 인터페이스의 모든 추상 메서드를 구현해야 함
@Override
public void 메서드이름(매개변수) {
// 메서드 구현
}
}
public class Dog implements Animal {
@Override
public void sound() {
System.out.println("Bark");
}
// 디폴트 메서드 sleep()은 선택적으로 오버라이드 가능
}
인터페이스 타입의 변수를 사용하면 해당 인터페이스를 구현한 클래스의 객체를 참조할 수 있습니다. 이를 통해 다형성을 구현할 수 있으며, 코드의 유연성과 확장성을 높일 수 있습니다.
public interface Animal {
void sound();
void sleep();
}
public class Dog implements Animal {
@Override
public void sound() {
System.out.println("Bark");
}
@Override
public void sleep() {
System.out.println("Dog is sleeping...");
}
}
public class Cat implements Animal {
@Override
public void sound() {
System.out.println("Meow");
}
@Override
public void sleep() {
System.out.println("Cat is sleeping...");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
Animal myCat = new Cat();
myDog.sound(); // "Bark" 출력
myDog.sleep(); // "Dog is sleeping..." 출력
myCat.sound(); // "Meow" 출력
myCat.sleep(); // "Cat is sleeping..." 출력
}
}
Animal 타입의 변수를 사용하여 Dog와 Cat 객체를 참조할 수 있으며, 이를 통해 다형성을 구현합니다. 이렇게 하면 새로운 동물 클래스가 추가되어도 Animal 인터페이스를 구현하기만 하면 동일한 방식으로 사용할 수 있습니다.
인터페이스는 다른 인터페이스를 상속할 수 있습니다. 이 경우 하위 인터페이스는 상위 인터페이스의 모든 메서드를 상속받습니다.
public interface 상위인터페이스 {
void 메서드1();
}
public interface 하위인터페이스 extends 상위인터페이스 {
void 메서드2();
}
여기에서 하위인터페이스는 상위인터페이스를 상속받습니다. 따라서 하위인터페이스는 상위인터페이스의 메서드도 포함하게 됩니다. 구현 클래스는하위인터페이스의 모든 메서드를 구현해야합니다.
public interface Animal {
void sound();
}
public interface Pet extends Animal {
void play();
}
public class Dog implements Pet {
@Override
public void sound() {
System.out.println("Bark");
}
@Override
public void play() {
System.out.println("Playing with the dog...");
}
}
public class Main {
public static void main(String[] args) {
Pet myDog = new Dog();
myDog.sound(); // "Bark" 출력
myDog.play(); // "Playing with the dog..." 출력
}
}
Animal 인터페이스는 sound() 메서드를 선언하고, Pet 인터페이스는 Animal 인터페이스를 상속하여 play() 메서드를 추가로 선언합니다.
Dog 클래스는 Pet 인터페이스를 구현하며, sound()와 play() 메서드를 모두 구현해야 합니다.
이러한 상속 구조를 통해 인터페이스 간의 관계를 정의하고, 코드의 재사용성을 높일 수 있습니다. 특히, 다중 상속을 지원하는 인터페이스를 사용하면 여러 인터페이스를 결합하여 더 복잡한 기능을 가진 인터페이스를 만들 수 있습니다.
public interface Animal {
void sound();
}
public interface Playable {
void play();
}
public interface Pet extends Animal, Playable {
}
public class Dog implements Pet {
@Override
public void sound() {
System.out.println("Bark");
}
@Override
public void play() {
System.out.println("Playing with the dog...");
}
}
public class Main {
public static void main(String[] args) {
Pet myDog = new Dog();
myDog.sound(); // "Bark" 출력
myDog.play(); // "Playing with the dog..." 출력
}
}
Pet 인터페이스는 Animal과 Playable 인터페이스를 동시에 상속받습니다. Dog클래스는 Pet 인터페이스를 구현하며, sound()와 play()메서드를 모두 구현합니다.
이를 통해 Pet 인터페이스는 두 부모 인터페이스의 모든 메서드를 포함하게 됩니다.
Java 8부터 인터페이스는
default키워드를 사용하여 디폴트 메서드를 정의할 수 있습니다. 디폴드 메서드는 인터페이스를 구현하는 클래스에서 선택적으로 오버라이드할 수 있으며, 기본 구현을 제공하므로 구현 클래스에서 반드시 구현할 필요는 없습니다.
public interface Animal {
void sound();
default void sleep() {
System.out.println("Sleeping...");
}
}
public class Dog implements Animal {
@Override
public void sound() {
System.out.println("Bark");
}
// sleep() 메서드는 디폴트 구현을 사용
}
public class Cat implements Animal {
@Override
public void sound() {
System.out.println("Meow");
}
@Override
public void sleep() {
System.out.println("Cat is sleeping...");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
Animal myCat = new Cat();
myDog.sleep(); // "Sleeping..." 출력
myCat.sleep(); // "Cat is sleeping..." 출력
}
}
위 예제에서 Animal 인터페이스는 디폴트 메서드인 sleep()을 제공합니다. Dog 클래스는 이 메서드를 오버라이드하지 않고 디폴트 구현을 사용합니다.
반면 Cat 클래스는 sleep() 메서드를 오버라이드하여 자신만의 구현을 제공합니다.
디폴트 메서드를 사용하면 인터페이스를 확장할 때 기존 코드를 깨지 않고 새로운 메서드를 추가할 수 있습니다.
(인터페이스 추상메서드를 추가하면, 상속받는 모든 클래스에 구현이 추가되어야 하기 때문에...)
Java 8부터 인터페이스는
static키워드를 사용하여 정적 메서드를 정의할 수 있습니다. 정적 메서드는 인스턴스가 아닌 인터페이스 이름을 통해 호출할 수 있으며, 인터페이스의 공통 기능을 제공하는 데 사용될 수 있습니다.
public interface Animal {
void sound();
static void printLegs() {
System.out.println("This animal has 4 legs.");
}
}
public class Main {
public static void main(String[] args) {
Animal.printLegs();
// "This animal has 4 legs." 출력
}
}
위 예제에서 Animal 인터페이스는 printLegs()라는 정적 메서드를 정의합니다. 정적 메서드는 인스턴스 없이 인터페이스 이름을 통해 직접 호출됩니다.
이를 통해 공통 기능을 인터페이스에 정의하고 모든 구현 클래스에서 사용할 수 있습니다.
Java 9부터 인터페이스는
private키워드를 사용하여 프라이빗 메서드를 정의할 수 있습니다.프라이빗 메서드는 인터페이스 내에서만 사용될 수 있으며, 공통 코드의 재사용을 돕습니다.
프라이빗 메서드는 다른 디폴트 메서드나 정적 메서드 내에서 호출될 수 있습니다.
public interface Animal {
void sound();
default void sleep() {
breathe();
System.out.println("Sleeping...");
}
private void breathe() {
System.out.println("Breathing...");
}
}
public class Dog implements Animal {
@Override
public void sound() {
System.out.println("Bark");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
myDog.sleep();
// "Breathing..." 및 "Sleeping..." 출력
}
}
위 예제에서 Animal 인터페이스는 breath()라는 프라이빗 메서드를 정의하고, 이를 sleep() 디폴트 메서드에서 호출합니다.
breathe() 메서드는 외부에서 직접 접근할 수 없고, 인터페이스 내에서만 사용됩니다. 이를 통해 인터페이스 내에서 공통 코드의 재사용이 가능해집니다.
이와 같이 인터페이스는 클래스 간의 결합도를 낮추고, 코드의 유연성과 재사용성을 높이는 데 중요한 역할을 합니다. Java의 다양한 인터페이스 기능을 활용하면 더욱 견고하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.