객체지향을 본격적으로 활용하기 위해, 추상(Abstract)와 인터페이스(interface)의 개념이 존재한다.

  • 자바에서는, 일종의 미완성 클래스라고 할 수 있는 추상(Abstract)클래스를 제공하는데, 추상클래스는 직접적으로 객체(인스턴스)를 생성할 수 없지만,
    < 새로운 클래스(추상클래스를 상속하는 자식 클래스) 를 작성하는데 밑바탕이 되는 역할을 해준다는 것>에 의미가 있다.
    예를 들어, 사각형/ 원/ 삼각형 이라는 클래스는 <공통적으로 넓이()와 모양()>이라는 메소드가 필요하다.
    그것을 반드시 구성할 수 있도록 추상 클래스에 설계해놓고 알려준다.
    - 규칙 : 추상클래스 꼭 상속받아야 하며, 모든 추상메소드는 자식클래스에서 구현이 되어야한다.


[1] 추상의 개념을 이용해서, 음악 플레이어 클래스를 구현해보자.

  1. Player클래스를 만들어보자. 그리고 접근제한자 public 대신 <abstract>로 바꿔서 추상클래스로 바꾸자.
  2. 안에 추상메소드를 넣어줘야한다. 인터페이스처럼 body{}가 없다.3가지 매소드를 넣어주자.
    abstract class Player {
       
         abstract void play(String songName);
         abstract void pause();
        abstract void stop();
  3. }


  4. 메인클래스를 만들고 추상클래스를 상속(extends Player)하자.
    *추상 클래스를 상속했다면, 그 안의 추상 메소드들은 모두 implements해야한다. 오류가 뜨는 것을클릭해서 메소드들을 구현하자.
      -> 오버라이딩 되면서, 추상클래스들의 추상 메소드들이 implements된다.


    @Override
     void play(String songName) {
         // TODO Auto-generated method stub
        
     }

    @Override
     void pause() {
         // TODO Auto-generated method stub
        
     }

    @Override
     void stop() {
         // TODO Auto-generated method stub
        
     }

4. 이제 비어있는, 추상 메소드들을  구현화하자.
     @Override
     void play(String songName) {
         System.out.println(songName+"곡을 재생합니다");       
     }

    @Override
     void pause() {
         System.out.println("곡을 일시정지 합니다");       
     }

    @Override
     void stop() {
         System.out.println("곡을 정지합니다");
     }

5. 메인메소드에서 구현화한 추상메소드들을 이용해보자. 이 때, 그냥 평소 호출하듯이 play("");를 호출하면, 오류가 뜬다. 그 이유는 메인메소드가 static이기 때문이다.
     클래스의 것으로, 클래스에서만 사용할 수 있도록 만든 static 메소드 내부에서는 반드시 호출되는 메소드들도 static이어야만 한다.*****
  ==> 이러한 것을 해결하는 방법으로, 호출하는 메소드에 static을 붙혀줄 수 도 있지만,
      ****< 메인클래스의 객체를 생성한 뒤, 객체.를 이용해서 호출하면 static이 붙은 메인메소드안에서 호출이 가능하다.>****

    public static void main(String[] args) {

        Main main = new Main();
         main.play("따르릉 by 홍진영");
        
     }

6. 다른 메소드 2개도 호출하여 실행해본다.


public class Main extends Player {

    public static void main(String[] args) {

        Main main = new Main();
         main.play("따르릉 by 홍진영");
        
         main.pause();
         main.stop();
        
     }

    @Override
     void play(String songName) {

        System.out.println(songName+"곡을 재생합니다");
        
     }

    @Override
     void pause() {

        System.out.println("곡을 일시정지 합니다");
        
     }

    @Override
     void stop() {

        System.out.println("곡을 정지합니다");

    }

}


[2] 추상의 개념을 이용해서 동물 클래스를 구현해보자.


1. Animal클래스를 만들고, 추상클래스로 바꾸자. 그리고  abstract void crying(); 메소드 하나를 넣어주자.

2. Dog클래스를 만들고 Animal 추상클래스를 상속하자. 추상메소드를 가져와서, 개가 우는 방식으로 구현화하자.

public class Dog extends Animal{

    @Override
     void crying() {
         System.out.println("월 ! 월 !");
     }

}

3. 마찬가지로 Cat 클래스를 만들고 추상클래스를 상속해서, 추상메소드를 구현화해주자.

4. 메인클래스에서, dog/cat객체를 만들어서, crying()을 호출해준다.
  - [1]에서는 메인클래스가 직접 추상클래스를 상속해서 이너메소드로 추상메소드가 오버라이딩 되었다. 하지만 이너메소드이면서 static메소드인 메인메소드에서 nonstatic 이너메소드를 호출 할 수없으니, 메인객체를 만들어서, 외부에서 호출하는 것처럼 만들었다.
    하지만, 이번에는 메인클래스에서 추상클래스를 상속한 것이 아니므로, 메인클래스의 객체를 생성할 필요가 없다.

    public static void main(String[] args) {

        Dog dog = new Dog();
         Cat cat = new Cat();
         dog.crying();
         cat.crying();
        
     }



[정리] 이렇게 추상클래스를 상속함으로써, 반드시 구현화해야하는 추상 메소드들을 알려준다. 사용자는 상속한 자식클래스에서 꼭 implements를 통해 오버라이딩해서 구현화해야하니 , 필요한 메소드들을 미리 알림을 받을 수 있고, 설계적인 측면에서 효율적으로 가져오면서, 안빠트리고 사용할 수 있다.

[1]enum(상수값들의 집합)

 - 프로그램에서 미리 정해놓아야할 값들(상수들)이 존재할 때, 사용한다.

 - 문법 형식 : 


 public enum FoodMenu {

  PIZZA("피자"), KIMCHI("김치), CHIKEN("치킨");

 }

  그외에, 필드 와 생성자를 내부에 가질 수 있다.


 - 실제로는 java.lang.Enum 클래스의 자식 클래스로 생성된다. 많이 쓰는 메소드로 enum변수.name(), ordinal()이 가장 많이 쓰인다.

 - 자동적으로 제공되는 메소드 :  values() - return 타입 : E[]에다가 안에 있는 상수들을 다 뽑아 낼 수 있다 valueOf(String name) - E 타입 하나를 뽑아 낼 수 있다

 - 사용은 Enum명.상수명 을 이용해서 불러와, Enum변수에다가 집어넣어서 --> 보통 swtich -case문에 많이 사용한다. 

    FoodMenu f = FoodMenu.KOREAN

f.na



[2] 가변형 인자(var args) (String... a)

 - 인자값(파라미터, argumen)의 개수를 정하지 않는 것

 - 배열과 같게 취급이 되어, 확장for문  for(String s : a) 형식으로 사용된다.

 - 문법 형식 : 

   public void method(String... a){

for(String s : a) {

System.out.println(s);

}

   }

  인자값이 1개가 됬든, 10개가 됬든, String형 배열에 담겨서 그것들을  확장for문으로 뽑아낼 수 있다.

 - 반드시 마지막 인자값으로 가변형 인자가 들어가야한다. (String a, int b, String... c)


[3] 추상 클래스(abstract Class)

 - class이지만, 객체를 생성할 수 없다. 불완전한 설계도이므로 상속받는 자식클래스에서 객체를 생성해야한다.

 - 추상메소드를 가지는 것은 인터페이스와 동일하다. 하지만 , 필드와 일반메소드들도 가질 수 있는 점에서 인터페이스와 차이가 난다.

 - 목적미리 만들어진 메소드를 자식클래스가 반드시 오버라이딩해서 가지도록 하기위해서이다.(인터페이스가 더 추상적이라 설계적인 측면에서 선호된다)

 

[4] 중첩 클래스(nested class)  : 3가지가 존재한다.

 - 클래스안에 클래스가 들어간다는 의미이다. 

   만약 클래스안의 클래스인데, static이 붙어있으면, static-nested class라 한다.

   만약 클래스안에 들어간 클래스가 static이 없으면, inner class라고 부른다.

   만약, 클래스이름이 없고, 인터페이스를 상속(new Runnable(){})해서 바로 body{}만 있는 것이라면, anonymous - inner class라 부란다




   my) 클래스는 객체를 생성하기 위한 것이다. 만약 static이 붙어서 클래스의 것이 되면, 외부에서 객체생성 못한다.

         대신 클래스 내에서는 객체생성이 가능하다.


  래스안에 클래스(중첩클래스)가 존재하는 것은 3가지 경우이다.

1) static이 붙은 중첩클래스 : 스태틱이 붙어 있으므로, 클래스의 것 => 클래스 내부에서만 객체생성이 가능하다.

2) static이 안붙은 이너클래스스태틱이 안붙어 있으므로, 객체의 것 => 어디서든 객체를 생성해서 사용한다.

3) 클래스의 이름이 없이 인터페이스를 상속한 new Runnable() { } 클래스 : 어노니머스-이너클래스 => 클래스이름이 없고 바로 내부에 실행매쏘드를 가진다.


 - 목적 : 오로지 한 클래스 안에서만 필요한, 클래스(외부에서 객체를 만들필요가 있을 경우)가 필요할 때 사용한다.

  encalsulation이 강화된다. 프로세스가 돌아갈 때, 안쪽 한군데서만 돌아가도록 하고, 메소드를 통해서, 통신만 하도록 하게 하는 것이 강해진다.

 - 가장 많이 쓰이는 곳 : Swing(ui), android에서 이벤트 처리용으로 많이 사용한다.

 

 static-nested class의 static은 소유제한자이며, class의 것이다. 클래스에서 객체를 생성해서 사용한다.

 

public class Outer {

private static class StaticNested { } : static이 붙은 [ 중첩클래스 ]이며, 클래스내에서만 객체가 생성 가능하다.

private class Inner{ } : static이 안붙어 있는, 클래스안의 클래스를  [ 이너클래스 ]라고 한다. static이 안붙었기 때문에, 객체의 것이므로, 객체를 생성해서 사용해야한다.

private Runnable run = new Runnable(){ } : [anonymous - inner class]로, java.lang.패키지에 있는 Runnable이라는 인터페이스이다.

}

- new Runnable( ) { } 이라는 것이 Runnable이라는 인터페이스의 객체를 생성하는 것 처럼 보이지만, 사실은 인터페이스를 상속하고 있는 또다른 클래스를 만드는 과정이다. 그래서 {  }안에는 필드와 메소드가 들어간다. 

  - 인터페이스를 상속받고 있는 클래스이지만, 이름이 없다.

 


 -  중첩클래스의 객체를 생성하는 문법 형식

1)static-nested class(스태틱- 중첩클래스) :  <클래스 내부에서> 클래스명.중첩클래스명  변수 = new 클래스명  .중첩클래스명();

2)inner class(이너 클래스) :   클래스명.이너클래스명  변수 = new 클래스명(). new 이너클래스명(); 

   [ Outer객체 > Inner클래스 ] -- [ Inner객체 ]

3)anonymous-inner class(어노니머스-이너클래스 ) : 인터페이스명  변수 = new 인터페이스명() { 오버라이딩 메소드 };

   - 인터페이스 객체를 생성하는 것이 아니라 인터페이스를 상속하는 어노니머스 이너클래스를 만드는 과정



[5] annotation(애노테이션)

 - 프로그램에 대한 정보를 제공하는 것이다.

 - 목적 : 컴파일러에게 정보제공 / 컴파일 시 자동으로 소스를 만들어줌  /  xml을 생성기능 / 실행시에 검사하기 위해서

 - 활용 : Spring 프레임워크에서 많이 사용된다.


 - 컴파일러에게 정보제공 할 때 쓰이는 방식

  @Deprecated : 더이상 쓰지 말아야할 곳에 쓴다

  @Override : 반드시 오버라이딩 해야할 곳

  @SuppressWarnings : Generics( )를 제대로 사용하지 않았거나, Deprecated된 메소드를 사용할 때 Warning이 발생하는 곳에 막아주는 기능


[6] final

 - 변수 앞에 붙어서 상수로 만들어준다

 - 메소드 앞에 붙어서 자식이 오버라이딩(재정의) 못하게 한다

 - 클래스 앞에 붙어서 자식이 상속할 수 없게 한다.



[7] 실습


1. 메인메소드를 가진, package enumpack, public class TestEnum 를 만들어준다.

(1) 중첩클래스처럼, 내부에 enum을 만들어준다.

     public class TestEnum {

public enum Language{

}

(2) 대문자로 상수를 만들어준다.

KOREAN, ENGLISH, JAPANESE;


(3)[  ctrl+space ] 를 눌러서 생성자를 넣어준다. (사용은 안할 것이다)


(3) 보통 메인함수에서 참조형 변수를 생성한 뒤에 Language.상수명을 넣은 다음, 변수를  switch case문에 넣어서 사용한다.

public static void main(String[] args) {


Language l = Language.ENGLISH;

switch(l) {

case KOREAN : System.out.println("한글입니다."); break;

case ENGLISH : System.out.println("영어입니다 " + Language.ENGLISH); break;

}

}

(4) 이제 enum명. values()를 이용해서 선언한 상수들을 모두 배열에 넣은다음, 확장for문을 이용해 하나씩 꺼내보자.

     for문안에서는 사용된 변수.name()을 상수명을, 변수.ordinal()을 이용해서 index순서도 같이 찍어주자.


for(Language lang : Language.values()) {

System.out.println(lang.name() +"은 "+ lang.ordinal()+"번째 상수입니다.");

}


2. abs패캐지, abstract 클래스를 만들자. 메인함수도 넣어주자.

(1) class앞에 abstract를 추가해주자.

(2) 메소드를 만드는데 반환형 앞에다가 abstract를 넣어줘야한다. 순서바뀌면 안됨.

(3) 인터페이스와는 다르게, 일반메소드도 넣어줄 수 있다. 


package abs;

public abstract class TestAbs {

public abstract void test() ;

 

public void test2() {

System.out.println("추상클래스안의 일반메소드");

}

 

public static void main(String[] args) {


}


}



(4) abs패키지안에, 추상클래스를 상속받을 자식클래스를 만들어주자. [browse]를 눌러서 부모클래스를 TestAbs를 선택해주자. 메인함수도 포함시키자

 - 부모클래스가 추상클래스이므로, 자식클래스가 반드시 오버라이딩 해야하는 매쏘드가 , 자동으로 작성되어있다.


public class TestAbsSub extends TestAbs {


@Override

public void test() {

// TODO Auto-generated method stub


}

(5) 메인메소드에서 사용해보자. 

*** 나는 객체를 생성해서, 변수에 넣고, 변수.메소드()를 호출하지만 , 변수 없이 바로 객체생성후.메소드()를 호출 할 수 있다.

클래스의 메소드를 사용하는 것은 [ new 생성자() ] 의 객체가 메소드를 사용해서 통신


public static void main(String[] args) {


//객체를 생성해서 변수에 넣고 이용하는 방법

TestAbsSub tab = new TestAbsSub();

tab.test();

//객체 생성하자마자 바로 메소드를 이용하는 방법

new TestAbsSub().test();

//부모인 추상클래스의 일반 메소드를, 자식이 사용하기

new TestAbsSub().test2();

}



3. 중첩클래스를 만들어보자.

(1) 클래스안에,  Runnable인터페이스를 상속받는 [이너클래스]를 만들자. -> Runnable인터페이스안의 추상메소드를 상속해야한다.

(2) run()함수안에는 for문으로 0부터 9까지 출력시키는 코드를 넣어주자.


//이너클래스

private class Target implements Runnable {


@Override

public void run() {

for(int i=0;i<10;i++) {

System.out.println("i : "+i);

}

}

}


(3) 메인메소드에서 Target클래스의 객체를 만들자. 하지만 이너클래스는 static 이너클래스인 메인메소드 안에 바로 들어갈 수 없다.

    바깥쪽 TestOuter객체를 만들고 그것을 이용해야한다.

   ***** 이너클래스의 객체는 바로 생성하지 못한다 ==> 현재 바깥 클래스의 객체를 만들고 난 뒤, 변수를 선언할 때는, 클래스명. 을 / 객체를 생성할 때는, 객체명. 을 써서 생성한다.

   ***** [바깥 클래스명].[이너클래스명]  변수명    =    [바깥 클래스 객체]. new [이너클래스명](); 

    왜냐면, 변수 선언은   [설계도 클래스명]이 앞에 오고 / 객체 생성은, [객체]에서 비롯 되기 때문이다.

public static void main(String[] args) {


TestOuter out = new TestOuter();

TestOuter.Target t = out.new Target(); 

}


(4) 쓰레드를 하나 만들어고, 파라미터에는 Runnable인터페이스를 상속한 클래스의 변수를 넣어준다.

    - Runnable 인터페이스의 run()메소드는 쓰레드의 파리미터에 넣어서 실행된다. 그것을 상속한 자식의 run()메소드도 쓰레드에서 실행된다.


Thread th = new Thread(t);

th.start();


(5) anonymous-inner class를 메인함수에서 바로 만들어주자.

     먼저 쓰레드 객체를 생성하고, 파라미터에는 new Runnable() {  }을 만들어준 다음, ctrl+space로 run()매소드를 오버라이딩 하자.


//어노니머스 이너클래스

Thread th2 = new Thread(new Runnable() {

@Override

public void run() {

for(int i=0;i<10;i++) {

System.out.println("i : "+i);

}

}

});

th2.start();


단축키) 

생성자/겟셋터 : 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을 상속하는 무엇이든 그 자리를 차지할 수 있다.


미리 만든 [Person - 이름, 키, 나이, 몸무게 ]클래스를 상속하면, 

아래 자식클래스들[ Student - 학점, 학번, 학년 + (상속)이름, 키,나이,몸무게 ] , [ Teacher - 교직원 번호, 월급, 년차  + (상속)이름, 키,나이,몸무게] 를 만들 때,  상속해서 그 속성을 쓸 수 있다. 불필요한 코드를 줄여서, 효율적으로 코딩할 수 있다.




[1] 부모클래스(4가지 변수)를 만들고 자식클래스(3가지변수 + 부모 4가지 변수)에서 상속해보자.


1. 사람의 특징을 가진 [Person]클래스를 만든다.( private 필드 -> getter/setter -> 생성자 -> 그외 매쏘드 순)

(1) 각각 private로 필드들을 만든다. 

(2) 보안private필드에 접근할 수 있는 get/set()매쏘드를 만든다.(이번에는 한번에 만들 수 있는 자바기능을 이용한다)

  *** 클래스 내부에서 우클릭 > [ Source ]  >  [ Generate getter / setter ]

  cf) 외부에서 꺼내쓰는 int get() / 내부에 입력하는 void set(int x)


(3) 각 필드(private 필드=멤버변수)에 대한 생성자를 만든다.  우클릭 > source > Generate Constructor using Field

 *** 이 때 super()라는 것은, 부모클래스의 생성자를 호출해서 초기화 시키겠다는 의미이다. 

       그러나, Person은 가장 상위 클래스로, 아직 상속한 부모클래스가 없기 때문에, 비어있다.


public class Person {

private String name;

private int age;

private int height;

private int weight;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public int getHeight() {

return height;

}

public void setHeight(int height) {

this.height = height;

}

public int getWeight() {

return weight;

}

public void setWeight(int weight) {

this.weight = weight;

}

public Person(String name, int age, int height, int weight) {

super();

this.name = name;

this.age = age;

this.height = height;

this.weight = weight;

}


}


2. Person이라는 클래스를 상속하는 Student클래스를 만들자.

(1) 클래스를 만들고, extends Person 으로 상속하자.

(2) 학생클래스에 필요한 필드를 만들어주자.

(3) getter/setter를 만들고

(4) 생성자를 만들어주자. 이때, Student클래스에 만든 필드들 이외에, 

    상속한 Person클래스의 필드(name, age, height, weight)들까지 입력되어있다.*******

 - 개발의 편의성을 위해, 자신이 상속한 부모클래스의 필드들까지 한꺼번에 초기화 해주기 위한 것이다.

 - super( 파라미터)부모가 가진 생성자를 호출해서, 초기화 한다는 의미이다.****


public Student(String name, int age, int height, int weight, String studentID, int grade, double gPA) {

super(name, age, height, weight);

this.studentID = studentID;

this.grade = grade;

GPA = gPA;

}

(5) 이제 추가적으로 Student클래스 내부에 show() 라는 매쏘드도 만들어주자. 출력시 get변수명()으로 꺼내쓰자.

  *** 이때 Person클래스 내부 필드인 name을 getName()할 때는, 상속받은 상태이므로 Person.getName()이 아니라 getName()으로 바로 사용할 수 있다.

public void show() {

System.out.println("-----------------------------");

System.out.println("학생 이름 : " + getName());

System.out.println("학생 나이 : " + getAge());

System.out.println("학생 키 : " + getHeight());

System.out.println("학생 몸무게 : " + getWeight());

//위에는 상속받은 Person클래스의 매쏘드를 바로 사용함

System.out.println("학생 학번 : " + getStudentID());

System.out.println("학생 학년 : " + getGrade());

System.out.println("학생 학점 : " + getGPA());

System.out.println("-----------------------------");

}



3. 이제 메인클래스를 만들고 메인함수에서 객체를 만들고, show()매쏘드를 호출해보자.



public class Main {


public static void main(String[] args) {


Student student1 = new Student("조재성", 32, 163, 55, "1111048", 3, 4.1);

Student student2 = new Student("김석영", 31, 167, 47, "1311051", 3, 3.8);

student1.show();

student2.show();

}


}


4. 출력물을 확인해보자.

-----------------------------

학생 이름 : 조재성

학생 나이 : 32

학생 키 : 163

학생 몸무게 : 55

학생 학번 : 1111048

학생 학년 : 3

학생 학점 : 4.1

-----------------------------

-----------------------------

학생 이름 : 김석영

학생 나이 : 31

학생 키 : 167

학생 몸무게 : 47

학생 학번 : 1311051

학생 학년 : 3

학생 학점 : 3.8

-----------------------------


[2] 또하나의 클래스를 만들고 출력해보자. 


1. Teacher클래스를 만들고, extends Person을 해보자.

(1) 3가지 private필드를 만들고 -> 외부에서 접근할 수 있는 public 겟셋터 -> 생성자까지 만들자.

(2) show()함수를 만들어서 3+ 부모4 총 7가지 변수를 출력해주자.


2. 메인클래스 메인함수로 가서, Teacher객체를 만들면서 초기화해주고, 출력도 해보자.

Teacher teacher1 = new Teacher("이숭인", 38, 171, 55, "0000000", 400, 5);

teacher1.show();

------------------

교사 이름 : 이숭인

교사 나이 : 38

교사 키 : 171

교사 몸무게 : 55

교직원 번호 : 0000000

교사 월급 : 400

교사 연차 : 5

------------------



[3]배열을 이용해서 많은 객체들을 관리해보자.


1. Student클래스 객체100개를 배열로 생성하자.

 *** 객체배열을 만들때는, 생성자호출이 아니므로 new Student() [ 배열 ] ; 이 아니라, new Student[ 배열 ]; 로 우항을 적는다.  

     생성자로 초기화하는 것은 따로 해줄 것이다.


Student[] students = new Student[100];


2. for문을 이용해서 100명의 학생들을 모두 [ 생성자를 이용한 초기화 ]를 한번해 해주자. 대신 학번만 다르게 주자.

- 학번은 숫자가 하나의 단어로 인식되는 String 문자열이다. index인 i를 쓰더라도 뒤에 [ + "" ] 로 끝나야한다.( i + "" )


for(int i=0;i<100;i++) {

students[i] = new Student("홍길동 "+i+"번째", 20, 175, 70, i + "" , 1, 4.5 );

students[i].show();

}



3. 출력값 


for(int i=0;i<100;i++) {

students[i] = new Student("홍길동 "+i+"번째", 20, 175, 70, i + "" , 1, 4.5 );

students[i].show();

}



[4] Scanner로 실제 입력을 받아서 객체를 초기화하여, 출력해주자.

1. Scanner 변수를 생성해서, 콘솔창에서 총 학생수를 입력받고, 그 숫자로 배열을 만들자.


Scanner sc = new Scanner(System.in);

System.out.print("총 몇명의 학생이 존재합니까?(배열수) : ");

int number = sc.nextInt();


2. for문을 만들고, 각 학생들마다 입력받을 정보들을 Student클래스의 생성자의 파라미터에서 복사해와서 가져온 뒤

   임시적으로 변수로 선언하여 받은 다음, 생성자로 초기화 해준다.

< 객체 생성시, 생성자로 초기화해줄 파라미터는, 클래스의 생성자부분의 파라미터를 복사해와서 편하게 작성할 수 있다>


(1) Student 클래스에서 생성자의 파라미터에 각 변수들을 복사해오자

public Student(String name, int age, int height, int weight, String studentID, int grade, double gPA)


(2) 그것을 for문 안에 변수선언으로서 수정하자.


for(int i = 0 ; i <number ; i++) {

String name;

int age;

int height;

int weight;

String studentID;

int grade;

double gPA;


}

(3) 출력문 + sc.nextInt() 등 7가지를 만들어서, 각 변수에다 대입해준다.

 *** 이때, String은 sc.nextString()이 아니라 , sc.next()이다! / double 은 sc.nextDouble()


for(int i = 0 ; i <number ; i++) {

String name;

int age;

int height;

int weight;

String studentID;

int grade;

double gPA;


System.out.print("학생의 이름을 입력하세요 : ");

name = sc.next();

System.out.print("학생의 나이를 입력하세요 : ");

age = sc.nextInt();

System.out.print("학생의 키를 입력하세요 : ");

height = sc.nextInt();

System.out.print("학생의 몸무게를 입력하세요 : ");

weight = sc.nextInt();

System.out.print("학생의 학번을 입력하세요 : ");

studentID = sc.next();

System.out.print("학생의 학년을 입력하세요 : ");

grade = sc.nextInt();

System.out.print("학생의 학점을 입력하세요 : ");

gPA = sc.nextDouble();

}


(4) 입력받은 값을 가진 변수들을 이용해서, 생성자를 호출하여 각 배열[i]에 new Student(~ , , , ,~)로 초기화해준다.

*** Student 클래스의 파라미터를 다시 복사해 온 뒤, 자료형을 다 지워주면 쉽게 생성자호출을 할 수 있따.


my) 생성자의 파라미터에 Model타입에 직접 값을 입력해주는 것이 아니라, 생성자의 변수명과 똑같은 변수를 선언한 뒤, 입력받아서 변수에 넣고,

      생성자의 파라미터를 활용해서 자료형만 지워주면, 바로 대입하는 식을 만들 수 있다.


students[i] = new Student(name,age,  height,  weight,  studentID, grade, gPA);



3. 출력도 for문을 써서 show()로 출력해준다.


for(int i = 0; i < number ; i++) {

students[i].show();

}



4. 출력값을 보자.


총 몇명의 학생이 존재합니까?(배열수) : 3

학생의 이름을 입력하세요 : 조재성

학생의 나이를 입력하세요 : 20

학생의 키를 입력하세요 : 19


-----------------------------

학생 이름 : 조재성

학생 나이 : 20

학생 키 : 19

단축키) [Alt + Shift + S ] : 겟셋터/생성자 자동생성해주는 메뉴를 띄운다(안드로이드의 [alt + insert ]와 동일)


객체지향 프로그래밍에 있어서 가장 기본이 되는 것으로, 가장 대표적으로 많이 사용되는 것이 Node클래스이다. 이는 하나의 장소나 위치를 의미할 수 도 있으며 자료구조에서 말하는 이진 탐색트리의 하나의 서브 트리가 될 수도 있다. 

개발프로젝트에서는 종종 Student클래스와 같이 < 하나의 처리할 데이터 단위를 명시> 하는데 사용된다.


클래스는 공장, 객체는 물건이라고 생각하면 좋다.  new Car();와 같이 객체를 만드는 과정을 <인스턴스 화>라고 한다.

클래스에서 만들어진, 사용가능한 변수를 <인스턴스>라 한다.

my) 인스턴스 = 객체형 변수


[클래스 구조 정리]

클래스내부에서는 보안관계상 private으로 변수(필드, 멤버변수)들을 선언한다.

외부에서 접근이 바로 안되므로, public getter/setter를 만든다.

기본적으로 외부에서 객체를 만들 때, 초기화하는 생성자도 만든다.
그외 필요한 메소드를 만든다.




[1] 하나의 점을 의미하는 Node 클래스를 생성하자


1. 이번에는 클래스가 2개가 필요하다. 기존에 만든 Main클래스( 메인함수 포함)을 만들고 + Node라는 클래스도 생성한다.


2. Node클래스에서 private 형 변수 2개를 생성한다( 클래스 필드(멤버변수)는 private으로 생성하는 것이 좋다)

 *** 보안을 굉장히 중요시 하므로, private 형태로 만들어서, < 클래스 외부에서 함부로 변형이 안되도록 만든다>

public class Node {

private int x;

private int y;


}


3. public int getX() 라는 매쏘드를 만들고, return x를 통해 외부에 x를 반환해준다. (get은 외부에서 꺼내는 반환형 get - return private 필드)

 *** [ private 변수 ] 는 자체적으로는 외부에서 접근이 안된다. 대신 [ public 반환형 get 매쏘드 ]를 만들어서  클래스 내부의 

      private필드 x --> 외부에서 꺼내는 get하도록 반환 해주는 매쏘드다.


public int getX() {

return x;

}


4. public void setX(int x)라는 매쏘드를 만들고, x를 받아서 클래스의 필드인 [ private int x = this.x ] 에다가 값을 set해준다. 

   (set은 내부에 넣어주는 void set(파라미터) - this.필드 = 파라미터; )

 ***  [private 변수 ] 에 외부에서 받은 값을 대입해주기 위해서 [public void set (int x) 매쏘드]를 만들어서  외부의 x --> 클래스 내부의 x에 set하도록 입력해주느 매쏘드다.


public void setX(int x) {

this.x = x;

}


5. y도 마찬가지로 복사해서 만들어준다.


6. 이제 생성자를 만들어준다. 이때, this.x, this.y에다가 넘어온 값을 넣어줘야한다.( 생성자는 new 객체 만들 때, 필드 초기화해주는 것)


 - 생성자는 메인함수에서 객체(인스턴스)를 만들어줄 때, 직접 클래스필드(멤버변수)에 값을 넣어 초기화해주는 것이다. 

public Node(int x, int y) {

this.x = x;

this.y = y;

}


7. 파라미터로 Node객체를 받아서, 초기화된 필드 x,y를 기준으로 <중앙좌표를 계산>한 뒤 new Node( x좌표, y좌표)를 만듬과 동시에 를 반환하는 , 

  public Node getCenter(Node other)를 만들어준다.


(1) 자신의 x좌표 [ this.x ] 와  넘어오는 다른 곳의 Node other의 x좌표를 의미하는 [ other.getX() ] 를 더한 뒤 2를 나누어서 중앙 x좌표를 구하고

  * other도 Node클래스의 객체이므로, getX()메소드를 사용할 수 있다.

(2) y도 똑같이 구한 다음

(3) new Node( 중앙x, 중앙y); 객체를 생성함과 동시에, 변수에 안넣어주고 바로 return한다.


public Node getCenter(Node other) {

return new Node(  (this.x + other.getX())/2  ,(this.y + other.getY() )/2 );

}


my)

****** priavate 변수로 클래스 필드의 보안을 만들고, public 외부에서 꺼내는 get() / 내부에 넣어주는 set() 매쏘드를 만들어서 소통하는구나!

****** 생성자는, 필요한 곳에서 객체를 만들때, 클래스 필드(멤버변수)에 값을 넣어 초기화 해주는 것이다.

****** new Car(); 는 기본생성자를 이용한 것이다. 만약 기본생성자가 없다면,, 생성안된다.(안드로이드는 컴파일시 자동생성 되기도 한다)



[2] Node클래스를 이용하여 두 점 사이의 중점을 구하는 프로그램을 작성해보자.


1. 메인함수에서 생성자를 이용해서, 새로운 객체를 만들자. -> one이라는 객체는 생성자를 통해 priavte 변수(필드)인 x와 y에 10, 20을 가지고 있다.

Node one = new Node(10, 20);

2.  two라는 객체를 만들자.

3. 이제 one이라는 node를 기준으로해서 two와의 중앙점을 구하자. getCenter()는 기준Node인 one. getCenter ( 비교할 Node); 로 사용하는 것이다. 그것을 Node result에 넣어주자.

Node one = new Node(10, 20);

Node two = new Node(30, 40);

Node result = one.getCenter(two);

4. result라는 Node객체에서 getX(), getY()를 이용해 좌표들을 출력해보자.


System.out.println("중앙 x : "+ result.getX());

System.out.println("중앙 y : "+ result.getY());




5. 전체코드


[Node.java]

public class Node {

private int x;

private int y;


public int getX() {

return x;

}

public void setX(int x) {

this.x = x;

}


public int getY() {

return y;

}

public void setY(int y) {

this.y = y;

}

public Node(int x, int y) {

this.x = x;

this.y = y;

}

public Node getCenter(Node other) {

return new Node(  (this.x + other.getX())/2  ,(this.y + other.getY() )/2 );

}

}




[Main.java]


public class Main {


public static void main(String[] args) {


Node one = new Node(10, 20);

Node two = new Node(30, 40);

Node result = one.getCenter(two);

System.out.println("중앙 x : "+ result.getX() + " 중앙 y : "+ result.getY());

}


}

+ Recent posts