오늘의하루

[JAVA] 객체지향 2편 본문

JAVA

[JAVA] 객체지향 2편

오늘의하루_master 2022. 8. 1. 12:57

1. 상속

  • 기존 클래스를 재사용하여 새로운 클래스를 만드는 것이다.
  • 상속으로 만들어진 클래스들은 부모 자식의 관계가 생긴다.
  • 자식은 부모의 모든 멤버를 상속받게된다.
    • 단, 생성자와 초기화 블록은 제외
      • 해결방법 : 부모의 생성자를 호출할 수 있는 생성자 super() 사용
    • 자식의 멤버개수는 부모의 멤버개수보다 작거나 많다.
  • 부모 클래스의 변경은 자식 클래스에게 영향을 미치지만 자식 클래스의 변경은 부모 클래스에 아무런 영향을 미치지 못한다.
  • Java는 단일상속만을 허용한다.
    • 두개 이상의 클래스를 가져오고 싶다면 비중이 높은 클래스는 상속을 하고 나머지는 포함관계를 가지면 됩니다.
  • 부모가 없는 클래스는 자동으로 (최상위 클래스)Object 클래스를 상속받고 있습니다.
    • 이런 이유로 모든 클래스는 11개의 매서드를 상속받습니다.
      • Object로 부터 상속받는 매서드 : toString(), equals(), hashCode()...
        • toString()의 경우 System.out.println(Test) == System.out.println(Test.toString())
class parents { // 부모 클래스 멤버 2개
    int x;
    int y;
}

class child extends { // 자식 클래스 멤버 3개
    int z;
    // 부모로 부터 받은 int x;
    // 부모로 부터 받은 int y;
}

1-1. 오버라이딩(overfiding)

부모로부터 상속받은 메서드의 내용을 자식 클래스에 맞게 변경하는것이다.

오버라이딩의 조건

  • 선언부가 같아야한다. (메서드명, 매개변수, 리턴타입)
  • 접근제어자를 부모 클래스보다 좁게 지정할수 없다.
    • 범위 순서 : public > protected > default > private
  • 부모 클래스의 메서드보다 많은 수의 예외를 선언할 수 없습니다.
오버로딩 : 기존에 없는 새로운 메서드를 정의하는 것 (new)
오버라이딩 : 상속받은 메서드의 내용을 변경하는 것 (change)

2. 포함

  • 멤버변수로 다른 클래스를 선언한다.
  • 작은 단위의 클래스를 만들고 이것들을 조합해서 하나의 큰 클래스를 만든다.
class T{
    int x;
    int y;
}

class TT{
   T test = new T(); // 포함
   int z;
}

⭐ 사용하는 방법
TT composite = new TT();
composite.test.x = 1; // T클래스 x에 접근
composite.z = 3; // TT클래스의 z에 접근

3. 참조변수 super

참조변수 super는 부모의 멤버와 자식의 멤버를 구별하기 위해 사용됩니다.

class parent{
    int x = 10;
}

class child extends parent{
    int x = 20;
    void method(){
        System.out.println("x = " + x); // 가장 가까운 x
        System.out.println("x = " + this.x); // 호출한 당사자의 x
        System.out.println("x = " + super.x); // 부모 클래스의 x
    }
}

만약 child 클래스에 x가 정의되지 않았다면 x, this.x, super.x 모두 parent 클래스의 x를 가져옵니다.

4. 생성자 super()

부모 클래스에서 상속받을 때 생성자, 초기화 블록은 상속받지 못하기 때문에 상속받은 자식 클래스에서 부모 클래스로 부터 상속받은 멤버를 초기화 하기 위해 부모 클래스의 생성자를 호출할때 사용한다.

자식 클래스에서 직접 초기화 할 수 있지만 부모로 부터 상속 받은 멤버는 부모 클래스가 가장 정확하기 때문에 생성자 super()를 이용해서 초기화 해준다.
  • 모든 클래스의 생성자 첫 줄에는 생성자(같은 클래스의 다른 생성자 || 부모 클래스의 생성자)를 호출해야한다.
    • 같은 클래스의 다른 생성자 호출 this() 부모 클래스의 생성자 호출 super() 
    • 만약 첫 줄에 작성하지 않으면 컴파일러가 자동으로 super()를 첫줄에 삽입한다.
⭐ 정상적으로 작동
class T{
    int x;
    
    T(){this(1);} // 매개변수 없는 기본 생성자
    T(int x){ // 매개변수 있는 생성자
        //super();
        this.x = x;
    }
}

class TT{
    int y;
    
    TT(){ // 기본 생성자
        this(0,0);
    }
    TT(int x, int y){ // 매개변수 있는 생성자
        super(x); // == T(int x)
        // 부모 클래스 생성자를 이용해서 초기화
        // 이 코드에서는 생략하더라도 정상 작동한다.
        this.y = y;
    }
}

💥 에러 발생
class E{
    int x;
    E(int x){
        // super();
        this.x = x;
    }
}

class EE{
    int y;
    EE(){
        this(1,1);
    }
    EE(int x, int y){
        // super(); // == E();
        // 부모 클래스에는 현재 E() 라는 메서드가 존재하지 않는다.
        // Error : onstructor E in class E cannot be applied to given types;
        this.x = x;
        this.y = y;
    }
}

5. 패키지 (Package)

  • 서로 관련된 클래스와 인터페이스의 묶음
  • 패키지는 물리적으로 폴더이며 서브패키지를 가질 수 있고 "."으로 구분한다.
  • 클래스의 실제 이름은 패키지명이 포함된 것이다.
    • String 클래스의 실제 이름은 java.lang.String
  • rt.jar은 Java API의 기본 클래스들을 압축한 파일이다.
  • 패키지는 소스파일 첫번째 문자으로 단 한번 선언한다.
  • 하나의 소스파일에 두개 이상의 클래스가 포함되어있다면 모두 같은 패키지에 속하게 된다.
  • 패키지가 선언되지 않은 클래스는 자동적으로 unnamed 패키지에 속하게 된다.

6. import

  • 사용할 클래스가 속한 패키지를 지정하는데 사용
  • import문을 사용하면 클래스를 사용할때 패키지명을 생략할 수 있다.
    • import문 사용 x : java.util.Date today = new java.util.Date();
    • import문 사용 o : Date today = new Date();
  • java.lang 패키지의 경우 import문을 사용하지 않아도 생략이 가능하다.
    • String, Object, System, Thread...
  • import문은 패키지문과 클래스 선언의 사이에서 선언된다.
  • import문 선언 방법은 import 패키지명.클래스명;
    • 만약 같은 패키지에 있는 모든 클래스를 사용하고 싶다면 import 패키지명.*;
      • import 패키지명.*을 하면 서브 패키지에 있는 클래스들도 사용이 가능하다.

 

Comments