본문 바로가기
dev/기본쌓기

[JAVA] 빠르게 정리하는 자바 문법 (5)

by dev-everyday 2024. 12. 31.
반응형
더보기

해당 글은 아래 링크를 참고하여 작성되었습니다.

https://www.tcpschool.com/java/java_usingClass_package

8. 제어자

1. 패키지

자바에서 패키지란 클래스와 인터페이스의 집합을 의미한다.

서로 관련 있는 클래스나 인터페이스를 함께 묶어서 파일을 효율적으로 관리한다.

자바에서 패키지는 물리적으로 하나의 디렉터리를 의미한다.

따라서 하나의 패키지에 속한 클래스나 인터페이스 파일은 모두 해당 패키지 이름의 디렉터리에 포함되어 있다.

자바에서 패키지를 선언하는 방법은 다음과 같다.

package 패키지이름;

자바의 모든 클래스는 반드시 하나 이상의 패키지에 포함되어야 한다.

하지만 자바 컴파일러는 소스 파일에 어떠한 패키지의 선언도 포함되지 않으면, 기본적으로 이름 없는 패키지(unnamed package)에 포함해 컴파일한다.

따라서 패키지를 명시하지 않은 모든 클래스와 인터페이스는 모두 같은 패키지에 포함되게 된다.

 

import 문

import 문은 자바 컴파일러에 코드에서 사용할 클래스의 패키지에 대한 정보를 미리 제공하는 역할을 한다.

따라서 import 문을 사용하면 다른 패키지에 속한 클래스를 패키지 이름을 제외한 클래스 이름만으로 사용할 수 있게 된다.

또한, 자바에서는 가장 많이 사용하는 java.lang 패키지에 대해서는 import 문을 사용하지 않아도 클래스 이름만으로 사용할 수 있도록 해주고 있다.

 

2. 접근 제어자

제어자(modifier)란 클래스와 클래스 멤버의 선언 시 사용하여 부가적인 의미를 부여하는 키워드를 의미한다.

자바에서 제어자는 접근 제어자(access modifier)와 기타 제어자로 구분할 수 있는데 기타 제어자는 경우에 따라 여러 개 사용할 수 있지만 접근 제어자는 하나만 사용할 수 있다.

 

접근 제어자는 아래의 네 가지가 존재한다.

1) private

private 접근 제어자를 사용하여 선언된 클래스 멤버는 외부에 공개되지 않으며, 외부에서는 직접 접근할 수 없다.

2) public

public 접근 제어자를 사용하여 선언된 클래스 멤버는 외부로 공개되며, 해당 객체를 사용하는 프로그램 어디에서나 직접 접근할 수 있다.

public 메소드는 private 멤버와 프로그램 사이의 인터페이스(interface) 역할 수행한다.

3) default

자바에서는 클래스 및 클래스 멤버의 접근 제어의 기본값으로 default 접근 제어를 별도로 명시하고 있다.

default 접근 제어를 가지는 멤버는 같은 클래스의 멤버와 같은 패키지에 속하는 멤버에서만 접근할 수 있다.

4) protected

자바 클래스는 private 멤버로 정보를 은닉하고 public 멤버로 사용자나 프로그램과의 인터페이스를 구축한다.

여기에 부모 클래스(parent class)와 관련된 접근 제어자가 하나 더 존재한다.

protected 멤버는 부모 클래스에 대해서는 public 멤버처럼 취급되며, 외부에서는 private 멤버처럼 취급한다.

 

3. 기타 제어자

1) final 제어자

자바에서 final 제어자는 '변경할 수 없다'는 의미로 사용된다.

필드나 지역 변수에 사용하면 값을 변경할 수 없는 상수(constant)가 된다.

클래스에 사용하면 해당 클래스는 다른 클래스가 상속받을 수 없게 된다.

메소드에 사용하면 해당 메소드는 오버라이딩(overriding)을 통한 재정의를 할 수 없게 된다.

자바에서 final 제어자를 사용할 수 있는 대상은 클래스, 메소드, 필드, 지역 변수이다.

 

2) static 제어자

자바에서 static 제어자는 '공통적인'이라는 의미로 사용된다.

 static 제어자를 변수에 사용하면 해당 변수를 클래스 변수로 만들어 준다.

static 제어자를 가지는 멤버는 다음과 같은 특징을 가지게 된다.

a. 프로그램 시작시 최초에 단 한 번만 생성되고 초기화됩니다.

b. 인스턴스를 생성하지 않고도 바로 사용할 수 있게 됩니다.

c. 해당 클래스의 모든 인스턴스가 공유합니다.

자방에서 static 제어자를 사용할 수 있는 대상은 메소드, 필드, 초기화 블록이다.

 

3) abstract 제어자

자바에서 abstract 제어자는 '추상적인'이라는 의미로 사용된다.

선언부만 있고 구현부가 없는 메소드를 추상 메소드라 하며, 반드시 abstract 제어자를 붙여야 한다.

하나 이상의 추상 메소드가 포함하고 있는 추상 클래스도 반드시 abstract 제어자를 붙여야 한다.
자방에서 static 제어자를 사용할 수 있는 대상은 클래스와 메소드이다.

abstract class Car {       // 추상 클래스
    abstract void brake(); // 추상 메소드
}

 

 

자바에서는 제어자의 특성상 몇몇 제어자는 함께 사용할 수 없다.

1. 클래스에 final + abstract

final 제어자를 가지는 클래스는 다른 클래스가 상속받을 수 없게 되며 abstract 제어자를 가지는 클래스는 다른 클래스가 상속해서 오버라이딩해야만 사용할 수 있어서 이 두 제어자는 클래스에 함께 사용할 수 없다.

 

2. 메소드에 static + abstract

abstract 제어자를 가지는 메소드는 선언부만 있고 구현부가 없는 메소드인데 static 제어자를 가지는 메소드는 인스턴스를 생성하지 않고도 바로 사용할 수 있어야 해서 이 두 제어자는 메소드에 함께 사용할 수 없다.

 

3. 메소드에 private + abstract

abstract 제어자를 가지는 메소드는 다른 클래스가 상속하여 오버라이딩해야만 사용할 수 있는데 private 제어자를 가지는 메소드는 자식 클래스에서 접근할 수 없게 되므로 이 두 제어자는 메소드에 함께 사용할 수 없다.

 

4. 메소드에 private + final

메소드에 사용된 final 제어자와 private 제어자는 모두 해당 메소드가 오버라이딩을 통한 재정의를 할 수 없다는 의미를 가지므로, 둘 중에 하나만 사용해도 의미가 충분히 전달될 수 있다.

9. 클래스 멤버

1. 필드의 구분

클래스 내에서 필드는 선언된 위치에 따라 다음과 같이 구분된다.

 

1) 클래스 변수

클래스 영역에 위치한 변수 중에서 static 키워드를 가지는 변수를 클래스 변수(static variable)라고 한다.

2) 인스턴스 변수

클래스 영역에 위치한 변수 중 static 키워드를 가지지 않는 변수는 인스턴스 변수(instance variable)라고 한다.

3) 지역 변수

메소드나 생성자, 초기화 블록 내에 위치한 변수를 지역 변수(local variable)라고 한다.

 

클래스 변수와 인스턴스 변수는 초기화를 하지 않아도 변수의 타입에 맞게 자동으로 초기화된다.

하지만 지역 변수는 사용하기 전에 초기화하지 않으면 자바 컴파일러가 오류를 발생시킨다.

 

2. 메소드의 구분

클래스 내에서 메소드는 static 키워드의 여부에 따라 다음과 같이 구분된다.

class Car {
    boolean door;                       // 인스턴스 변수
    void openDoor() {                   // 인스턴스 메소드
        door = true;
    }
    static void toggleDoor(boolean d) { // 클래스 메소드
        return !d;
    }
}

 

1) 클래스 메소드

static 키워드를 가지는 메소드를 클래스 메소드(static method)라고 한다.

클래스 메소드는 클래스 변수와 마찬가지로 인스턴스를 생성하지 않고도 바로 사용할 수 있다.

클래스 메소드는 메소드 내부에서 인스턴스 변수를 사용할 수 없다.

 

2) 인스턴스 메소드

static 키워드를 가지지 않는 메소드는 인스턴스 메소드(instance method)라고 한다.

 

3. 초기화 블록

자바에서 필드는 초기화하지 않아도 변수의 타입에 맞는 초깃값으로 자동으로 초기화된다.

하지만 지역 변수와 마찬가지로 적절한 값으로 초기화한 후에 사용하는 것이 좋다.

자바에서 필드를 초기화하기 위한 방법은 아래와 같다.

1) 명시적 초기화

명시적 초기화는 지역 변수를 초기화하는 방법과 마찬가지로 필드를 선언과 동시에 초기화하는 방법이다.

2) 생성자를 이용한 초기화

생성자를 이용한 초기화는 객체의 생성과 동시에 필드를 초기화하는 방법이다.

생성자를 이용한 초기화는 인스턴스를 생성할 때까지 필드를 초기화할 수 없다.

3) 초기화 블록을 이용한 초기화

필드를 초기화하는 마지막 방법으로는 자바에서 제공하는 초기화 블록(initialization block)을 이용하는 방법이 있다.

초기화 블록이란 클래스 필드의 초기화만을 담당하는 중괄호({})로 둘러싸인 블록을 의미한다.

초기화 블록은 생성자보다 먼저 호출되며, static 키워드의 유무에 따라 다음과 같이 구분한다.

a. 인스턴스 초기화 블록

인스턴스 초기화 블록은 단순히 중괄호({})만을 사용하여 정의할 수 있다.

인스턴스 초기화 블록은 생성자와 마찬가지로 인스턴스가 생성될 때마다 실행된다.

하지만 언제나 인스턴스 초기화 블록이 생성자보다 먼저 실행된다.

생성자와 인스턴스 초기화 블록의 차이는 거의 없으므로 인스턴스 초기화 블록은 잘 사용되지 않는다.

b. 클래스 초기화 블록

클래스 초기화 블록은 인스턴스 초기화 블록에 static 키워드를 추가하여 정의할 수 있다.

이러한 클래스 초기화 블록은 클래스가 처음으로 메모리에 로딩될 때 단 한 번만 실행된다.

클래스 초기화 블록은 생성자나 인스턴스 초기화 블록으로는 수행할 수 없는 클래스 변수의 초기화를 수행할 때 사용된다.

class InitBlock {
    static int classVar; // 클래스 변수
    int instanceVar;     // 인스턴스 변수
    static { // 클래스 초기화 블록을 이용한 초기화
        classVar = 10;
    }
}

public class Member04 {
    public static void main(String[] args) {
        System.out.println(InitBlock.classVar); // 클래스 변수에 접근
    }
}

 

자바에서 필드는 다음과 같은 순서로 초기화된다.

1) 클래스 변수 : 기본값 → 명시적 초기화 → 클래스 초기화 블록

2) 인스턴스 변수 : 기본값 → 명시적 초기화 → 인스턴스 초기화 블록 → 생성자

10. 상속

1. 상속의 개념

상속(inheritance)이란 기존의 클래스에 기능을 추가하거나 재정의하여 새로운 클래스를 정의하는 것을 의미한다.

이러한 상속은 캡슐화, 추상화와 더불어 객체 지향 프로그래밍을 구성하는 중요한 특징 중 하나로 상속을 이용하면 기존에 정의되어 있는 클래스의 모든 필드와 메소드를 물려받아 새로운 클래스를 생성할 수 있다.

 

자바에서 클래스의 상속은 다음과 같은 장점을 가진다.

1) 기존에 작성된 클래스를 재활용할 수 있다.

2) 자식 클래스 설계 시 중복되는 멤버를 미리 부모 클래스에 작성해 놓으면 자식 클래스에서는 해당 멤버를 작성하지 않아도 된다.

3) 클래스 간의 계층적 관계를 구성함으로써 다형성의 문법적 토대를 마련한다.

 

자식 클래스(child class)란 부모 클래스의 모든 특성을 물려받아 새롭게 작성된 클래스로 자바에서 자식 클래스는 다음과 같은 문법을 통해 선언한다.

class 자식클래스이름 extend 부모클래스이름 { ... }

자식 클래스에는 부모 클래스의 필드와 메소드만이 상속되며 생성자와 초기화 블록은 상속되지 않는다.

부모 클래스의 접근 제어가 private이나 default로 설정된 멤버는 자식 클래스에서 상속받지만 접근할 수는 없다.

자바에서 클래스는 단 한 개의 클래스만을 상속받는 단일 상속만이 가능하다.

 

자바에서 Object 클래스는 모든 클래스의 부모 클래스가 되는 클래스다.

따라서 자바의 모든 클래스는 자동으로 Object 클래스의 모든 필드와 메소드를 상속받게 된다.

자바의 모든 객체에서 toString()이나 clone()과 같은 메소드를 바로 사용할 수 있는 이유가 해당 메소드들이 Object 클래스의 메소드이기 때문이다.

 

2. super와 super()

super 키워드는 부모 클래스로부터 상속받은 필드나 메소드를 자식 클래스에서 참조하는 데 사용하는 참조 변수다.

인스턴스 변수의 이름과 지역 변수의 이름이 같을 경우 인스턴스 변수 앞에 this 키워드를 사용하여 구분할 수 있었는데 이와 마찬가지로 부모 클래스의 멤버와 자식 클래스의 멤버 이름이 같을 경우 super 키워드를 사용하여 구별할 수 있다.

 

super() 메소드는 부모 클래스의 생성자를 호출할 때 사용한다.

자식 클래스의 인스턴스를 생성하면, 해당 인스턴스에는 자식 클래스의 고유 멤버뿐만 아니라 부모 클래스의 모든 멤버까지도 포함되어 있다.

따라서 부모 클래스의 멤버를 초기화하기 위해서는 자식 클래스의 생성자에서 부모 클래스의 생성자까지 호출해야한다.

따라서 자바 컴파일러는 부모 클래스의 생성자를 명시적으로 호출하지 않는 모든 자식 클래스의 생성자 첫 줄에 자동으로 다음과 같은 명령문을 추가하여, 부모 클래스의 멤버를 초기화할 수 있도록 한다.

class Parent {
    int a;
    Parent(int n) { a = n; }
}

 

class Child extends Parent {
    int b;
    Child() {
        super();
        b = 20;
    }
}

 

3. 메소드 오버라이딩

자바에서 자식 클래스는 부모 클래스의 private 멤버를 제외한 모든 메소드를 상속받는다.

이렇게 상속받은 메소드는 그대로 사용해도 되고, 필요한 동작을 위해 재정의하여 사용할 수도 있다.

즉, 메소드 오버라이딩이란 상속받은 부모 클래스의 메소드를 재정의하여 사용하는 것을 의미한다.

 

자바에서 메소드를 오버라이딩하기 위한 조건은 아래와 같다.

1. 오버라이딩이란 메소드의 동작만을 재정의하는 것이므로 메소드의 선언부는 기존 메소드와 완전히 같아야 한다.

2. 부모 클래스의 메소드보다 접근 제어자를 더 좁은 범위로 변경할 수 없다

3. 부모 클래스의 메소드보다 더 큰 범위의 예외를 선언할 수 없다.

반응형