Part8 인터페이스와 다른 형식의 클래스

인터페이스 만들기

인터페이스: 서로 관계까 없는 물체들이 상호 작용을 하기 위해서 사용하는 장치나 시스템

  • 인터페이스 정의하는 방법
    • 추상 메소드와 상수를 정의 할 수 있다.
    public interface TV{
        public int MAX_VOLUME = 100;
        public int MIN_VOLUME = 0;

        public void turnOn();
        public void turnOff();
        public void changeVolume(int volume);
        public void changeChannel(int channel);
    }
  • 인터페이스에서 변수를 선언하면 컴파일시 자동으로 아래와 같이 바뀐다.
    public static final int MAX_VOLUME = 100;
    public static final int MIN_VOLUME = 0;
  • 인터페이스에서 정의된 메소드는 모두 추상 메소드이다. 위에서 선언된 모든 메소드는 컴파일 시에 다음과 같이 자동으로 변경된다.
    public abstract void on();
    public abstract void off();
    public abstract void volume(int value);
    public abstract void channel(int number);

인터페이스 사용하기

  • 인터페이스 사용하는 방법
    • 인터페이스는 사용할 때 해당 인터페이스를 구현하는 클래스에서 implements 키워드를 이용한다.
    public class LedTV implements TV{
        public void on(){
            System.out.println("켜다");
        }
        public void off(){
            System.out.println("끄다");   
        }
        public void volume(int value){
            System.out.println(value + "로 볼륨조정하다.");  
        }
        public void channel(int number){
            System.out.println(number + "로 채널조정하다.");         
        }
    }
  • 인터페이스가 가지고 있는 메소드를 하나라도 구현하지 않는다면 해당 클래스는 추상클래스가 된다.(추상클래스는 인스턴스를 만들 수 없음)
    public class LedTVExam{
        public static void main(String args[]){
            TV tv = new LedTV();
            tv.on();
            tv.volume(50);
            tv.channel(6);
            tv.off();
        }
    }
  • 참조변수의 타입으로 인터페이스를 사용할 수 있다. 이 경우 인터페이스가 가지고 있는 메소드만 사용할 수 있다.
  • 만약 TV인터페이스를 구현하는 LcdTV를 만들었따면 위의 코드에서 new LedTV부분만 new LcdTV로 변경해도 똑같이 프로그램이 동작할 것이다. 동일한 인터페이스를 구현 한다는 것은 클래스 사용법이 같다는 것을 의미한다.
  • 클래스는 이러한 인터페이스를 여러개 구현할 수 있다.

인터페이스의 default method

JAVA 8이 등장하면서 interface에 대한 정의가 몇 가지 변경되었다.

default 메소드

  • 인터페이스가 default키워드로 선언되면 메소드가 구현될 수 있다. 또한 이를 구현하는 클래스는 default 메소드를 오버라이딩 할 수 있다.
    public interface Calculator {
        public int plus(int i, int j);
        public int multiple(int i, int j);
        default int exec(int i, int j){      //default로 선언함으로 메소드를 구현할 수 있다.
            return i + j;
        }
    }

    //Calculator인터페이스를 구현한 MyCalculator클래스
    public class MyCalculator implements Calculator {

        @Override
        public int plus(int i, int j) {
            return i + j;
        }

        @Override
        public int multiple(int i, int j) {
            return i * j;
        }
    }

    public class MyCalculatorExam {
        public static void main(String[] args){
            Calculator cal = new MyCalculator();
            int value = cal.exec(5, 10);
            System.out.println(value);
        }
    }
  • 인터페이스가 변경이 되면, 인터페이스를 구현하는 모든 클래스들이 해당 메소드를 구현해야 하는 문제가 있다. 이런 문제를 해결하기 위하여 인터페이스에 메소드를 구현해 놓을 수 있도록 하였다.

static 메소드

  • 인터페이스에 static 메소드를 선언함으로써, 인터페이스를 이용하여 간단한 기능을 가지는 유틸리티성 인터페이스를 만들 수 있게 되었다.
    public interface Calculator {
        public int plus(int i, int j);
        public int multiple(int i, int j);
        default int exec(int i, int j){
            return i + j;
        }
        public static int exec2(int i, int j){   //static 메소드 
            return i * j;
        }
    }

    //인터페이스에서 정의한 static메소드는 반드시 인터페이스명.메소드 형식으로 호출해야한다.  

    public class MyCalculatorExam {
        public static void main(String[] args){
            Calculator cal = new MyCalculator();
            int value = cal.exec(5, 10);
            System.out.println(value);

            int value2 = Calculator.exec2(5, 10);  //static메소드 호출 
            System.out.println(value2);
        }
    }

내부클래스

내부 클래스란 클래스 안에 선언된 클래스

어느 위치에 선언하느냐에 따라서 4가지 형태가 있을 수 있다.

  • 첫번째는 클래스 안에 인스턴스 변수, 즉 필드를 선언하는 위치에 선언되는 경우. 보통 중첩클래스 혹은 인스턴스 클래스라고 한다.
    • 내부에 있는 Cal객체를 생성하기 위해서는, 밖에는 InnerExam1의 객체를 만든 후에 InnerExam1.Cal cal -= t.new Cal();과 같은 방법으로 Cal 객체를 생성한 후 사용한다.
    public class InnerExam1{
        class Cal{
            int value = 0;
            public void plus(){
                value++;
            }
        }

        public static void main(String args[]){
            InnerExam1 t = new InnerExam1();
            InnerExam1.Cal cal = t.new Cal();
            cal.plus();
            System.out.println(cal.value);

        }
    }
  • 두번째는 내부 클래스가 static으로 정의된 경우, 정적 중첩 클래스 또는 static 클래스라고 한다.
    • 필드 선언할 때 스태틱한 필드로 선언한 것과 같다. 이 경우에는 InnerExam2 객체를 생성할 필요없이 new InnerExam2.Cal()로 객체를 생성할 수 있다.
    public class InnerExam2{
        static class Cal{
            int value = 0;
            public void plus(){
                value++;
            }
        }

        public static void main(String args[]){
            InnerExam2.Cal cal = new InnerExam2.Cal();
            cal.plus();
            System.out.println(cal.value);

        }
    }
  • 세번째로는 메소드 안에 클래스를 선언한 경우, 지역 중첩 클래스 또는 지역 클래스라고 한다.
    • 메소드 안에서 해당 클래스를 이용할 수 있다.
    public class InnerExam3{
        public void exec(){
            class Cal{
                int value = 0;
                public void plus(){
                    value++;
                }
            }
            Cal cal = new Cal();
            cal.plus();
            System.out.println(cal.value);
        }
      
        public static void main(String args[]){
            InnerExam3 t = new InnerExam3();
            t.exec();
        }
    }
  • 네번째로는 익명클래스가 있다.
    • 아래의 절로 이동하여 설명하겠다!

익명클래스

익명 중첩 클래스는 익명 클래스라고 보통 말하며, 내부 클래스이기도 하다.

    //추상클래스 Action 
    public abstract class Action{
        public abstract void exec();
    }

    //추상클래스 Action을 상속받은 클래스 MyAction
    public class MyAction extends Action{
        public void exec(){
            System.out.println("exec");
        }
    }

    //MyAction을 사용하는 클래스 ActionExam 
    public class ActionExam{
        public static void main(String args[]){
            Action action = new MyAction();
            action.exec();
        }
    }

    //MyAction을 사용하지 않고 Action을 상속받는 익명 클래스를 만들어서 사용하도록 수정해 보도록 하겠습니다.
    public class ActionExam{
        public static void main(String args[]){
            Action action = new Action(){
                public void exec(){
                    System.out.println("exec");
                }
            };
            action.exec();
        }
    }
  • 생성자 다음에 중괄호 열고 닫고가 나오면, 해당 생성자 이름에 해당하는 클래스를 상속받는 이름없는 객체를 만든다는 것을 뜻한다.
  • 괄호 안에는 메소드를 구현하거나 메소드를 추가할 수 있다. 이렇게 생성된 이름 없는 객체를 action이라는 참조변수가 참조하도록 하고, exec() 메소드를 호출한다.
  • 익명클래스를 만드는 이유는 Action을 상속받는 클래스를 만들 필요가 없을 경우이다.
  • Action을 상속받는 클래스가 해당 클래스에서만 사용되고 다른 클래스에서는 사용되지 않는 경우이다.

댓글남기기