티스토리 뷰

1.    상속( Inheritance )의 개념

-      자식 클래스가 부모 클래스의 멤버를 물려받는 것

-      자식이 부모 클래스를 선택해서 물려받는다.

-      상속 대상 : 부모 클래스의 필드와 메소드 ( 생성자는 물려받지 않는다. )

-      자식 클래스 : 부모 클래스의 필드와 메소드 + 자식 클래스에서 추가한 필드와 메소드

-      상속을 통해서 객체의 다향성을 구현할 수 있다.

-      상속 대상 제한 :

-      1 ) 부모 클래스의 private 접근제한자를 갖는 필드와 메소드는 제외된다.

-      2 ) 부모 클래스가 다른 패키지에 있을 경우, default 접근제한자를 갖는 필드와 메소드도 제외된다.

-      + 자식 클래스일지라도 외부 클래스로 간주되기 때문에 private로 제한된다.

 

2.    클래스 상속 ( extends )

-      Extends 키워드 : 자식 클래스가 상속할 부모 클래스를 지정하는 키워드

-      Extends는 확장된다는 의미로, 자식 클래스가 부모클래스를 상속 받음으로써 확장된다는 의미이다.

-      Ex. public class B extends A { }  : B클래스에서 A클래스를 부모로 지정하여 상속한다.

-      자바에서는 단일 상속(1개의 부모)이 되기에, 부모 클래스를 나열할 수 없다.

 

3.    jar 파일 ( Lombok 설치 )

-      jar 파일이란 : 자바 언어로 만든 압축/해체 프로그램

-      XXXXX.jar 파일 관리 방법 :

-      (1) XXXX.jar 파일의 내용 보기

-        C:\temp> jar tvf XXXX.jar

-      (2) XXXX.jar 파일의 해체(압축풀기)  

-       C:\temp> jar xvf XXXX.jar

-      (3) XXXX.jar 파일의 생성(압축생성)

-       C:\temp> jar cvf XXXX.jar 파일1 파일2 디렉토리1 디렉토리2

-      Lombok agentlibrary jar 파일의 용도는 참조타입 여러 개 중에 class 선언할 때 사용한다.

 

4.    부모 생성자의 호출 ( super ( . . . ) )

-      부모 없는 자식은 없기에, 부모객체가 먼저 생성된 후에 자식객체가 생성되게 된다.

-      부모 생성자 호출 완료 후에 자식 생성자 호출이 완료된다.

-      Ex. DmbCellPhone dmbCellPhone = new DmbCellPhone() ; 일 때,

-      스택 영역에 dmbCellPhone가 생성되고

-      힙 영역에는 부모객체(CellPhone)가 생성된 후에, 자식객체(DmbCellPhone)가 생성된다.

-      Super은 부모생성자로 부모객체의 주소를 들고 있는 키워드이다.

-      부모생성자가 없다면 컴파일 오류가 발생할 수 있다.

-      부모 클래스에 매개변수가 있을 경우에는 필수로 “super();”를 작성해야 한다.

 

5.    다향성의 조건

-       1 ) 부모 / 자식 상속관계를 가져야 한다!

-       2 ) 자식 클래스에서 부모 클래스의 메소드를 재정의(메소드 오버라이딩) 해야 한다.

-       3 ) 자동형변환 조건이 성립되어야 한다.

 

6.    메소드 재정의 ( Over ride )

-      부모 클래스의 상속 메소드를 수정해 자식 클래스에서 재정의 하는 것이다.

-       + 오버 로딩과 오버 라이딩은 서로 다른 것이기에 구분해야 한다.

-      메소드 재정의 조건 :

-      1 ) 부모 클래스의 메소드와 동일한 시그니처를 가져야 한다.

-      2 ) 부모의 접근 제한자보다 더 강하게는 오버 라이딩이 불가능 하다.

-       + defaultpublic으로 바꾸는 것은 가능하지만, publicdefaultprivate로 변경하는 것을 불가능 하다. ( 주로 똑같이 사용하기는 한다. )

-      3 ) 새로운 예외(버그) throws 불가능하다.

-      메소드 재정의는 부모 클래스에서 상속받은 메소드에서만 가능하다!

-      요약 :

-      1. 부모 / 자식 관계이어야 한다!!

-      2. 부모에게서 상속받은 메소드의 껍데기는 그대로 받아서, 중괄호 { } 블록 내에서만 재정의 한다.

-      @Override 어노테이션 ( 메소드 재정의 )

-       : 컴파일러에게 부모 클래스의 메소드 선언부와 동일한지 검사를 지시한다.

-       : 정확한 메소드 재정의를 위해 붙여주면 된다.

-      메소드 재정의 효과 : 부모의 오리지날(원래) 메소드가 숨겨지는 효과가 발생하고 재정의된 자식 메소드가 실행된다.

 

7.    다형성 ( polymorphism )

-      같은 부모 타입이지만, 부모타입에 대입된 자식객체가 부모타입의 선언된 메소드를 재정의한 경우 다양한 객체를 대입하는 것이 가능한 성질

-      이때 다양한 성질은 부모타입의 메소드를 수행했을 때 대입된 자식객체의 재정의된 다양한 성질을 의미하며, 이를 통해 다양한 결과가 나오는 이 성질을 다형성이라고 한다.

-      부모 타입에는 모든 자식 객체가 대입 가능하다.

-      자식 타입은 부모 타입으로 자동타입 변환된다.

-      Ex. 자동차는 타이어 타입으로 한국 타이어와 금호 타이어를 사용하지만, 각 타이어의 성능은 다르게 나온다. 하지만 금호타이어나 한국 타이어는 타이어 타입이 정한 규격을 지켜야 한다.

-      부모타입 변수명 = new 자식타입 ( ) ;

 


01. 과제 8 - 펙토리얼 구하기!

 

package homeworks;

 

public class Factorial {

      

       /**

        *

        * 과제 8 - factorial 구하기

        *

        * (1) n! -> n factorial

        *

        * if n = 2, 2! = 2x1

        * if n = 3, 3! = 3x2x1

        * if n = 7, 7! = 7x6x5x4x3x2x1

        *

        * (2) n!에서 n의 숫자가 몇일 때, 여러분 pc로 답이 안나오는지 알려주세요!

        *

        *  for / while / 구글링 ( self information )

        * 

        *  배운 것을 기반으로 완성시켜 보시오!

        * 

        *  코드를 다양하게 작성해서 제출해 보기.

        * 

        *  결과가 나오는데 걸리는 시간을 측정해 보시오.

        * 

        *  */

      

       public static long Factorial ( long x ) {

            

             long result1 = 1l; // 팩토리얼의 결과 값

            

             for ( long i = 1l; i<= x; i++) {

                   

                    result1 = result1 * i;

                   

             } // for

            

             System.out.println (x + "! = " + result1);

            

             return result1;

            

       } // static

      

       public static void main (String[] args) {

            

             for ( long i = 1l; i <=100; i ++) {

                   

                    if( Factorial(i) < 0) {  // 여기에서 factorial은 리턴값만이 아니라 메소드가 불러오기에 출력이 된다.

                           System.out.println( i + "번째서부터 오류가 납니다!" );

                           break;

                    } // if - break

                   

             } // for

            

//           출력 결과 :

            

//                         1! = 1

//                         2! = 2

//                         3! = 6

//                         4! = 24

//                         5! = 120

//                         6! = 720

//                         7! = 5040

//                         8! = 40320

//                         9! = 362880

//                         10! = 3628800

//                         11! = 39916800

//                         12! = 479001600

//                         13! = 6227020800

//                         14! = 87178291200

//                         15! = 1307674368000

//                         16! = 20922789888000

//                         17! = 355687428096000

//                         18! = 6402373705728000

//                         19! = 121645100408832000

//                         20! = 2432902008176640000

//                         21! = -4249290049419214848

//                         21번째서부터 오류가 납니다!

            

       } // main

 

} // end class

 

02. lombok과 부모자식관계

 

package Practice;

 

//@NoArgsConstructor // 어노테이션마다 위치가 지정되어있는 것이 있을 수 있으니 확인해봐야 한다.

public class CellPhone { // 전화기

      

       // @NoArgsConstructor는 바이트 코드를 직접 조작해서 클래스의 멤버를 만들어 준다.

       // lombok이 기본생성자를 생성해 준다.

      

       // 1. 고유속성 필드

       String model;

       String color;

      

      

       // 2. 생성자 -> 자바 컴파일러의 default constructor

      

       public CellPhone() {

            

//           this.model = model;

//           this.color = color;

//          

             System.out.println("CellPhone() invoked"); // --- > 부모 객체가 자식 객체보다 먼저 생성됨을 알 수 있다.

            

       } // default constructor를 생성하면 컴파일 오류가 발생하게 된다.

//     --- > 그 이유는 lombok이 바이트 코드를 조작하여 생성자를 직접 생성하였기에 생성자가 중복되었기 때문이다.

      

       // 위와 같이 매개변수가 있을 경우에는 super();를 활용하여 자식클래스에 생성해 줘야 한다!! (**)

      

       // 만약 부모 클래스 생성자가 없을 경우에는 super();를 직접 입력하지 않아도, 자식클래스에서 사용이 가능하다. (***)

      

       public CellPhone(String model) {

            

             System.out.println("CellPhone(String model) invoked");

            

             this.model = model;

            

       } // overRoading 1

      

       public CellPhone(String model, String color) {

            

             System.out.println("CellPhone(String model, String color) invoked");

            

             this.model = model;

             this.color = color;

            

       } // overRoading 2

      

      

       // 3. 메소드

       void powerOn() {System.out.println("전원을 킵니다.");}

       void powerOff() {System.out.println("전원을 끕니다.");}

      

       void bell() {System.out.println("벨이 울립니다.");}

      

       void sendVoive(String message) {System.out.println("자신 : " + message);}

       void receiveVoice(String message) {System.out.println("상대방 : " + message);}

      

       void hangUp() {System.out.println("전화를 끊습니다.");}

 

} // end class


package Practice;

 

import lombok.AllArgsConstructor;

import lombok.NoArgsConstructor;

 

@NoArgsConstructor

@AllArgsConstructor // 모든 필드를 갖는 생성자를 만들어주지만, 이때 상속관계는 고려하지 않는다.

// 지금은 필드가 int 1개 분이기에 DmbCellPhone(int)가 생성된다.

public class DmbCellPhone extends CellPhone { // 부모자식 관계 (****)

      

       // 1. 필드

       int channel;

      

       // 2. 매개변수가 있는 생성자

      

       DmbCellPhone (String model, String color, int channel) {

            

             // super()로 부모객체의 생성자를 출력해 보자!

            

//           super(); // OK!

            

//           super("model","color"); // OK! (******)

             // 매개변수가 있는지 확인하고, 있으면 값을 입력해줘야 한다.

             // 매개변수가 없을 경우에는 super();을 생성하지 않아도 괜찮다.

             // 매개변수가 없을 경우에는 컴파일러가 자동으로 super();을 넣어주기 때문이다.

            

             // 부모 객체가 자식객체보다 먼저 생성되어야 하기에, 부모 객체를 자식객체보다 먼저 초기화되어야 하기에

             // 밑의 위치에서는 생성이 불가능하지만 앞의 위치에는 가능한 것이다.

            

             super(model,color);  // (****)

             // 부모의 객체를 완전히 초기화하기 위해서 super();이 아니라 super(model,color);로 작성하였다.

             // 부모 객체의 초기화는 super();을 통해 이루어져야 한다.

             // 이 방법으로 초기화를 해야하는데, 부모객체에서 오버로딩을 한 후

             // 자식객체에서 필요에 따라 초기화할 필요가 있다.

            

             System.out.println("DmbCellPhone (String model, String color, int channel) invoked");

            

             // 부모 초기화

//           this.model = model; // model color의 필드가 자식에게는 없지만 부모에게 있기에 사용이 가능하다.

//           this.color = color; // model color의 상속이 이루어진 것이다.

             // 사실 부모 객체는 super을 통해서 초기화시켜 줄 수 있도록 해야 한다.

            

             // 자식 초기화

             this.channel = channel;

            

//           super(); // 이 위치에서는 컴파일 오류가 발생한다.

            

             System.out.println("\t + 1. this(자식객체의 주소) : " + this);

//           System.out.println("\t + 2. super(부모) : " + super);

            

       } // constructor

      

       // 메소드도 상속받은 상태이다.

       // 부모자식관계는 Type Hierachy에서 볼 수 있다.

      

       // 3. 메소드

      

       void turnOnDmb() {

             System.out.println("채널" + channel + " DMB 방송 수신을 시작합니다.");

       } // turnOnDmb

      

       void changeChannel(int channel) {

            

             this.channel = channel;

             System.out.println("채널 " + channel + "번으로 바꿉니다.");

            

       } // changeChannel

      

       void turnOffDmb() {

            

             System.out.println("DMB 방송 수신을 멈춥니다.");

            

       } // turnOffDmb

      

} // end class


package Practice;

 

public class DmbCellPhoneExample {

      

       public static void main (String [] args) {

            

             // 1. 자식 DmbCellPhone 객체 생성

            

             DmbCellPhone dmbCellPhone = new DmbCellPhone("자바폰", "로즈골드",10);

            

             // 2. CellPhone으로부터 상속 받은 필드를 사용가능 한가? - 상속재산은 전부 내꺼!!

            

             System.out.println("모델 : " + dmbCellPhone.model);

             System.out.println("색상 : " + dmbCellPhone.color);

            

             // 3. 자식 클래스에서만 선언된 DmbCellPhone의 필드의 사용 - 당연히 OK!!

            

             System.out.println("채널 : " + dmbCellPhone.channel);

            

             // 4.

            

             dmbCellPhone.powerOn();

             dmbCellPhone.powerOff();

             dmbCellPhone.sendVoive("여보세요!");

             dmbCellPhone.receiveVoice("안녕하세요! 저는 민주인데요!");

             dmbCellPhone.sendVoive("반갑습니다!");

             dmbCellPhone.hangUp();

            

             // 5.

            

             dmbCellPhone.turnOnDmb();

             dmbCellPhone.changeChannel(12);

             dmbCellPhone.turnOffDmb();

            

       } // main

 

} // end class

 

03. 상속 - 재정의

 

package Practice;

 

public class Calculator01 {

      

       double areaCircle ( double r ) {

            

             System.out.println("Calculator01::areCircle(r) invoked.");

//           Calculator01::areCircle(r)의 의미는 Calculator01객체의 areCircle(r)이라는 의미이다.

            

             return 3.14159 * r * r;

            

       } //areaCircle

      

 

} // end class


package Practice;

 

public class Computer extends Calculator01 {

      

       @Override

       double areaCircle (double r) {

            

             System.out.println("Computer::areaCircle(r) invoked");

            

             return Math.PI * r * r;

            

       } // areaCircle

      

       // 이렇게 재정의 하면 Calculator01.areacircle해도 부모클래스 메소드가 아닌 자식 클래스에서 재정의 된 메소드가 실행된다.

 

} // end class


package Practice;

 

public class ComputerExample {

      

      

       public static void main(String [] args) {

            

             int r = 10;

            

             Calculator01 calculator = new Calculator01();

            

             System.out.println("1. 원면적 : " + calculator.areaCircle(r));

             // 결과 : Calculator01::areCircle(r) invoked. 1. 원면적 : 314.159

             System.out.println();

            

//           ===========================================================================

            

             Computer computer = new Computer();

            

             System.out.println("2. 원면적 : " + computer.areaCircle(r));

             // 결과 :Computer::areaCircle(r) invoked  2. 원면적 : 314.1592653589793

             System.out.println();

            

//            ============================================================================

            

       } // main

 

} // end class

 

04. 상속 - 재정의 2

 

package Practice;

 

public class Airplane {

      

       public void land() {

             System.out.println("Airplane::land() invoked");

       } // land

      

       public void fly() {

             System.out.println("Airplane::fly() invoked");

       } // fly

      

       public void takeOff() {

             System.out.println("Airplane::takeOff() invoked");

       } // takeOff

 

} // end class


package Practice;

 

public class SupersonicAirplane extends Airplane {

      

       // 1. 불변의 진리값 (상수) 선언 : 공용으로 사용

      

       public static final int NORMAL = 1;

       public static final int SUPERSONIC = 2;

      

       public int flyMode = NORMAL; // 비행모드 : NORMAL / SUPERSONIC

      

       @Override

       public void fly() {

             System.out.println("SupersonicAirplane::fly() invoked");

            

             if(flyMode == SUPERSONIC) {

                    System.out.println("초음속 비행중입니다.");

             } else {

                    super.fly();

             } // if -else

            

       } // fly

 

} // end class


package Practice;

 

public class SupersonicAirplaneExample { // 재정의

      

       public static void main ( String[] args) {

            

             SupersonicAirplane sa = new SupersonicAirplane();

            

             sa.takeOff(); // 이륙

             sa.fly(); // 비행

            

             sa.flyMode = SupersonicAirplane.SUPERSONIC; // 초음속 모드로 변경

             sa.fly(); // 비행

            

             sa.flyMode = SupersonicAirplane.NORMAL; // 정상 모드로 변경

             sa.fly(); // 비행

            

             sa.land(); // 착륙

            

//           ===========================================================================

            

             // 결과

            

             /*

              *

              *

             Airplane::takeOff() invoked

             SupersonicAirplane::fly() invoked

             Airplane::fly() invoked

             SupersonicAirplane::fly() invoked

             초음속 비행중입니다.

             SupersonicAirplane::fly() invoked

             Airplane::fly() invoked

             Airplane::land() invoked

             *

             *

             **/

 

            

       } // main

 

} // end class

 

05. 상속 - 오버라이딩을 통한 재정의 3

 

package Practice;

 

import lombok.NoArgsConstructor;

 

@NoArgsConstructor

public class Animal {

      

       public void sound() {

             System.out.println("Animal::sound() invoked.");

       } // sound

 

} // end class


package Practice;

 

import lombok.NoArgsConstructor;

 

@NoArgsConstructor

public class Dog extends Animal {

      

       @Override

       public void sound() {

            

             System.out.println("Dog::sound() invoked.");

             System.out.println("멍멍!!");

            

       } // sound

     

} // end class


package Practice;

 

import lombok.NoArgsConstructor;

 

@NoArgsConstructor

public class Cat extends Animal {

      

       @Override

       public void sound() {

            

             System.out.println("Cat::sound() invoked.");

             System.out.println("냐옹!!");

            

       } // sound

     

} // end class


package Practice;

 

import lombok.NoArgsConstructor;

 

@NoArgsConstructor

public class Cat extends Animal {

      

       @Override

       public void sound() {

            

             System.out.println("Cat::sound() invoked.");

             System.out.println("냐옹!!");

            

       } // sound

      

} // end class


package Practice;

 

public class App { // 오버라이드를 통한 다형성 (****)

      

       public static void main (String[] args) {

            

             // 다형성 1 : 상속관계의 두 참조타입이 있을 때 자식타입의 객체가 부모타입의 변수에 대입이 가능하다.

             //  ( ? 부모가 자식보다 크니까 )

             // 주의사항 : 부모는 단순 직계존속뿐만이 아니라 조상인 object까지 포함한다.

            

             Animal animal = new Dog(); // 다형성 1

             // 부모타입 변수명 = new 자식타입(); (****)

            

             // 부모타입이 자식타입으로 초기화

             // LvalueRvalue가 다른데 어떻게 초기화된 것일까?

             // 기본타입이 아니라서 큰타입 작은타입 비교도 어려울텐데??

            

             // --> 부모타입이 자식타입보다 크기 때문에 초기화가 가능하다!! (**)

             // --> 부모자식의 상속을 통해서 누가 크고 누가 작은지 파악할 수 있다.

             // --> 부모 자식 간에는 크기가 존재해서 자동형변환이 발생한다.

            

             // , 컴파일러가 dog animal의 크기로 자동형변환하여 초기화시킨 것이다.

             // 그렇다고 해서 애니멀이라는 그릇안에 도그가 있는 것이지

             // 도그가 애니멀로 완전히 변한 것은 아니다.

            

             // 그렇기 때문에 부모 애니멸의 메소드를 오버라이드한 도그의 메소드가 실행된다.

            

             animal.sound(); // 다형성 2

             // 출력 : Dog::sound() invoked. 멍멍!!

            

//           다형성 2 :

//           전제조건( 다형성 1 )을 충족한다면, 부모타입의 참조변수의 메소드를 호출했을 때 부모타입 객체의 메소드가 호출되는 것이 아니라,

//           부모로부터 상속받은 메소드가 "오버라이딩" 되었을 때, 이 "오버라이딩"된 메소드가 무조건 호출된다.

            

            

//           ===============================================

            

             animal = new Cat(); // 다형성 1

            

             animal.sound(); // 다형성 2

             // 출력 : Cat::sound() invoked. 냐옹!!

            

             // 같은 변수 같은 메소드임에도 불구하고 다른 출력결과가 나타났다.

            

             // 부모 클래스에 있는 것이 아니라, 자식객체에 오버라이딩된 메소드가 출력되게 된다.

            

       } // main

 

} // end class

 

728x90
댓글
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
최근에 올라온 글
Total
Today
Yesterday
공지사항