4. 제어자(modifiers)
4.1 제어자란?
- 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미를 부여한다.
- 제어자는 크게 접근 제어자와 그 외의 제어자로 나뉜다.
- 하나의 대상에 여러 개의 제어자를 조합해서 사용할 수 있으나, 접근제어자는 단 하나만 사용할 수 있다.
4.2 static (클래스의, 공통적인)
static은 시작부터 끝까지 고정되어 있는 메모리기이기 떄문에 적당히?? 사용해야한다..
static이 사용될 수 있는 곳 : 맴버변수, 메서드, 초기화 블록
맴버변수
- 모든 인스턴스에 공통적으로 사용되는 클래스변수가 된다.- 클래스변수는 인스턴스를 생성하지 않고도 사용 가능하다.
- 클래스가 메모리에 로드될 때 생성된다.
메서드
- 인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 된다.- static메서드 내에서는 인스턴스맴버들을 직접 사용할 수 없다.
4.3 final (마지막의, 변경될 수 없는)
상수처럼 만들어 버림!!
보통 상수의 이름은 모두 대문자로 하는 것이 관례
final이 사용 될 수 있는 곳 : 클래스, 메서드 , 맴버변수, 지역변수
클래스
- 변경될 수 없는 클래스, 확장 될 수 없는 클래스가 된다.(상속 불가능)- 대표적인 final클래스로는 String과 Math가 있다.
final class A
{
}
class B extends A // 상속 불가능~!
{
}
메서드
- 변경될 수 없는 메서드, final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다.(오버라이딩 불가능)class A
{
final void add()//재정의 불가능
{}
}
맴버변수, 지역변수
- 변수 앞에 final을 붙이면, 값을 변경할 수 없는 상수가 된다.class Test
{
public static void main(String[] args)
{
final double PI = 3.141592; //final을 사용하여 상수로 만들어 버림!!
PI = 99.9; //할당 불가능!!
System.out.println(a);
}
}
4.4 생성자를 이용한 final 맴버변수 초기화
- final이 붙은 변수는 상수이므로 보통은 선언과 초기화를 동시에 하지만, 인스턴스변수의 경우 생성자에서 초기화 할 수 있다.
인스턴스 변수가 초기화 되지 않았을때 명시적으로....
class A
{
final int x = 10; //초기화
A(int x)
{
this.x = x; //명시적으로 초기화를 1회 하였기때문에 수정 불가능
}
}
class A
{
final int x; //초기화 하지 않고 선언만 한경우
A(int x)
{
this.x = x;
}
}
class Test
{
public static void main(String[] args)
{
A a1 = new A(100); //수정 가능
System.out.println(a1.x);
}
}
4.5 abstract (추상의, 미완성의)
미완성이란? 선언부만 존재하고 구현부가 없는것!
추상클래스는 객체를 생성할 수 없당.
abstract가 사용될 수 있는 곳 : 클래스, 메서드(주로 메서드에서 사용됨)
클래스
- 클래스 내에 추상메서드가 선언되어 있음을 의미한다.메서드
- 선언부만 작성하고 구현부는 작성하지 않은 추상메서드임을 알린다.참고
- 추상메서드가 없는 클래스도 abstract를 붙여서 추상클래스로 선언하는 것이 가능하기는 하지만 그렇게 해야 할 이유는 없다.
- 추상클래스를 상속을 받는다면 무조건!! 오버라이딩을 해야한다.(추상 메서드 모두를 오버라이딩)
- 오버라이딩 하지 않으면 그 클래스 역시 추상클래스가 됨
abstract class A
{
/*
void add() //선언부
{ //구현부 : {}블록 자체가 구현부의 완성임
} //아무일도 하지 않는 구현부
*/
abstract void add(); //선언부
}
추상클래스를 상속을 받는다면 무조건!! 오버라이딩을 해야한다.(추상 메서드 모두를 오버라이딩)
오버라이딩 하지 않으면 그 클래스 역시 추상클래스가 됨
abstract class A
{
abstract void add(); //선언부
}
class B extends A
{
void add() //오버라이딩
{
}
}
4.6 접근 제어자(access modifier)
거의 private, public만 사용됨- 맴버 또는 클래스에 사용되어, 외부로 부터의 접근을 제한한다.
- private : 같은 클래스 내에서만 접근 가능.
- default : 같은 패키지 내에서만 접근 가능.
- protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근 가능
- public : 접근 제한이 전혀 없다.
4.7 접근 제어자를 이용한 캡슐화
접근 제어자를 사용하는 이유
- 외부로부터 데이터를 보호하기 위해
- 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해
private는 "선언된 클래스에서만 사용하겠다"는 의미
변수를 감추는것 : 캡슐화(변수에 private를 주는것)
보통 대부분의 변수는 private를 두어서 접근을 할 수 없도록 만든다.
접근이 필요할 시에는 우회적으로 접근한다.
class A
{
private int x = 10;
public void setX(int x)//우회하는 메서드
{
if(x <= 100 && x > 0)
//유효성 검사와 같은 것도 사용할 수 있다.
this.x = x;
}
public int getX()//우회하는 메서드
{
return x;
}
}
class Test
{
public static void main(String[] args)
{
A a = new A();
a.setX(500);
System.out.println(a.getX());
}
}
>>이런 방식을 DTO(Data Transfer Object) 방식이라고 한다..
>>변수는 private, 메소드는 public
4.8 생성자의 접근 제어자
- 일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 일치한다.
- 생성자에 접근 제어자를 사용함으로써 인스턴스의 생성을 제한할 수 있다.
객체를 만든다는것은 개별적인 인스턴스 변수가 필요할 때인것
그렇지 않다면 객체를 만들 필요가 없다....
따라서 이럴때 일부러 생성자를 사용하지 못하도록 함
대표적으로 System class
class A
{
private A() //생성자에 private
{ }
}
class Test
{
public static void main(String[] args)
{
A a = new A(); //객체 생성 불가능
System.out.println(a);
}
}
=====================================
final class Singleton
{
private static Singleton s = new Singleton();
private Singleton() //생성자에 접근을 제어함
{
}
public static Singleton getInstance() //참조형(Singleton)리턴
{
if(s==null)
{
s = new Singleton();
}
return s;
}
}
class SingletonTest
{
public static void main(String[] args)
{
//Singleton s = Singleton(); //에러! Singleton() has private...
Singleton s1 = Singleton.getInstance();
//변수가 없고 메서드만 있는경우
//변수가 모두 상수있때
//즉, 개별적 저장공간이 없을때(인스턴스변수가 없을때)
//Singleton 방식을 사용한다.
}
}
4.9 제어자의 조합
클래스 : public, (default), final, abstract
메서드 : 모든 접근 제어자, final, abstract, static
맴버변수 : 모든 접근 제어자, final, static
지역변수 : final
- 메서드에 static과 abstract를 함께 사용할 수 없다.(static메서드는 구현부가 있는 메서드에만 사용할수 있기 때문)
- 클래스에 abstract와 final을 동시에 사용할 수 없다.(클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미고, abstract는 상속을 통해서 완선되어야 한다는 의미이므로 서로 모순되기 때문.)
- abstract메서드의 접근제어자가 private일 수 없다.(abstract메서드는 자손클래스에서 구현해주어야 하는데 접근제어자가 private이면, 자손클래스에서 접근할 수 없기 때문이다.)
- 메서드에 private과 final을 같이 사용할 필요는 없다.(접근 제어자가 private인 메서드는 오버라이딩될 수 없기 때문, 이 둘 중 하나만 사용해도 의미가 충분하다.)