국비교육(22-23)

17일차(4)/java(19) : Interface

서리/Seori 2022. 10. 30. 15:28

새 프로젝트- Step10_Interface 생성!

 

<Remocon> '인터페이스' 생성

package test.mypac;
/*
 * [ interface ]
 * 
 * - 생성자가 없다 (단독 객체 생성 불가)
 * - 구현된 메소드는 가질 수 없다 (추상 메소드만 가질 수 있다)  
 * - 필드는 static final 상수만 가질 수 있다.
 * - data type의 역할을 할 수 있다.
 * - interface type의 참조값이 필요하면 구현(implements) 클래스를 만들어서 객체를 생성해야 한다. 
 * - 클래스 상속은 단일 상속이지만, 인터페이스는 다중 구현이 가능하다.
 */
public interface Remocon {
	// 필드는 static final 상수만 가질 수 있다.(static final은 생략가능)
	public static final String COMPANY="LG";
			
	//메소드는 추상 메소드만 정의할 수 있다.
	public void up();
	public void down();
}

 

<MyRemocon> class

package test.mypac;

public class MyRemocon implements Remocon{

	@Override
	public void up() {
		System.out.println("채널을 올려요");		
	}

	@Override
	public void down() {
		System.out.println("채널을 내려요");		
	}

}

 

<MainClass01>

package test.main;

import test.mypac.MyRemocon;
import test.mypac.Remocon;

public class MainClass01 {
	public static void main(String[] args) {
		//인터페이스도 data type 역할이 가능하다.
		Remocon r1=null;
		
		//Remocon r2=new MyRemocon(); //인터페이스 단독으로 객세생성 불가
		
		//Remocon 인터페이스를 구현(implements)한 클래스를 이용해서 Remocon type의 참조값 얻어내기
		Remocon r2=new MyRemocon();
		r2.up();
		r2.down();
		//인터페이스의 필드 참조(static final)
		String result=Remocon.COMPANY;
	}
}

 

[ interface ]
- 생성자가 없다. (단독 객체 생성 불가)
- 구현된 메소드는 가질 수 없다. (추상 메소드만 가질 수 있다)
- 필드는 static final 상수만 가질 수 있다.
- data type의 역할을 할 수 있다.
- interface type의 참조값이 필요하면 구현(implements) 클래스를 만들어서 객체를 생성해야 한다.
- 클래스 상속은 단일 상속이지만, 인터페이스는 다중 구현이 가능하다.

 

- 완성된 메소드를 가질 수 없지만, 추상메소드는 만들 수 있다!

 (abstract를 붙일 필요가 없다! 어차피 추상메소드만 만들 수 있기 때문에..)
- 필드는 static final 상수만 가능하다. (수정 불가능)
- 인터페이스명에 바로 . 점을 찍어서쓴다.

- 데이터타입으로 사용 가능. 인터페이스임에도 Remoncon r= null; 형태로 쓸 수 있다.
- 인터페이스를 상속 대신 구현한다고 하며, 여러 개를 함께 구현할 수 있다.

 

- 클래스에서 인터페이스를 상속하여 사용하려면 extend는 쓸 수 없고, implement 를 사용해야 한다.

- extend로는 아예 문법이 성립하지 않는다.

 

- 인터페이스도 추상메소드를 완성시키는 것이 강제된다.
- implements라고 수정한 후 오류부분을 클릭하면 강제 override창이 나온다.

 

- 인터페이스에 . 점을 찍어서 보면 COMPANY 라는 이름의 static final 상수를 볼 수 있다.

- 아이콘에 S, F 로 표시되어 있음!

 

- 현재 부모-자식 관계는 위와 같다.

- 인터페이스의 구현도 클래스의 상속과 같이 부모 타입의 역할을 한다.

 → 인터페이스도 java의 어떤 객체의 다형성에 기여한다.

 

- 다중상속을 받을수는없지만, interface는 여러개 구현이 가능하다.(다중 구현)

- 다중구현을 하면 한 객체의 타입이 다양하게 늘어날 수 있다.

 

- 구현하면 heap영역에 이렇게 2개의 객체만 생성된다.

- Remocon 객체는 생성되지 않는다. 인터페이스이기 때문에! 생성자도 없다.

 단지 저 객체를 리모콘 타입으로 쓸 수 있을 뿐이다.

 

- heap영역에 필드 자체가 만들어지지 않기 때문에 필드가 없다. 

- 단, static 영역에 올라가는 static field는 가질 수 있다.(수정 불가능함)

 

- 추상클래스는 객체가 만들어지지만, 인터페이스는 만들어지지 않는다.

 인터페이스를 구현한 클래스의 메소드 모양만 강제하는 효과가 있을 뿐이다.

→ 틀을 만들어두어서 어떤 객체의 표준을 정하는 것. 인터페이스를 사용하면 표준화가 가능해진다.

 

- 객체의 메소드를 중구난방으로 만드는게 아니라, 모양을 강제해서 표준을 만드는 것이라고 생각하면 된다.

 일종의 거푸집같은 느낌??

ex) 충전 단자라면 삼성=implements usbC / 애플=implements lightening 라는 느낌...

 


 

<MainClass02>

package test.main;

import test.mypac.MyRemocon;
import test.mypac.Remocon;
import test.mypac.TVRemocon;

public class MainClass02 {
	public static void main(String[] args) {
		//다형성 확인
		MyRemocon r1=new MyRemocon();
		Remocon r2=r1;
		Object r3=r1;
		
		//직접 클래스를 test.mypac 패키지에 파일로 만들어서 useRemocon() 메소드를 여기서 호출해 보세요.
		Remocon r=new TVRemocon();
		useRemocon(r);
	}
	
	public static void useRemocon(Remocon r) {
		r.up();
		r.down();
	}
}

 

 

<TVRemocon>

package test.mypac;

public class TVRemocon implements Remocon {

	@Override
	public void up() {
		System.out.println("TV 볼륨을 올려요");
	}

	@Override
	public void down() {
		System.out.println("TV 볼륨을 내려요");
	}

}

- Remocon 인터페이스를 구현하는 TVRemocon 클래스. Remocon의 표준을 따른다.

- Remocon 인터페이스를 구현(implement)하여 override하면 이 객체를 리모콘으로 쓸 수 있다.

 

- TVRemocon 객체를 생성(new)하면서 Remocon 타입으로 받을 수 있다.

 


 

<MainClass03>

package test.main;

import test.mypac.Remocon;

public class MainClass03 {
	//anonymous inner class를 이용해서 interface type의 참조값을 얻어내기
	//static method 안에서 사용해야 되기 때문에 static field로 만들어준다.
	static Remocon r1=new Remocon() {
		
		@Override
		public void up() {
			System.out.println("온도를 올려요");
		}
		
		@Override
		public void down() {
			System.out.println("온도를 내려요");
		}
	};
	public static void main(String[] args) {
		useRemocon(r1);		
		//anonymous local inner class를 이용해서 interface type의 참조값을 얻어내기
		Remocon r2=new Remocon() {			
			@Override
			public void up() {
				System.out.println("속도를 올려요");
			}			
			@Override
			public void down() {
				System.out.println("속도를 려려요");
			}
		};
		useRemocon(r2);
		//메소드 호출하면서 Remocon type을 즉석에서 얻어내서 전달하기
		useRemocon(new Remocon() {			
			@Override
			public void up() {
				System.out.println("고도를 올려요");
			}			
			@Override
			public void down() {
				System.out.println("고도를 내려요");
			}
		});
	}
	
	public static void useRemocon(Remocon r) {
		r.up();
		r.down();
	}
}

- 익명의 inner type을 사용해서 Remocon 타입을 얻어낼 수 있다.

 

- 인터페이스에서 익명의 inner type 자동완성 가능! (ctrl+space)

 

{ } 안은 익명 클래스이고, 클래스면 extends / 인터페이스면 implements 가 생략되어있다고 생각하면 된다.

- (){}; 괄호 앞의 단어가 익명 클래스의 생성자를 호출하는 기능을 한다. (여기서는 Remocon)

 

- r1을 static method 안에서 사용해야 하기 때문에 필드에 static을 붙여준다.

 

- { } 는 익명클래스이면서 메소드 안에서 만들어진 innerClass라서

  anonymous local inner class이다. 

- 참조값을 호출하면서 r2라는 지역변수 안에 넣어 전달하는 방식이다.

 

- Remocon 타입을 즉석에서 얻어내면서 전달하는 방법도 있다.

 (javascript에서 함수를 call하면서 함수를 전달하는 것처럼!)

- r2라는 지역변수를 별도로 생성하지 않아도 된다.

 

useRemocon( new Remocon() {} );

- new Remocon(){} 부분을 아래 useRemocon의 r이라는 매개변수에 바로 전달하는 것이라고 생각하면 된다. 

- useRemocon(){} 안에서 사용될 메소드를 전달하는 것!

 

- 익명 클래스를 사용해서 클래스를 만드는 수고를 덜 수 있다.

 


 

- javascript에서는 함수를 변수 안에 담을 수 있다.
- 이와 다르게 java에서는 메소드가 단독으로 존재할 수 없다. 메소드는 객체 안에 존재해야 한다.
 (함수를 변수에 담는다 해도 타입이 뭔지 알 수 없기 때문에 문법이 성립하지 않는다.)

 

 


 

<Drill>

package test.mypac;

//추상 메소드가 1개인 인터페이스
public interface Drill {
	public void hole();
}

 

<MainClass04>

package test.main;

import test.mypac.Drill;

public class MainClass04 {
	public static void main(String[] args) {
		useDrill(new Drill() {			
			@Override
			public void hole() {
				System.out.println("바닥에 구멍을 뚫어요!");
			}
		});
		
		useDrill(()->{
			System.out.println("천장에 구멍을 뚫어요!");
		});
	}
	
	public static void useDrill(Drill d) {
		d.hole();
	}	
}

- useDrill(()->{}); 구조. javascript와 비슷한 전달식 사용

 

- useDrill(new Drill) 하면서 ctrl+space 해서 자동완성 작성.
- 메소드를 호출하면서 내부에서 사용될 메소드를 전달하는 방식.

useDrill( () -> { } );
{ } 위의 추상메소드 → 그렇기 때문에 {} 안에 override하는 메소드를 작성
( ) 매개변수 부분

- 함수를 함수에 전달하는 느낌! 인터페이스를 전달하는 익명클래스.

 

useDrill(new Drill() {			
    @Override
    public void hole() {
        System.out.println("바닥에 구멍을 뚫어요!");
    }
});
		
useDrill(()->{
    System.out.println("천장에 구멍을 뚫어요!");
});

- 위의 식과 아래 식은 같은 식이다.

- javascript와 비슷한 모양. 메소드가 오직 하나인 경우에만 이렇게 줄여서 쓸 수 있다.
- 객체에 참조값을 만들어서 전달하는 것!

 


 

참고) 다형성 관련!

- ArrayList 설명 링크: 링크 

- ArrayList는 클래스이다. javascript의 [ ] 형태의 array!

 

- 부모타입 클래스를 거슬러 올라가보면 타입이 될수있는 게 4가지 있다. 구현할 인터페이스는 6가지!

→ 총 10가지 종류의 타입으로 사용할 수 있다.

 

- 객체는 arraylist로 생성, 타입은 List Interface 타입으로 가장 많이 쓸 것