본문 바로가기

코딩/JAVA 공부

[JAVA] 자바의 정석 _ 상속, 포함

  * 클래스의 관계

1. 상속: 기존의 클래스로 새로운 클래스를 작성하는 것

- Java는 단일 상속만 허용. (다중 상속은 충돌의 문제가 있음.) 인터페이스를 통해 다중상속 비슷하게 구현 가능함.

class Parent{}
class Child extends Parent{
//....
}

자손은 조상의 모든 멤버를 상속받는다. (생성자, 초기화블럭 제외)

자손의 변경은 조상에 영향을 미치지 않는다.

 

2. 포함: 클래스의 멤버로 참조변수를 선언하는 것

class Point{
    int x;
    int y;
}

class Circle{
    Point c = new Point(); // 포함
    int r;
}

class Circle2{
	int x;
    int y;
    int r;
 }

Circle이 Point를 포함

선언 및 생성 시 아래와 같은 구조로 만들어짐.

포함을 활용하면 다중상속과 비슷한 효과를 낼 수 있다.

//DVD class에 play(), stop(), ff() im이 있다 가정.
class TvDVD extends Tv{
    DVD dvd = new DVD();
    
    void play(){
    	dvd.play();
    }
    
    void stop(){
    	dvd.stop();
    }
    
    void ff(){
    	dvd.ff();
    }

}//TvDVD end

 

클래스 생성할 때 상속할지, 포함할지 결정하는 방법

상속 관계: A는 B이다.

포함 관계: A는 B를 가지고 있다.

문장을 만들어보고 더 잘 맞는 거로. 대부분 포함관계이다. (상속 관계는 제약이 있음)

 

 * Object 클래스 - 모든 클래스의 최고 조상

부모가 없는 클래스는 자동적으로 Object클래스를 상속받게 된다.

Object에 정의된 11개 메서드는 자동으로 상속된다.

그래서 toString(), equals(), hashCode() 같은 메서드 사용 가능.

 

 (println의 기능)

println 내부적으로, 매개변수로 입력한 것에 .toString을 붙여 사용한다.

 

 * 메서드 오버라이딩(overriding)

- 상속받은 조상의 메서드를 자신에 맞게 변경하는 것. 선언문은 바꾸지 못하고 내용(구현부)만 변경 가능.

class Point{
    int x;
    int y;
    
    String getLocation(){
    	return "x :" + x + ", y :" + y;
    }
}

class Point3D extends Point{
    int z;
    
    String getLocation(){            // 오버라이딩
    	return "x :" + x + ", y :" + y + ", z :" +z;
    }
}

오버라이딩의 조건

1. 선언부가 조상 클래스의 메서드와 일치해야 한다.

2. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.

    접근 제어자 : publoc, protected, private, default

3. 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.

class Patent{
    void parentMethod() {}
}

class Child extends Parent{
    void parentMethod() {}	// 오버라이딩
    void parentMethod(int i) {}	// 오버 로딩
    
    
    void childMethod() {}	// 메서드 정의
    void childMethod(int i) {}	// 오버 로딩
}

 

* 참조 변수 super & 생성자 super()

참조 변수 super:  객체 자신을 가리키는 참조 변수. 인스턴스 메서드(생성자) 내에만 존재, 조상 멤버와 자신의 멤버 구별할 때 사용.

조상의 멤버에 super. 을 붙임.

cf) 참조 변수 this : lv와 iv 구분에 사용

class Parent {int x = 10;}

class Child extends Patenr{
    int x = 20;
    
    void method() {
    	System.out.println(x)		// 20
        System.out.println(this.x)	//20
        System.out.println(super.x)	//10
    }
}

조상의 멤버와 자신의 멤버가 겹치지 않은 경우, this, super 둘 다 조상 멤버로 접근.

 

생성자 super() : 조상의 생성자를 호출할 때 사용. 조상의 멤버는 조상의 생성자를 호출해서 초기화.

(상속 시 조상의 생성자, 초기화 블록은 상속 안됨)

조상 class에서 생성된 멤버는 super()를 통해 조상 클래스를 통해 초기화해야 함

class Point{
    int x,y;
    
    Point(int x, int y){
    	this.x = x;
        this.y = y;
    }
}

class Point3D extends Point {
	int z;
    
    Point3D(int x, int y, int z){
    	super(x,y);	// 조상클래스의 생성자 Point(int x, int y) 호출
        this.z = z;	// 자신의 맴버 초기화
    }
}

!!중요!! 생성자의 첫 줄에 반드시 생성자를 호출해야 한다. 만약 없으면 컴파일러가 super(); 삽입.

 

 * 패키지(package)

- 서로 관련된 클래스의 묶음.

 

패키지 선언 : 소스파일의 첫 번째 문장으로 단 한번 선언

같은 소스 파일의 클래스들은 모두 같은 패키지에 속하게 된다.

패키지 선언이 없으면 이름 없는 패키지에 속하게 된다.

 

클래스 패스 : 클래스 파일(*. class)의 위치를 알려주는 경로

환경변수 classpath로 관리하며, 경로 간의 구분자는 ';'를 사용

 

 * import문

- 클래스 사용할 때 패키지 이름을 생략하게 해 줌. 컴파일러에게 클래스가 속한 패키지를 알려줌.

(이클립스 단축키 ctrl+shift+O)

class ImportTest{
    java.util.Date today = new java.util.Data();
}
----------------------------------------------------------------------------------------
import java.util.Data;

class ImportTest{
    Data today = new Date();
}

기본 패키지(java.lang)은 import 없이 사용 가능.

 

static import문 : static멤버를 사용할 때 클래스 이름을 생략할 수 있게 해 준다.

import static java.lang.Math.random;
import static java.lang.System.out;

System.out.println(Math.random());
--> out.println(random());

 

* 제어자(modifier) 

- 클래스와 클래스의 멤버(변수, 메서드)에 부가적인 의미 부여 (형용사와 비슷한 역할)

 

1. 접근 제어자(access modifier) : public, protected, private, (deafault)  4개 중 1개만 사용 가능

 public : 접근 제한 없음

 protected : 같은 패키지 내 + 다른 패키지의 자손 클래스에서 접근 가능

 (default) : 같은 패키지 내에서만 접근 가능

 private : 같은 클래스 내에서만 접근 가능

제어자 같은 클래스 같은 패키지 자손 클래스 전체
public O O O O
protected O O O  
(default) O O    
private O      

class엔 public or (default) 둘 중 1개 (+ 하나의 소스파일엔 public class가 1개만 가능 + public class와 소스파일 이름 일치)

멤버 변수엔 4개 중 1개

 

2. 그 외 : static, final, abstract, native, transient, synchronized, volatile, strictfp 등..  여러 개 사용 가능

 static - 멤버 변수, 메서드 앞에 붙음.

 final - 클래스, 메서드, 변수 앞에 붙음 / final 선언 시 변경할 수 없다.

 abstract - 클래스, 메서드 앞에 붙음 / 추상 메서드가 포함된 클래스, 선언부 만 있고 구현부는 없는 메서드. 객체 생성 불가.

추상 클래스는 상속받아 완전한 클래스(구상 클래스)를 만든 후에 객체 생성 가능.

 

 * 캡슐화

접근 제어자 사용하는 이유 : 외부로부터 데이터를 보호하기 위해 + 내부적으로만 사용되는 부분을 감추기 위해

이를 통해 캡슐화를 구현 가능.

public class Time{
    private int hour;	// 대입 연산을 통한 직접 접근은 막음
    private int minute;
    private int second;
    
    public int getHour() {return hour;}
    public void setHour(int hour){
    	if (hour < 0 || hour > 23) return;
        this.hour = hour;	// 메서드를 통해 간접 접근 허용
    }
}