[Java] 인터페이스(Interface)와 다형성(Polymorphism)

당당·2023년 4월 24일
0

Java

목록 보기
19/20

https://opentutorials.org/module/4872

📔설명

인터페이스는 말하자면 규제라고 말할 수 있다.
하지만, 이것의 목적은 자유이다!

인터페이스와 다형성을 공부해보자~~!!


🤷🏻‍♀️인터페이스 정의

비극적인 외주

기능 구현을 시간이 없어서 외주를 맡겼다고 생각하자.

더하기 기능이 있는 클래스를 만들어주세요.

라고 했다고 가정하자!

class DummyCal{ //fake class
	public int sum(int v1, int v2) {
		return 3;
	}
}

public class InterfaceApp {

	public static void main(String[] args) {
		// 더하기 기능이 있는 클래스를 만들어주세요.
		DummyCal cal=new DummyCal();
		System.out.println(cal.sum(2, 1));
	}

}

그리고 가짜 클래스를 만들어서 납품해줄 클래스를 기다렸다.

그러나 비극적이게도 납품받은 클래스는 다음과 같았다.

class RealCal{
	public double plus(double v1,double v2, double v3) {
		return v1+v2+v3;
	}
}

우리가 DummyCal로 만든 cal 인스턴스를 RealCal 클래스로 바꾸면 우리가 원하는 sum(2,1)과 plus() 함수의 형식이 맞지않아 문제가 생긴다.

인터페이스!

이러한 문제를 해결해주는 것이 Interface 이다.

외주를 맡길 때 이제 말로 설명하는 것이 아닌, Java의 기능을 통해서 규격을 엄격하게 준수할 수 있도록 유도할 수 있다.

int sum(int v1,int v2);

이러한 형태의 메소드가 필요하는 규칙이다.
이러한 규칙에 이름을 정하는데 Calculable이라고 이름을 붙였다.
그리고 이것은 interface이기 때문에 앞에 interface를 붙인다.

interface Calculable{
	int sum(int v1,int v2);
}

그러면, 이렇게 된다! 그리고 아까 만든 DummyCal 클래스 옆에 implements키워드를 써서 Calculable을 구현한다고 적자.

class DummyCal implements Calculable{ //fake class
	public int sum(int v1, int v2) {
		return 3;
	}
}

이렇게!
여기서 만약 sum함수를 지우거나,
Calculable의 sum 함수와 다른 이름으로 구현해도 컴파일 조차 되지않는다.

즉, interface Calculable은 클래스의 형식을 지정해주는 인터페이스고, 외주에서 납품하는 클래스는 다음과 같게 된다.

class RealCal implements Calculable{
	@Override
	public int sum(int v1, int v2) {
		// TODO Auto-generated method stub
		return 0;
	}
	
}

안에 아무 내용 없을 때 IDE에서 method 생성을 누르면 알아서 만들어준다!

위의 코드에서 return만 수정해주면 된다! return v1+v2;로!

인터페이스를 이용하면 버그는 있을지라도 원하지 않는 형태는 아닐거라는 확신을 할 수 있다.

인터페이스는 약속 또는 클래스의 형태를 규정하는 것이다.

💾인터페이스 형식

하나의 클래스에는 하나의 인터페이스만 올 수 있는가?

자바는 단 하나의 클래스만 상속받을 수 있다.
하지만, 자바는 여러개의 인터페이스를 구현할 수 있다.

위의 소스코드에서 RealCal클래스에 화면에 출력하는 기능도 필요하다고 가정해보자.

추가로, 자바의 인터페이스 이름은 대문자로 시작하고, 형용사를 쓸 때가 많다.

Printable이라는 인터페이스를 만들자.

interface Printable{
	void print();
}
class RealCal implements Calculable, Printable{
	@Override
	public int sum(int v1, int v2) {
		return v1+v2;
	}
	
}

implements Calculable, Printable을 사용하면 RealCal클래스는 두 인터페이스를 모두 구체적으로 구현해야한다.

interface Calculable{
	int sum(int v1,int v2);
}

interface Printable{
	void print();
}

class RealCal implements Calculable, Printable{
	@Override
	public int sum(int v1, int v2) {
		return v1+v2;
	}

	@Override
	public void print() {
		System.out.println("This is RealCal!!!");
	}
	
}

public class InterfaceApp {
	public static void main(String[] args) {
		RealCal cal=new RealCal();
		System.out.println(cal.sum(2, 1));
		cal.print();
	}

}

이제 잘 동작하는지 확인해보자.

잘 동작한다 ^^



인터페이스에 변수

잘 사용하지 않는 기능이지만, 인터페이스에 변수를 정의할 수도 있다.

interface Calculable{
	double PI=3.14;
	int sum(int v1,int v2);
}

인터페이스에서 함수를 정의할 땐 내용을 적지 않았지만,
변수를 정의할 땐 내용을 적는다

이것은 RealCal 클래스가 PI라는 변수를 정의해야 하는 것이 아니라(할 수 없음 어차피), RealCal이라는 클래스가 PI라고 하는 변수의 값인 3.14를 갖게 되는 것이다.

public class InterfaceApp {
	public static void main(String[] args) {
		RealCal cal=new RealCal();
		System.out.println(cal.sum(2, 1));
		cal.print();
		System.out.println(cal.PI);
	}

}

이렇게 실행해보면 3.14가 마지막에 출력되는 것을 확인할 수 있다!


👀다형성(Polymorphism)

다형성이란 하나의 클래스가 여러가지의 얼굴을 가지는 것

위의 소스코드에서 calRealCal 클래스의 인스턴스이고, 데이터 타입은 RealCal이다. 그런데, 이 데이터타입은 클래스를 지정할 수 있고, 클래스가 구현하고 있는 인터페이스를 지정할 수도 있다!

Calculable cal=new RealCal();

cal은 이제 Calculable로서 동작하고, CalculablePI라는 변수와 sum()이라는 메소드로 이루어져있다. Printableprint()라는 메소드는 Calculable의 소속이 아니다. 그러므로,

public class InterfaceApp {
	public static void main(String[] args) {
		Calculable cal=new RealCal();
		System.out.println(cal.sum(2, 1));
		cal.print();
		System.out.println(cal.PI);
	}

}

cal.print()에 빨간 밑줄이 생긴다.

이제는 Printable 데이터 타입으로 바꿔보자.

Printable cal=new RealCal();

이렇게 되면 cal.sum(2,1)cal.PI에 빨간 밑줄이 생긴다.

이걸 이제 어디다가 쓰는지가 중요하다.
기능이 너무 많은 소프트웨어는 좋지 않다. 기능을 배워야하는 부담감이 생기기 때문이다. 그러므로, 나에게 필요한 기능만 보여주면 좋겠다는 것이다.

이것이 바로, RealCal이라는 클래스에 메소드가 1000개라고 생각해보자.
그러면 배워야 할 기능이 너무 많아지는 것이다. 이때, RealCalPrintable 로서 동작하게 한다고 지정하면 Printable에 해당되는 기능을 제외한 나머지 메소드, 변수들은 감춰지는 것이다.

또, RealCal이라는 것을 Printable 기능만 이용하겠다고 지정을 해놓으면, 나중에 다른 클래스 AdvancedPrint라는 것이 생겼다고 가정해보자.

class AdvancedPrint implements Printable{
	@Override
	public void print() {
		System.out.println("This is RealCal!!!");
	}
	
}

이렇게 했을 때,

Printable cal=new AdvancedPrint();

이렇게 원래 RealCal자리에 AdvancedPrint라고 바꿔도, 우리는 예상했던 것 대로 동작할 걸 확신할 수 있게 된다.
즉, 호환성을 보장할 수 있다.

이것이 바로, 인스턴스 앞에 데이터타입을 인터페이스로 지정하는 의미이고,
어떠한 클래스가 데이터타입을 뭘로하느냐에 따라 다양한 얼굴을 가지게 되는 것을 다형성이라 한다.


📰사용설명서 속의 인터페이스

https://docs.oracle.com/javase/7/docs/api/java/io/FileWriter.html

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class FileWriterApp {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		Writer fileWriter=new FileWriter("filewriter.txt");
		
		fileWriter.write("data 1");
		fileWriter.write("data 2");
		fileWriter.write("data 3");
		
		fileWriter.close();
	}

}

자바는 close() 행위를 필요로 하는 모든 클래스가 저 메소드를 똑같은 형태로 구현하도록 강제하기 위해 장치를 가지고 있다.


많은 인터페이스를 구현하고 있는데, 그 중 AutoCloseable이라는 것을 눌러보자!

즉, AutoCloseable이라고 하는 인터페이스는 close()라고 하는 메소드를 강제하고 있다.

인터페이스는 동작 방법을 표준화하는 데에 많이 사용이 되고 있다는 것을 알 수 있다!


🕦이후

Java에서 패키지, enum, abstract, final, 제네릭, Collections Framework 들만 골라서 강의를 들을까 싶다.

+)23.04.25
했으나.. 데이터베이스 강의를 듣고, JDBC를 이용해서 프로젝트를 하나 만들어보려고 한다.

profile
MySQL DBA 신입 지원

0개의 댓글