단축키) 

생성자/겟셋터 : ALT +SHIFT + S

한줄 삭제 : Ctrl + d

자바독 : ALT+SHIFT+J



[1] 인터페이스(interface)


안드로이드에서 인터페이스는 어떤동작을 듣고 있는 귀이다. 귀를 달아준 뒤 귀에 들릴 때, 행동할 것은 우리가 적어서 한다.


리모콘의 버튼을 누르는 것이 인터페이스이다.  노래방 기계 개발자가 노래목록을 api로 제공하는 것이 인터페이스다.

예를 들어서, 1111을 누르면, 자동으로 노래를 불러온다. 하지만, 리모콘을 눌러도, 안쪽에 캡슐화가 되어있기 때문에 어떻게 돌아가는지는 모른다.


1. 인터페이스의 문법적 특징 

 - final이 붙어 있는 상수가 존재한다.(인터페이스 내부의 필드들은 다 상수다. final이 없다면 생략된 것이다.)

 - 메소드는 선언으로만 이루어진다.(내용(body부분 {  }) 은 비어있고 나중에 인터페이스를 상속하는 곳에서 내용을 채워 사용한다. 

   예를 들어, 안드로이드의 버튼의클릭 리스너는 내용은 비어있다)

 - 모든 상수와 메소드는 public이다.

 - 여러개 상속이 가능하다.

 - 클래스와 달리 객체 생성(new 생성자)은 불가능하다.

   (변수는 생성가능하다. 해당 인터페이스를 상속한 자식 클래스의 객체가 생성된 것을 참조할 수 있다.)

 - 서브클래스(상속받는 자식클래스)는 메소드 내용 구현이 필수적이다.

 - 인터페이스가 인터페이스를 상속할 때는, extends로 상속한다. 클래스가 상속할 때는 implements로 한다.


public interface InterSub extends Inter1, Inter2 { // 인터페이스가 인터페이스를 상속할 때는, extends로 상속한다. 클래스를 상속할 때는 implements로 한다.

public static final int HEIGHT = 768; // 인터페이스에서 필드를 선언하지만, 모두 상수값이 된다.

int width = 1024; // public static final은 생략이 가능하다. 인터페이스에서 선언한 필드는 다 상수다.


public abstract void open(); //인터페이스의 매쏘드는 { }의 내용이 구현되어 있지 않다.

void close(); // 인터페이스의 public abstract는 생략이 가능하다. 인터페이스에서 선언한 [반환형 + 매쏘드()]는 다 내용이 구현되어 있지 않다.


}


* abstract : 메소드의 body{ }가 없는 경우에 붙이게 되는 예약어이다. 인터페이스들의 메소드는 다 abstract를 가지고 있는데 생략되어 있다.

* 나중에 메소드를 추가 혹은 변경 하고 싶다면, 해당 인터페이스를 상속받는 자식 인터페이스를 만드는 것을 추천한다. 

  왜냐하면, 인터페이스는 외부에 공개가 되는 것이다. 전세계 사람들이 open(), close()메소드를 쓰고 있을 것이다. 이것을 변경하면 안된다.


[2] JavaDoc(/**  */)

 -  // 한줄주석, /* */ 여러줄 주석, 그리고 바로 /** */ (안드로이드의 초록색 주석)--> javadoc

 - [api용 문서]로 사용이 된다. (커서를 갖다놓으면 자바독이 바로바로 뜬다)

 - 내용으로는 인터페이스 생성 정보, 메쏘드에 대한 설명 등을 인터페이스를 사용하는 사용자들에게 정보를 제공하는 문서가 된다.


[3] 상속(inheritance)

 - 부모클래스가 자식클래스에게 필드와 메소드를 물려주는 것

 - is a 관계

 - 계층구조도 맨 꼭대기에는 Object라는 클래스가 있다. 모든 클래스는 Object를 상속하고 있다. 모든 클래스는 Object이다.

 - 필드와 메소드만 물려주기 때문에, 생성자는 상속되지 않는다.


[4] 형변환 (Type Casting)

 - Reference Type 변수(참조형 변수, 대문자로 시작하는 클래스 변수)의 type을 변환하는 것이다. ( 실제로 객체가 변하는 것은 아니다)

 - 암시적 형변환 :  

Human h = new Human(); 에서,  new Human();은 <하위계층>인 사람 클래스의 객체를 <참조형 변수>가 받았다

Obeject o = h; 에서, <하위계층>인 사람클래스의 참조형 변수 h는 <상위계층>인 Object클래스의 참조형 변수 o에 형변환(캐스팅)없이 바로 대입 할 수있다

 - 명시적 형변환 :  

Object o = new Human(); 에서, <하위계층>인 사람 객체를 , <상위계층>인 객체의 참조형 변수에 넣었다. 암시적 형변환으로 형변환 없이 바로 작은 것을 큰것에 넣을 수 있다

Human h = (Human) o; 에서, <상위계층>인 Object 클래스의 참조형 변수 o<하위계층>에 넣을 때는, 반드시 형변환을 해줘야한다.


  my) 큰 단위(Object)에 <=====더 작은 단위(human)을  대입할 때는 형변환 캐스팅 없이 암묵적으로

        더 작은단위(Human)에 <==큰 단위(Object)를  대입할 때는, 큰것 앞에다가 ( )로  형변환 캐스팅 해줘야한다.


[5] 오버라이딩(Overriding) - my)부모 메소드 재정의

 - 부모클래스에서 상속받은 메소드를  <현재 클래스에 맞는 형태로 재정의>하는 것이다.

 - ***규칙 : 부모 메소드와 똑같은 선언부를 가진다.(내용만 원하는대로 재정의한다) or 접근제한자가 더 넓은 범위를 써야한다.(부모 protected - > 자식 public or protected)


[6] 다형성(Polymorhism)

- 하나의 객체가 -->  다양한 형태로 모습(부모의 변수 or 자식의변수에 대입)이 변하는되는 것 : 형변환( or 오버라이딩 : 메소드명은 같으나 내용이 재정의 되어있다.)

- 다른 형태인 형변환( or 오버라이딩) 상태에서 처음생성된 해당 객체의 메소드가 실행되는 것 : 다형성

 ex> 오버라이딩 : 부모클래스의 메소드를  자식클래스가 오버라이딩해서 사용한다면, 부모의 메소드와는 전혀 다른 자식의 메소드가 실행된다.

 ex> 형변환 : new 사람() 객체는 동물객체가 될 수 있다.(is a 관계). 이때, 사람객체를 형변환해서 동물객체에 넣고, 동물객체.움직인다()를 호출하더라도,                      new 로 생성한 객체는 사람이다. new뒤에 붙은 객체의 메소드 ,사람객체.움직인다()가 실행된다.


     - new 뒤에 적힌것만 보고 어느계층의 메소드()가 호출되는지 판단하면 된다.******************



Human extends Animal

Monkey extends Animal 상황에서


Animal a = new Animal();

Animal h = new Human(); //작은 것(하위계층)을 대입한, 암시적 형변환

Animal m = new Monkey();// 작은 것(하위계층)을 대입한 암시적 형변환


이때, 메소드를 출력하면

a.move(); // Animal 클래스의 move()메소드가 호출됨

h.move(); // Animal  변수에 담겨있지만, new 뒤의 Human클래스의 오버라이딩 한 move()메소드가 호출

m.move();// Animal 변수에 담겨있지만, new 뒤의 Monkey클래스의 오버라이딩 한 move()메소드가 호출


[7] super 사용( 클래스의 생성자 or 메소드의 오버라이딩 )

 - this는 클래스 자기자신의 객체를 뜻한다. 그래서 this.필드명 을 치면 private한 필드에도 접근이 가능하다.

 - super는 부모 클래스의 객체를 뜻한다. 


 사용방법은 2가지

1. [자식클래스의 버라이딩 된 메소드 안에서] 오버라이딩된 자식메소드가 아닌, <부모클래스 속의 메소드>를 그대로 호출할 때, 메소드 안에 적어준다.  그 뒤에 추가로 재정의 할 수 도 있다.


@overridng

 void move(){

super.move(); //부모클래스객체 super.를 이용해서 부모의 메소드 move()를 그대로 호출한다.

System.out.printlm("사람이 움직인다"); // 추가적으로 자식클래스의 오버라이딩 메소드만의 추가적인 재정의를 더해줄 수 있다.

 }


2. [자식클래스의 생성자를 만들 때], 부모클래스의 필드를 초기화하기 위해, 부모생성자를 호출한다.

 - 모든 생성자의 첫번째 줄에는 부모생성자가 생략되어있다!! 컴파일러가 자동으로 super();를 자동으로 넣어준다.

 public class Human extends Animal {

public Human() {

super(); //자식클래스의 생성자에서는 부모클래스의 생성자를 먼저 호출한다. 없다면 생략된 것이다.

}

 }

  

 - 만약 부모클래스에 <파라미터가 비어있는> 기본생성자가 없고,  <파라미터를 가진 > 사용자정의 생성자( public Human(int height) {  this.height = height }  )를 가지고 있다면

    자식클래스에서는  super();를 생략하면 컴파일 오류가 난다. super( 초기화할 값 );  super ( 10, 20); 등 사용자가 정의한 생성자의 초기값을 파라미터로 넣어줘야한다.







[8] 실습 (javase07)

1. 자바프로젝트의 src> 우클릭 >new> interface를 선택해준다. 패키지명은 song, 인터페이스명은 [ Singable ]로 준다.

 (1) 인터페이스의 필드를 만든다. 인터페이스의 필드는 상수이므로, 대문자로 변수를 선언한다. (상수를 의미하는 public static final이 생략되어있다)

      아래의 상수는 다른 것 같지만 2개 모두 절대 변하지 않는 인터페이스의 상수이다.


String NO_1111= "미안해요";

public static final String NO_1234 = "제발";


 (2)  인터페이스의 메소드를 만든다. public abstract는 생략되어있다. 반환형과 메쏘드( )명, 그리고 파라미터도 하나 넣어준다.


int sing(String songNo);


 * 문법적으로는 완성되었지만 아직 미완성이다. 실제 인터페이스는 외부에 공개가 되어있는 것이므로, JavaDoc을 붙혀줘야한다.


package song;


public interface Singable {

String NO_1111= "미안해요";

public static final String NO_1234 = "제발";


int sing(String songNo);

}



 4. song 패키지에 우클릭해서 Singable 인터페이스를 상속받는 클래스 [ Singer ]를 만든다. 이때, [ add ]버튼을 눌러서 만든 Singable.java 인터페이스를 상속한다. 메인메쏘드도 추가해준다.

 (1) 새롭게 만든 Singer 클래스는 , Singable이라는 인터페이스를 implements(상속)했기 때문에, 인터페이스의 sing()메쏘드를 자동으로 @overridng 하고 있다.

      인터페이스를 상속한 클래스는 반드시 body{}가 없었떤 것을 구현화 해줘야하기 때문이다.

 (2) //TODO 주석은 [Ctrl + D] 로 지워준다.

 (3) song()메소드에는 구현화하는 내용으로, [1] 넘어오는 songNo의 노래를 불렀다고 출력문 + [2] 몇분동안 불렀는지 int 시간을 return 해준다.


5. 메인메소드에서 Singer 객체를 만들어서 참조형변수에 넣어준다.

***(1) 인터페이스 Singable의  new Singable이라는 객체를 생성할 수 없다

        하지만, new Singer객체를 만든 것을, 부모인 인터페이스 Singable의  변수에는 넣을 수 있다.

클래스끼리 만이 아니라, 클래스->인터페이스로 형변환해서 대입해주는 것이 가능하다.( 인터페이스를 클래스가 상속하고 있으니, 인터페이스 객체가 더 상위계층)


Singer s = new Singer();

Singable s1 = s; //클래스끼리만이 아니라, 클래스->인터페이스로 형변환이 가능하다.  인터페이스가 부모이므로, 더 상위계층이라 캐스팅 없이 바로 대입가능


 (2) heap Area의 같은 객체 new Singer()을 공유하는, s.와 s1.을 이용해서 매쏘드를 사용해보자.

s.sing(NO_1111);

s1.sing(NO_1234);


 (3) 출력값 

미안해요노래를 불렀다.

제발노래를 불렀다.


6. Singable 인터페이스는 외부에 공개하는 api이므로, JavaDoc을 붙혀줘야한다. ( 단축키 : ALT+SHIFT+J )

 - 인터페이스 선언부에 커서를 대고, [ALT + SHIFT + J]를 눌러보자.

 - @를 입력하면 자동완성으로 각종 title을 고를 수 있다.

 -  필드, 메소드에도 자바독을 달 수 있다.


package song;


/**

 * @author cho

 * 노래를 부르고, 노래시간을 반환하는 인터페이스

 * @since 2018. 02. 20

 * @version 1.0

 */

public interface Singable {

/** 김건모의 미안해요 자바독*/

String NO_1111= "미안해요";

public static final String NO_1234 = "제발";


/** 메소드에도 자바독을 달 수 있다. 인자값 : 노래번호를 받아서, 노래제목을 출력, 노래시간을 반환하는 메소드

* @param songNo Singable에 선언된 필드값을 노래번호로 넣어라.

* @return 노래한 시간을 반환한다.

*/

int sing(String songNo);

}


 - 자바독을 다 완성하고 난 뒤에는 

    [ 자바프로젝트(jaavase07)  우클릭 ] > [ Export ] >  [java폴더] > [JavaDoc ] 클릭

    [Configure ]버튼을 눌러서 javadoc.exe 위치를 잡아줘야한다 (C:\Program Files\Java\jdk1.8.0_144\bin\javadoc.exe)  > [Finish]

 - 콘솔창에 자바독이 만들어지는 과정이 보인다.

 - 자바프로젝트 > doc폴더가 보인다 > index.html 을 실행해보자. 자세한 설명이 나와있다.

 - 이제 Singer클래스에서 쓰인 인터페이스의 메소드 song()에 마우스를 갖다대변 자세한 설명이 나온다.


7. Singer클래스를 상속받는 BalladSinger를 만들어보자. 메인메소드도 추가해준다.

(인터페이스는 add버튼으로 만들 때 바로 상속가능, 클래스의 상속은 직접 extends 적어줘야한다)


(1) sing메소드를 오버라이딩 하자.  [ sing을 치고, ctrl+space로 자동완성해야지 오버라이딩 할 수 있다]

(2) return super.sing(songNo); 를 보자. 아직 구체적으로 오버라이딩해서 return값을 재정의 안해준다면, 부모의 메소드를 호출해서 return을 미리 채워놨다.

(3) 먼저, super.sing(NO_1111);을 호출하자. [ 생성자가 아닌 메소드 오버라이딩에서의 super는 부모 메소드내용을 그대로 갖다쓴다는 의미이다.]

     참고로, 부모 Singer의 sing()메소드는,, 인터페이스를 구현화 했는데,, 출력문이 이미 존재했다. 또 출력문이 발생할 것이다.

     부모의 sing()메소드는 int 노래시간을 return하므로, int로 받아준다.


int i = super.sing(NO_1111);


(4) return은 부모메소드에서 반환될 값 필요 없이, 10으로 그냥 넣어준다.


public class BalladSinger extends Singer {


@Override

public int sing(String songNo) {


int i = super.sing(NO_1111);

System.out.println(songNo + "란 노래를 발라드싱어가 불러요. ");

return 10;

}


8. BalladSinger의 메인함수에서, Singer객체, BalladSinger 객체 -> 더 상위계층 부모인 Singer 변수에 담아서(암묵적 형변환)  sing()을 호출해보자.

public static void main(String[] args) {


Singer s = new Singer();

Singer s2 = new BalladSinger();

s.sing(NO_1111);

s2.sing(NO_1234);

}


9. 출력값을 확인하면 출력문이 3개 인 것을 알 수 있다.


미안해요노래를 불렀다.

미안해요노래를 불렀다.

제발란 노래를 발라드싱어가 불러요. 


 (1) 첫 줄은, Singer가 Singable인터페이스를 상속한다음, sing()을 구체화하는 과정에서 출력문을 넣었다.

 (2) 2,3번째 줄은, BalladSinger가, Singer를 상속하여 sing()메소드에 이미 출력문1개를 가진 상태에서 , 오버라이딩으로 또 출력문을 하나 더 추가했다.


10. 가장 상위계층인 인터페이스의 Singable 변수에 new Singer();객체와 new BalladSinger();객체를 넣어 형변환시켜서 대입해도 제대로 작동한다. 


Singable s = new Singer();

Singable s2 = new BalladSinger();

s.sing(NO_1111);

s2.sing(NO_1234);




*** 객체 지향의 꽃 : 상위계층의 변수에, 하위계층(자식)들의 객체(new 클래스();)를 암묵적 형변환으로 대입해서도 바로 사용할 수 있다. 

                           어떠한 메소드를 호출한다면, 상위계층의 메소드가 아닌, 생성한 객체의 메소드가 호출된다. 


11. 새로 song패키지에, Excute라는 클래스를 메인함수를 포함해서 만들자. 

    그리고 메소드를 만드는데, 파라미터(인자값)으로 Singable변수 s와, String songNo를 받도록 하고, body{}에다가 s.sing(songNo);로 호출해보자.


void execute(Singable s, String songNo) {

s.sing(songNo);

}


 - Execute 클래스와 <--> Singable만 연결된 것 처럼 보인다. ( Singer나 BalladSinger 클래스와는 상관없어보인다.)

   그러나 파라미터 자리에 Singable 객체가 아니라, 자식인 Singer나 BalladSinger 객체를 넣으면, Singer나 BalladSinger의 sing()이 호출된다.


(1) BalladSinger의 메인함수에서 Execute 객체를 만들고, 변수에 참조해준다. 그리고 e.execute(  ,  );를 호출해준다.

*** 이때, 파라미터에는 Singerable의 변수가 들어가야 하나,  new BalladSinger() 객체를 생성해서 넣어준다.


Execute e = new Execute();

e.execute( new BalladSinger(),Singable.NO_1111);


(2) 실제 실행은 Execute클래스의 execute()메소드에서 Singable 변수 s.sing();으로 호출되지만, 

     Singable 변수 뿐만 아니라 그 자식들인 Singer 객체, BalladSinger객체가 들어와도 아무 상관이 없이 잘 작동하게 된다.

    위에 처럼 BalladSing 객체가 들어간다면, BalladSinger의 sing() 메소드 (출력문2개)가 호출되어 출력된다.


[정리]  전혀 상관없어보이는 클래스의 메소드에 파라미터에다가, (부모의 객체타입) 을 받도록 했다면,

          거기에는 상속하고 있는 (자식객체) 아무거나 넣어도 된다. 메소드를 호출할 때도, 부모의 메소드가 호출 되는 것이 아니라 

          자식이 <인터페이스의 메소드의 내용을 구현화 한것 > 또는 <오버라이딩해서 재정의 한 것>의 메소드가 호출된다.


형변환에 의해서 Singeable을 상속하는 무엇이든 그 자리를 차지할 수 있다.


+ Recent posts