즐겁게!! 자신있게!! 살아보세!!

재밌는 인생을 위하여! 영촤!

Language_Study/JAVA

[JAVA, App] 8.상속

Godwony 2020. 12. 23. 23:03
반응형

만들어진 클래스 이용

1.내가 원하는 기능을 가진 클래스를 찾기

2.내개 원하는 기능을 수행해주는 메소드를 찾기

  • static 인지 아닌지 확인: static 이라면 인스턴스를 생성할 필요가 없음

    • static이 아니라면 인스턴스를 생성해야 하므로 생성자를 다시 확인
  • 메소드의 매개변수를 확인

    • 매개변수는 메소드에게 일을 시킬 때 메소드가 사용할 데이터입니다.
    • 필요한 데이터를 제공하지 않으면 메소드는 일을 하지 않거나 에러를 발생
  • return type을 확인

    • 작업을 수행하고 어떤 결과를 돌려주는지 확인

package & import

1.package

  • 관련있는 클래스의 모임
  • 파일 시스템에서는 하나의 디렉토리
  • package가 배포 단위
  • 클래스는 실행은 가능하지만 배포를 할 수 없습니다.
  • 자바에서는 클래스들을 다른 프로젝트에서 사용하도록 배포하고자 할 때는 클래스들을 패키지로 묶어서 jar로 압축해서 전달하면 됩니다.

2.자바의 클래스 로드

  • 자바는 실행되는 프로그램에 존재하는 모든 클래스들을 jvm에 로드하고 실행
  • 자바에서는 존재하는 모든 클래스를 별도의 작업이 바로 사용이 가능
  • 사용을 할 때는 클래스의 전체 경로를 입력해야 합니다.
    • 패키지이름.클래스 의 형태로 사용해야 합니다.

3.import

  • import는 가져오는 개념이 아니고 줄여쓰기 위한 개념입니다.
  • 클래스를 만들기 전 상단 부분에 import를 해주면 패키지이름을 생략하고 클래스를 사용할 수 있습니다.

1) 패키지이름.*

  • 패키지에 존재하는 모든 클래스들을 패키지 이름을 생략하고 사용 가능

2) 패키지이름.클래스이름

  • 클래스이름에 해당하는 클래스만 패키지 이름을 생략하고 사용 가능

3) 예제

Scanner의 원래 이름은 java.util.Scanner

java.util.Scanner sc = new java.util.Scanner(System.in);
  • 위처럼 작성하면 너무 길어서 import 하고 사용
import java.util.Scanner;

Scanner sc = new Scanner(System.in);
  • Eclipse에서는 클래스 이름만 사용한 경우 클래스 이름에 커서를 갖다대면 import 해주겠다는 메시지가 보여고 이를 클릭하면 자동으로 import 구문이 입력됩니다.

4) import 할 때 주의할 점

  • 클래스를 찾을 때 자바는 현재 프로젝트에서 찾고 없으면 다른 패키지에서 찾습니다.
    • 제공되는 클래스와 동일한 이름의 클래스를 만들면 제공되는 클래스를 사용할 때는 패키지이름을 전부 입력해서 사용해야 합니다.
    • 제공되는 클래스와 동일한 이름의 클래스를 만들지 않는 것이 좋습니다.
  • 서로 다른 패키지에 동일한 이름의 클래스가 존재하는 경우가 있는데 프로젝트 내에서 2개의 클래스를 모두 사용할 때는 하나는 패키지이름을 전부 입력하는 것이 좋습니다.
    java.util.Date 와 java.sql.Date의 경우 모두 사용하는 경우에 하나는 전체 경로를 입력하는 것이 좋습니다.

5) java application을 개발할 때 import 하지 않아도 java.lang 패키지는 이미 import가 되어 있어서 클래스 이름만 이용하면 됩니다.

상속(Inheritance)

1.개념

  • 하위 클래스가 상위 클래스의 모든 것을 물려받는 것

  • 물려받는 클래스를 하위(Sub) 클래스라고 하는데 다른 용어로는 Derived(파생 클래스) 클래스라고도 하고 물려주는 클래스를 상위(Super) 클래스라고 하는데 다른 용어로는 Based(기반 클래스) 클래스라고도 합니다.

  • 자주 사용하는 상위 클래스들을 파악해서 프로그램을 만들기 쉽게 제공해주는 것을 프레임워크 또는 엔진 이라고 부릅니다.

  • 윈도우 용 프로그램 개발 프레임워크로 가장 유명한 것이 VC#, VC++(MFC)

  • Java 개발 프레임워크로 유명한 것은 Spring

2.상속을 이용했을 때의 장점

  • 코드를 간결하게 만들수 있기 때문에 유지보수가 편리해집니다.

  • 재사용성이 증가

3.단점

  • 상위 클래스의 내용을 변경하면 하위 클래스도 영향을 받게됩니다.
    • 하위 클래스는 상위 클래스에 종속됩니다.

4.상속을 관계로 표현할 때는 is a 관계라고 합니다.

5.java는 단일 상속만 지원합니다.

  • java의 모든 클래스는 하나의 클래스로부터만 상속을 받을 수 있습니다.

6.java의 모든 클래스는 java.lang.Object 라는 클래스로부터 상속을 받습니다.

7.java에서 상속 방법

class 클래스이름 extends 상위클래스이름{

}

8.접근지정자와 상속

  • private: 상속은 되지만 하위 클래스에서 접근 할 수 없음(사용 불가)

  • default(package): 동일한 패키지내에서는 하위 클래스에서 상위 클래스의 멤버를 사용할 수 있고 서로 다른 패키지에서는 사용이 불가능

  • protected: 하위 클래스에서 사용 가능

  • public: 하위 클래스에서 사용 가능하고 인스턴스도 사용 가능

9.상속과 접근 지정자

1) 상위 클래스로 사용할 Based 클래스

public class Based {
    private int num;
    String title; //접근 지정자를 설정하지 않는 것을 default 또는 package
    protected String content;
    public int readcnt;
}

2) Based 클래스로 부터 상속받은 Derived 클래스

//Based 클래스를 상속받은 Derived 클래스
public class Derived extends Based {
//메소드
    public void disp() {
        //num = 10;  //num은 private 멤버라서 보이지 않는다고 에러 메시지
        //protected로 변경할 것인지 물어봅니다.

        title = "제목";
        content = "내용";
        readcnt = 0;
    }
}
  • 상속을 받을 때는 클래스를 만들 때 Super Class에 입력해도 되고 클래스를 만든 후 직접 extends 상위 클래스 이름을 입력해도 됩니다.

10.super

1) 인스턴스 메소드에서의 super

  • 인스턴스 메소드 안에서 어떤 이름을 사용하면 메소드 안에서 먼저 찾고 없으면 메소드 외부에서 찾으며 그래도 없으면 상위 클래스에서 이름을 찾습니다.

    • 상위 클래스에도 없으면 undefined 되었다고 에러 메시지 출력
  • 메소드 안에서 찾지 않고 메소드 외부에서 부터 찾고자 할 때는 this. 을 앞에 붙이면 됩니다.

    • this가 붙으면 메소드 안에서는 찾지 않고 메소드 외부의 클래스에서 먼저 찾고 없으면 상위 클래스에서 찾습니다.
  • this. 대신에 super.을 붙이면 자신의 클래스에서도 찾지 않고 상위 클래스에서만 찾습니다.

  • this를 사용해야만 하는 경우는 메소드 내에 만든 변수와 클래스에 만들어진 변수 이름이 같을 때 클래스에 만들어진 변수를 사용할 때 이용

    • super는 현재 클래스와 상위 클래스에 동일한 이름의 메소드가 있을 때 상위 클래스의 메소드를 호출하기 위해서 사용합니다.

실습

  • Based 클래스에 print() 메소드를 생성
public void print() {
    System.out.println("상위 클래스의 print");
}
  • Derived 클래스에 print() 메소드를 생성
public void print() {
    System.out.println("하위 클래스의 print");
}

public void method() {
    print(); //앞에 아무것도 붙지 않았기 때문에 자신의 클래스에서부터 찾아 갑니다.
    //자신의 클래스에 만든 print()
    System.out.println("======================");

    super.print(); //상위 클래스에서 print()를 찾습니다.
    //Based에 만든 print()
}
  • main 메소드를 소유한 실행 클래스를 만들어서 Derived 클래스의 method()를 호출
public class Main {

    public static void main(String[] args) {
        //Derived 클래스의 method()를 호출

        //Derived 인스턴스를 생성
        Derived d = new Derived();
        //메소드 호출
        d.method();
    }
}

2) 생성자에서의 super()

  • 생성자에 첫번째 줄은 작성을 하지 않더라도 super()입니다.

    • 상위 클래스의 매개변수가 없는 생성자를 호출하는 구문입니다.
  • Based 클래스를 상속받은 Derived 클래스에 생성자를 만들지 않더라도 아래와 같은 생성자가 존재

public Derived(){
    super(); //이 구문은 new Based(); 와 동일한 구문
}
  • Based에 생성자를 만들고 super()를 호출하지 않으면 자동으로 super()가 삽입됩니다.

  • 상속을 받으면 상위 클래스의 모든 멤버를 상속받아서 생성해야 합니다.

    • 상위 클래스의 멤버를 생성할려면 상위 클래스의 생성자를 호출해야 합니다.
    • 코드 상 호출하지 않더라도 무조건 해야 하기 때문에 자바에서는 자동으로 삽입해줍니다.
  • 상위 클래스에 매개변수가 없는 생성자(default constructor)가 없으면 하위 클래스에 생성자를 만들어서 상위 클래스의 생성자를 직접 호출해야 합니다.

11.polymorphism(다형성)

1) method overriding(메소드 재정의)

  • 상위 클래스에 존재하는 메소드를 하위 클래스에서 다시 만드는 것
  • 메소드 이름이 같고 매개변수의 개수와 자료형이 같은 메소드를 다시 만드는 것
  • 매개변수의 개수나 자료형이 다르면 method overloading(메소드 중복정의)
  • 하는 이유는 자신이 만든 클래스의 경우는 다형성 구현을 위해서 이고 프레임워크가 제공하는 클래스가 상위 클래스인 경우는 기능확장을 위해서 입니다.

2) 프레임워크가 제공하는 클래스를 상속받아서 사용하는 경우

  • 프레임워크가 제공하는 클래스는 기본 기능만 제공해주기 때문에 기본 기능을 확장하기 위해서 상속을 받아서 사용
  • 기본 기능을 확장할 때 메소드 오버라이딩을 사용하는데 이 때 상위 클래스의 메소드를 호출을 해주어야 합니다.
public void method(){
    super.method();
    //추가하고자 하는 기능
}
  • 상위 클래스의 메소드 호출 시점은 정리를 하는 메소드를 제외하고는 상위 클래스의 메소드를 먼저 호출합니다.
  • 정리하는 메소드는 상위 클래스의 메소드를 나중에 호출합니다.
  • android studio 같은 경우에는 자신이 제공하는 클래스를 상속받아서 메소드를 오버라이딩 할 때 상위 클래스의 메소드를 호출하지 않으면 에러 발생하고 VC++ 같은 곳에서는 메소드 오버라이딩 할 때 상위 클래스 메소드 호출하는 구문이 자동 삽입됩니다.

3) @Override

  • @이 붙는 것은 자바에서는 annotation 이라고 하고 python에서는 decorator 라고 합니다.

    • 어노테이션은 자주 사용하는 자바 코드를 매번 작성하는 것이 번거롭기 때문에 이 어노테이션을 추가하면 자바가 컴파일을 할 때 자동으로 코드를 삽입해주는 것입니다.
  • @Override 는 이 메소드가 오버라이딩 된 메소드를 라는 것을 알려주기 위한 어노테이션

    • 이 어노테이션을 붙였는데 이 메소드가 상위 클래스에 없으면 에러가 발생합니다.
  • 프로그램의 가독성을 높이기 위해서 오버라이딩 한 경우에는 붙여주는 것이 좋습니다.

4) 객체 지향 언어에서의 참조형 사이의 대입

  • C나 Java 와 같은 정적 자료형 언어들은 변수를 선언할 때 사용한 자료형의 데이터만 변수에 대입할 수 있습니다.
int a = 10;
//a에는 정수만 대입이 가능합니다.
  • 참조형 에서는 한가지 예외가 있습니다.
    • 상위 클래스 타입으로 만들어진 변수에 하위 클래스 타입의 인스턴스 참조를 대입할 수 있습니다.

하위 클래스 타입으로 만들어진 변수에 상위 클래스 타입의 인스턴스 참조는 대입할 수 없는데 강제 형 변환을 하면 대입이 되고 문법적인 에러는 없습니다.
원래의 자료형이 하위 클래스 타입이 아니면 실행할 때 예외가 발생합니다.

Based , Based를 상속받은 Dervied가 존재
Based obj = new Based(); //Based 로 만든 변수에 Based 인스턴스를 대입 - 에러 없음
Derived ins = new Derived(); //에러 없음

Based o = new Derived(); //Derived가 Based로 부터 상속을 받았기 때문에 가능
Derived d = new Based(); //이 문장은 에러 Based가 Derived의 하위 클래스가 아니어서 에러

Derived d1 = (Derived)(new Based()); //강제 형 변환을 해서 에러는 아님 - 실행 시 에러
Derived d2 = (Derived)(o); //강제 형 변환을 에러는 아님 - 실행 시 에러 아님

5) 참조형 변수의 멤버 호출

  • 참조형 변수는 변수를 선언할 때 사용한 자료형의 멤버만 호출이 가능합니다.

Based o = new Derived();

  • o 는 Based 에 존재하는 것만 호출할 수 있습니다.

  • Based는 없고 Derived에만 존재하는 것은 호출할 수 없습니다.

  • 예외적으로 overriding 된 메소드는 인스턴스를 만들 때 사용한 생성자의 것을 호출합니다.

    • o가 오버라이딩 된 메소드를 호출할 때는 Based 의 것이 호출되는 것이 아니고 Derived의 것이 호출됩니다.

6) polymorphism(다형성)

  • 동일한 메시지에 대하여 다르게 반응하는 성질
  • 동일한 코드가 대입된 인스턴스에 따라 다른 메소드를 호출하는 것

12.다형성 구현 실습

1) 다형성과 상관없이 Terran, Zerg, Protoss의 공격 메소드를 생성하고 Main에서 실행하는 코드를 작성하고 실행

  • Terran 클래스를 생성하고 attack 메소드를 구현
public class Terran {
    //테란의 공격 메소드
    public void attack() {
        System.out.println("탱크로 대포를 쏘고 마린으로 총을 쏩니다.");
    }
}
  • Protoss 클래스를 만들고 attack 메소드를 구현
public class Protoss {
    //프로토스 공격 메소드
    public void attack() {
        System.out.println("질럿은 찌르고 드래군은 공을 던집니다.");
    }
}
  • Zerg 클래스를 만들고 attack 메소드를 구현
public class Zerg {
    //저그의 공격
    public void attack() {
        System.out.println("저글링은 때리고 히드라는 침을 뱉습니다.");
    }
}
  • main 메소드를 소유한 실행 클래스를 만들고 3개 클래스의 attack을 호출하는 코드를 작성
public class Main {

    public static void main(String[] args) {
        Terran t = new Terran();
        t.attack();

        Zerg z = new Zerg();
        z.attack();

        Protoss p = new Protoss();
        p.attack();
    }
}

2) 위까지 실행하면 3개의 메소드를 호출할 수 있습니다.

  • 지금은 3개 클래스의 인스턴스를 가지고 메소드를 호출하기 위해서 3개의 변수에 각각의 인스턴스를 대입해서 메소드를 호출했습니다.

  • 메소드를 호출하는 코드가 다릅니다.

  • 인터페이스에 메소드를 연결할려고 하면 3개의 명령어가 필요합니다.

  • 하나의 명령어로 3개 메소드를 모두 호출할 수 있도록 하기 위해서 동일한 코드가 3개의 메소드를 호출할 수 있도록 변경

  • Terran, Zerg, Protoss 클래스의 인스턴스를 모두 저장할 수 있는 변수를 만들기 위해서 3개 클래스에 상속할 상위 클래스를 생성하고 메소드를 오버라이딩 할 수 있도록 attack을 구현

public class Starcraft {
    //하위 클래스의 인스턴스가 attack을 호출할 수 있도록 오버라이딩을 위한 메소드
    public void attack() {

    }
}
  • Terran, Zerg, Protoss 클래스에 Starcraft 클래스를 상속하도록 클래스 선언문 수정
public class Terran extends Starcraft

public class Zerg extends Starcraft

public class Protoss extends Starcraft
  • main 메소드 수정
Starcraft star = new Terran();
star.attack();

star = new Zerg();
star.attack();

star = new Protoss();
star.attack();
반응형

'Language_Study > JAVA' 카테고리의 다른 글

[JAVA, App] 10.예외처리  (0) 2020.12.25
[JAVA, App] 9.추상메소드  (0) 2020.12.23
[JAVA, App] 7.클래스  (0) 2020.12.23
[JAVA, App] 6.검색  (0) 2020.12.23
[JAVA, App] 5.데이터정렬  (0) 2020.12.23