📚 Study/Java
JAVA :: Test117~Test120_인터페이스(Interface)
bono-hye
2023. 9. 14. 23:32
○ 인터페이스(Interface)
- 완전히 미완성된 채로 남겨져 인터페이스 안에 존재하는 그 어떤 메소드도 몸체(정의부)가 없기 때문에 사실상 실행 부분이 존재하지 않는다.
- 클래스를 위한 템플릿으로써의 기능을 수행하는 추상 클래스의 한 종류이다.
- 인터페이스는 클래스와 달리 다중 상속이 가능하며 인터페이스 자체도 상속된다.
- 기존의 C++ 언어 등에서 지원되는 다중 상속이 사용되는 과정에서 많은 문제점을 노출시켰기 때문에 자바에서는 다중 상속의 개념을 인터페이스라는 개념으로 변형하여 인터페이스를 통해 다중 상속을 구현하는 방법을 지원한다.
- 인터페이스는 상수와 추상 메소드만 가질 수 있으며 인터페이스 안의 메소드들은 접근제어지시자를 명시하지 않아도 『public』으로 설정되어 클래스에서 구현(implements)함으로써 바로 접근이 이루어질 수 있다.
○ 특징
- 추상 클래스의 일종으로 선언만 있고 정의가 없다.
- final 변수는 가질 수 있다. (상수의 개념)
- 인터페이스는 『public static final』 상수만 만들 수 있다.
- 인터페이스를 구현하기 위해서는 『extends』 대신에 『implements』를 이용한다.
- 하나 이상의 인터페이스를 implements 할 수 있다.
- 인터페이스를 implememts 한 클래스는 인터페이스의 모든 메소드를 Overriding 해야 한다.
- 인터페이스가 다른 인터페이스를 상속 받을 수 있으며 이 때, 『extends』 키워드를 사용한다.
- 클래스와 달리 인터페이스는 다중 상속이 가능하다.
○ 『extends』 vs. 『implements』
- 클래스 extends 클래스
- 클래스 extends 추상 클래스
- 인터페이스 extends 인터페이스
- 인터페이스 extends 인터페이스, 인터페이스, ...
- 추상클래스 implements 인터페이스
- 추상클래스 implements 인터페이스, 인터페이스, ...
- 클래스 implements 인터페이스
- 클래스 implements 인터페이스, 인터페이스, ...
▼ Test117
// 인터페이스
interface Demo
{
public static final double PI = 3.141592;
// 인터페이스의 멤버 변수는
// 『static final』을 별도로 명시하지 않아도
// 자동으로 『static final』인 상태~!!! 그래서 아래 public int a = 10;가 가능한 구문
public int a = 10;
// 인터페이스의 메소드는 선언만 가능(정의 불가)
// 자동으로 『abstract』인 상태
//public abstract void print(); → 어차피 인터페이스는 추상 클래스만 가지니까 abstract 안써줘도 된다.
public void print();
/*
{
System.out.println("PI : " + PI); // 인터페이스는 추상 메소드만 있어야 하니 이처럼 정의가 되면 안된다. 선언만 가능
}
*/
}
// 클래스
//class DemoImpl
//class DemoImpl extends Demo //--(Ⅹ) implements 사용해야함
//class DemoImpl implements Demo
// ↓
// 추상 클래스 - 인터페이스를 구현하는 추상 클래스
//abstract class DemoImpl implements Demo
// ↓
// 클래스 - 인터페이스를 구현하는 클래스 (→ print() 메소드 재정의)
class DemoImpl implements Demo
{
@Override
public void print()
{
System.out.println("인터페이스 메소드 재정의...");
}
public void write()
{
System.out.println("클래스에 정의된 메소드...");
}
}
// main() 메소드를 포함하는 외부의 다른 클래스
public class Test117
{
public static void main(String[] args)
{
//Demo ob = new Demo(); //-- 생성 불가~!!!
//-- 인터페이스는 인스턴스를 생성할 수 없음~!!!
//DemoImpl ob = new DempImpl(); //-- 임플리먼트 한 뒤 추상메소드를 재정의하여 추상 메소드가 아니게 되었으니 가능
//-- 인터페이스를 implements 만 한 상태에서는 불가
// print() 메소드(→ 추상 메소드)를 재정의한 후
// abstract 상태에서 벗어난 후 가능
//DemoImpl obTemp = new DemoImpl(); ┐
//Demo ob = (Demo)obTemp; ├ 생성 가능 구문
//Demo ob = obTemp; ┘
// ○ 업 캐스팅
// 인터페이스 객체는 상위 객체
Demo ob = new DemoImpl();
ob.print();
//--==>> 인터페이스 메소드 재정의... ob는 인터페이스이지만 덮어쓴 print
//ob.write(); //--Demo 위상으로 변경했는데 Demo에는 write()메소드가 없음
//--==>> 에러 발생(컴파일 에러)
// ○ 다운 캐스팅
((DemoImpl)ob).write();
//--==>> 클래스에 정의된 메소드...
System.out.println(Demo.PI); //-- static 이기 때문에... static(클래스 변수) → 변수가 선언된 클래스의 모든 인스턴스(객체)가 공유할 수 있는 변수
// static이 선언된 멤버 변수는 객체들 간의 전역변수 처럼 사용될 수 있다
//--==>> 3.141592
System.out.println(Demo.a);
//--==>> 10
//Demo.a = 300; //-- final 이기 때문에...
//--==>> 에러 발생(컴파일 에러)
}
}
▼ Test118
// 인터페이스
interface ADemo
{
public void write();
}
// 인터페이스
interface BDemo
{
public void print();
}
// ※ 인터페이스는 2개 이상을 구현(implements)할 수 있다.
// → 클래스에서 다중 상속이 되지 않는 부분을 보완(보충)하는 개념
// 클래스
//class DemoImpl
//class DemoImpl extends ADemo, BDemo //--(Ⅹ)
//class DemoImpl implements ADemo, BDemo
// ↓
// 추상 클래스 - 두 인터페이스를 구현하는 추상 클래스
//abstract class DemoImpl implements ADemo, BDemo
// ↓
// 클래스 - 두 인터페이스를 구현한 후 → 두 인터페이스의 모든 메소드를 Overriding → 일반 클래스
class DemoImpl implements ADemo,BDemo
{
// JDK 1.5(5.0)에서는 인터페이스 메소드를
// 오버라이딩(Overriding) 할 때
// 『@Override』 어노테이션(annotation)을 사용할 수 없다.
// JDK 1.6(6.0) 이후부터 적용 가능한 문법이다.
// 단, 상속받은 클래스의 메소드를 오버라이딩(Overriding)할 때에는
// JDK 1.5(5.0)에서도 어노테이션(annotation)사용이 가능하다.
@Override
public void write()
{
System.out.println("ADemo 인터페이스 메소드 write()...");
}
@Override
public void print()
{
System.out.println("BDemo 인터페이스 메소드 print()...");
}
}
// main() 메소드를 포함하는 외부의 다른 클래스
public class Test118
{
public static void main(String[] args)
{
// ADemo ob1 = new ADemo(); //-- 인터페이스 → 인스턴스 생성 불가
// BDemo ob2 = new BDemo(); //-- 인터페이스 → 인스턴스 생성 불가
// ADemo, BDemo 인터페이스를 구현(implements)한
// 클래스(→ DemoImpl) 기반의 인스턴스 생성
DemoImpl ob1 = new DemoImpl();
ob1.write();
//--==>> ADemo 인터페이스 메소드 write()...
ob1.print();
//--==>> BDemo 인터페이스 메소드 print()...
// 업 캐스팅
ADemo ob2 = new DemoImpl();
BDemo ob3 = new DemoImpl();
//ob2.print();
//--==>> 에러 발생(컴파일 에러)
//ob3.write();
//--==>> 에러 발생(컴파일 에러)
ob2.write();
//--==>> ADemo 인터페이스 메소드 write()...
ob3.print();
//--==>> BDemo 인터페이스 메소드 print()...
((BDemo)ob2).print();
//--==>> BDemo 인터페이스 메소드 print()...
((ADemo)ob3).write();
//--==> ADemo 인터페이스 메소드 write()...
//-- ※ DemoImpl 클래스가 두 인터페이스(ADemo, BDemo)를 모두 구현했기 때문에
// 이와 같은 처리가 가능하다.
// 만약, DemoImpl 클래스가 두 인터페이스들 중 한 인터페이스만 구현했다면
// 이 구문은 런타임 에러가 발생하는 구문이 된다.
// 다운 캐스팅
((DemoImpl)ob3).write();
//--==>> ADemo 인터페이스 메소드 write()...
}
}
▼ Test119
// 인터페이스
interface Demo
{
public void write();
public void print();
}
// 클래스
//class DemopImpl
// 인터페이스를 구현하는 클래스
abstract class DemopImpl implements Demo
{
@Override
public void write()
{
System.out.println("write() 메소드 재정의...");
}
// public abstract void print(); -- 눈에 보이진 않지만 이렇게 되어 있을 것임.
}
// 클래스
//class DemoimplSub
//class DemoimplSub extends DemoImpl
// 추상 클래스를 상속받은 추상 클래스
//abstract class DemoimplSub extends DemoImpl
// 추상 클래스를 상속받은 클래스
class DemoImplSub extends DemoImpl
{
/*
@Override
public void write()
{
System.out.println("write() 메소드 재정의...");
}
// public abstract void print();
*/
public void print()
{
System.out.println("print() 메소드 재정의...");
}
}
// main() 메소드를 포함하는 외부의 다른 클래스
public class Test119
{
public static void main(String[] args)
{
// Demo ob1 = new Demo();
//-- 인스턴스 생성 불가 → 인터페이스
// DempoImpl ob2 = new DemoImpl();
//-- 인스턴스 생성 불가 → 추상 클래스
DemoImplSub ob3 = new DemoImplSub();
ob3.write();
ob3.print();
//--==>> write() 메소드 재정의...
// print() 메소드 재정의...
}
}
▼ Test120
// 인터페이스
interface ADemo
{
public void write();
}
// 인터페이스
interface BDemo
{
public void print();
}
// 인터페이스
//interface CDemo
// 두 인터페이스 (ADemo, BDemo)를 상속받은 인터페이스
interface CDemo extends ADemo, BDemo
{
// public void write(); ┐
// publie void print(); ┘이 둘도 포함 왜? 상속받았으니까
public void test();
}
// 클래스
// class DemoImpl
// ↓
// 추상 클래스
// 두 인터페이스(ADemo, BDemo)를 상속받은 인터페이스를 구현한 추상 클래스
// abstract class DemoImpl implements CDemo
// ↓
// 클래스
// 두 인터페이스(ADemo, BDemo)를 상속받은 인터페이스를 구현한 후 모든 메소드를 재정의한 클래스
//abstract class DemoImpl implements CDemo
class DemoImpl implements CDemo
{
@Override
public void test()
{
System.out.println("test()...");
}
public void write()
{
System.out.println("write()...");
}
public void print()
{
System.out.println("print()...");
}
}
public class Test120
{
public static void main(String[] args)
{
// 두 개의 인터페이스(ADemo, BDemo)를 상속받은
// 인터페이스(CDemo)를 구현하고
// 해당 인터페이스(CDemo)의 메소드 뿐 아니라
// 상속받은 인터페이스(ADemo, BDemo)의 모든 메소드를 재정의(Overriding)한
// DemoImpl 클래스 기반의 인스턴스 생서
DemoImpl ob = new DemoImpl();
ob.test();
ob.write();
ob.print();
}
}
// 실행 결과
/*
test()...
write()...
print()...
계속하려면 아무 키나 누르십시오 . . .
*/