JAVA/JAVA 기본정리

제어자/ static / final/ abstract / public / protected/ default / private

hyun-1200 2022. 6. 2. 14:03

제어자 ( modifier)

: 클래스, 변수, 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다.

제어자의 종류는 접근제어자와 그 외의 제어자로 나눌 수 있다. 

 

접근 제어자 : public, protected, default , private
그 외 : static , final, abstract, native, transient, synchronized, volatile, strictfp 

static : 공통적인, 클래스의 

static 은 '클래스의' 또는 '공통적인'의 의미를 가지고 있다.

클래스변수(static변수)는 모든 인스턴스가 공유하기 때문에, 인스턴스에 관계없이 같은 값을 갖는다.

 

  • static 이 붙은 멤버변수와 메서드는 인스턴스를 생성하지 않고도 사용할 수 있다.
  • 인스턴스 메서드와 static메서드의 근본적인 차이는 메서드 내에서 인스턴스 멤버를 사용하는가의 여부에 있다.

 

제어자 대상 의미
static 멤버변수 - 모든 인스턴스에 공통적으로 사용되는 클래스변수가 된다.
- 클래스변수는 인스턴스를 생성하지 않고도 사용 가능하다.
- 클래스가 메모리에 로드될 때 생성된다.
메서드 - 인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 된다.
- static 메서드 내에서는 인스턴스 멤버들을 직접 사용할 수 없다. 

fianl  : 마지막의, 변경될 수 없는 

  • 변수에 사용되면 값을 변경할 수 없는 상수가 되며,
  • 메서드에 사용되면 오버라이딩을 할 수 없게되고,
  • 클래스에 사용되면 자신을 확장하는 자손클래스를 정의하지 못하게 된다. 
제어자  대상 의미 
final 클래스 변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다.
그래서 final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다. 
메서드 변경될 수 없는 메서드, final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다. 
멤버변수 변수 앞에 final이 붙으면, 값을 변경할 수 없는 상수가 된다. 
지역변수

 

생성자를 이용한 final멤버 변수의 초기화

- 클래스 내에 매개변수를 갖는 생성자를 선언하여, 인스턴스를 생성할 때 final이 붙은 멤버변수를 초기화하는데 필요한 값을 생성자의 매개변수로부터 제공받는 것이다. 

- 이 기능을 활용하면 각 인스턴스마다 final이 붙은 멤버변수가 다른 값을 갖도록 하는것이 가능하다. 

- 예를 들어, 각 카드마다 다른 종류와 숫자를 갖지만, 일단 카드가 생성되면 카드의 값이 변경되면 안되는 경우 이를 활용한다.

 


abstract : 추상의, 미완성의 

메서드의 선언부만 작성하고 실제 수행내용은 구현하지 않은 추상 메서드를 선언하는데 사용된다.

클래스에 사용되어 클래스 내에 추상메서드가 존재한다는 것을 쉽게 알 수 있게 한다.

 

제어자 대상 의미
abstract 클래스 클래스 내에 추상 메서드가 선언되어 있음을 의미한다.
메서드 선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알린다. 
  • 추상 클래스는 아직 완성되지 않은 메서드가 존재하는 '미완성 설계도'이므로 인스턴스를 생성할 수 없다. 
  • 다른 클래스가 이 클래스를 상속받아서 일부의 원하는 메서드만 오버라이딩해도 된다는 장점이 있다. 

접근제어자 ( access modifier ) 

접근 제어자는 멤버 또는 클래스에 사용되어, 해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제어하는 역할을 한다. 

접근 제어자가 사용될 수 있는 곳 - 클래스, 멤버변수, 메서드, 생성자
private : 같은 클래스 내에서만 접근 가능하다.
default : 같은 패키지 내에서만 접근 가능하다.
protected : 같은 패키지 내에서, 다른 패키지의 경우 자손클래스내에서 접근 가능하다.
public : 접근 제한이 전혀 없다. 

 

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

 

접근 제어자의 접근 범위가 넓은 쪽에서 좁은 쪽의 순으로 왼쪽부터 나열하면 아래와 같다.

public > protected > (default) > private 

 

대상에 따라 사용할 수 있는 접근 제어자는 아래와 같다. 

대상 사용가능한 접근 제어자 
클래스 public, (default) 
메서드 public, protected, (default), private
멤버변수
지역변수 X

 

접근 제어자를 사용하는 이유는

  • 외부로부터 데이터를 보호하기 위해서
  • 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서 (캡슐화)  이다. 

 

멤버변수를 private 이나 protected로 제한하고 멤버변수의 값을 읽고 변경할 수 있는 public 메서드를 제공함으로써 간접적으로 멤버변수의 값을 다룰 수 있도록 하는 것이 바람직하다.

 

 

  • Time의 객체 t 는 t.hour=13 과 같이 멤버변수로의 직접적인 접근이 허가되지 않는다.
  • 메서드를 통한 접근만이 허용될 뿐이다.
  • 상속을 통해 확장이 예상되는 클래스라면 자손클래스에서 접근하는것이 가능하도록 하기 위해 private 대신 protected를 사용한다. 

 

생성자의 접근제어자 

- 생성자에 접근 제어자를 사용함으로써 인스턴스의 생성을 제한할 수 있다. 

- 생성자의 접근 제어자를 private으로 지정하면, 외부에서 생성자에 접근할 수 없으므로 인스턴스를 생성할 수 없게 된다.  대신 내부에서 인스턴스를 생성할 수 있게 해주고 인스턴스를 생성해서 반환해주는 public메서드를 제공한다. 이로써 외부에서 이 클래스의 인스턴스를 사용하도록 할 수 있다. 이 메서드는 pulic인 동시에 static이어야 한다. 

 

class Singleton{
	private Singleton(){...}
    
    // 인스턴스가 미리 생성되어 있어야 하므로 static이어야 한다.
    private static Singleton s= new Singleton();

	// 인스턴스를 생성하지 않고도 호출할 수 있어야 하므로 static이어야 한다. 
    public static Singleton getInstance(){
    	return s;
    }
    
    
}
  • 생성자를 통해 직접 인스턴스를 생성하지 못하게 하고 public 메서드를 통해 인스턴스에 접근하게 함으로써 사용할 수 있는 인스턴스의 개수를 제한할 수 있다.
  • 생성자가 private인 클래스는 다른 클래스의 조상이 될 수 없다. 왜냐하면, 자손 클래스의 인스턴스를 생성할 때 조상클래스의 생성자를 호출해야만 하는데, 생성자의 접근제어자가 private이면 자손클래스에서 호출하는것이 불가능하기 때문이다.
    • 그래서 클래스 앞에 final을 추가하여 상속할 수 없는 클래스라는 것을 알리는 것이 좋다. 
//상속할 수 없는 클래스라는 것을 알리기 위해 final 사용 
public final class Math{
	private Math(){...}
}

 


제어자의 조합 

 

제어자가 사용될 수 있는 대상을 중심으로 정리한 제어자. 

대상 사용 가능한 제어자 
클래스 public, (default) , final, abstract
메서드 모든 접근 제어자, final, abstract, static
멤버변수 모든 접근 제어자, fianl, static 
지역변수 final

 

 

제어자를 조합해서 사용할 때 주의해야 할 사항

1. 메서드에 static과 abstract를 함께 사용할 수 없다.

  • static메서드는 몸통이 있는 메서드에만 사용할 수 있다.

2. 클래스에 abstract과 final을 동시에 사용할 수 없다.

  • 클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미이고, abstract는 상속을 통해서 완성되어야 한다는 의미이므로 모순.

3. abstract메서드의 접근제어자가 private일 수 없다.

  • abstract메서드는 자손클래스에서 구현해주어야 하는데 접근제어자가 private이면 자손클래스에서 접근할 수가 없다. 

4. 메서드에 private과 final을 같이 사용할 필요는 없다.

  • 접근제어자가 private인 메서드는 오버라이딩 될 수 없기 때문에, 둘 중 하나만 사용해도 의미가 충분하다.