4 minute read

Updated:

제어자(modifier)

  • 제어자는 클래스, 변수, 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다.
  • 제어자의 종류는 크게 접근 제어제와 그 외 제어자로 나뉜다.
접근 제어자 public, proteced, default, private
그 외      static, final, abstract, native, transient, synchronized, stricffp
  • 하나의 대상에 여러 제어자를 조합하여 사용할 수 있다. 단, 접근 제어자는 하나만 사용할 수 있다.
    public class 클래스명 {
      public static final int WIDTH = 200;    // static, final 동시에 사용. 접근제어자는 public 사용
      public static void main(String[] args){ // 제어자들 간의 순서는 관계없지만 주로 접근 제어자를 제일 먼저 놓는다.
          system.out.print("WIDTH=" + WIDTH);
      }
    }
    

static - 클래스의, 공통적인

  • static이 붙은 멤버변수와 메서드, 그리고 초기화 블럭은 인스턴스가 아닌 클래스에 관계된 것이므로 인스턴스를 생성하지 않고도 사용할 수 있다.
  • 인스턴스멤버를 사용하지 않는 메서드는 static을 붙여서 static 메서드로 선언하는 것을 고려하자. 가능하다면 static 메서드로 호출하는 것이 인스턴스를 생성하지 않고도 호출이 가능해서 더 편리하고 속도도 빠르다.

static이 사용될 수 있는 곳 - 멤버변수, 메서드, 초기화 블럭

class StaticTest {
    static int width = 200;     //클래스 변수(static 변수) 간단(명시적) 초기화
    static int height = 120;    //클래스 변수(static 변수)
    
    static {                    //클래스 초기화 블럭 (클래스가 메모리에 로드될 때 한번 수행되며,클래스 변수를 초기화하는데 사용된다.)
        // static 변수의 복잡한 초기화 수행
    }
    
    static int max(int a, int b){   //클래스 메서드(static 메서드)
        return a > b ? a : b ;
    }
}

final - 마지막의, 변경될 수 없는

  • 변수에 사용하면 값을 변경할 수 없는 상수가 되고, 메서드에 사용하면 오버라이딩 할 수 없게 되고, 클래스에 사용하면 자신을 확장하는 자손클래스를 정의할 수 없다.(조상클래스가 될 수 없다.)
  • 대표적인 final 클래스로는 String과 math가 있다.

    final이 사용될 수 있는 곳 - 클래스, 메서드, 멤버변수, 지역변수

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

  • final이 붙은 변수는 상수이므로 일반적으로 선언과 초기화를 동시에 하지만, 인스턴스변수의 경우 생성자에서 초기화가 가능하다.
class Card {
    final int NUMBER;               //상수지만 선언과 함께 초기화 하지 않고 생성자에서 단 한번 초기화할 수 있다.
    final String KIND;
    static int width = 100;
    static int height = 250;
    
    Card(String kind, int num) {    //매개변수를 갖는 생성자를 선언하여, final 멤버변수를 초기화하는데 필요한 값을
        KIND = kind;                //생성자의 매개변수로부터 받는다.
        NUMBER = num;
    }
    
    Card() {
        this("HEART", 1)
    }
    
    public String toString() {
        return KIND + " " + NUMBER;
    }
}

class FinalCardTest {
    public static void main(String args[]) {
        Card c = new Card("HEART", 10);
//        c.NUMBER = 5;     //에러. cannot assign a value fo final variable NUMBER
        System.out.printle(c.KIND);
        System.out.printle(c.NUMBER);
        System.out.printle(c);
    }
}

//실행결과
HEART
10
HEART 10

abstract - 추상의, 미완성의

  • 메서드의 선언부만 작성하고 실제 수행내용은 구현하지 않는 추상 메서드를 선언하는데 사용된다.
  • 클래스에 사용되면 클래스 내에 추상 메서드가 존재함을 의미한다.
  • 추상메서드는 아직 완성되지 않은 메서드가 존재하는 ‘미완성 설계도’이므로 인스턴스 생성이 불가하다.

    abstract가 사용될 수 있는 곳 - 클래스, 메서드

abstract class AbstractTest {       //추상 클래스(추상 메서드를 포함한 클래스 
    abstract void move();           //추상 메서드(구현부가 없는 메서드)
}

접근 제어자

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

접근 제어자를 이용한 캡슐화

  • 접근 제어자를 사용하는 이유는
    1. 외부로부터 데이터를 보호하기 위해서(데이터 감추기)
    2. 외부에서 접근할 필요없는, 내부적으로만 사용되는 부분을 감추기 위해서
      • 기능 변경 후 테스트 시, 메서드의 접근 제어자가 default나 private이라면 테스트 범위가 좁아지므로 테스트 시간을 줄일 수 있다.
public class Time {
    private int hour;       //접근 제어자를 private으로 하여 외부에서 직접 접근하지 못하도록 한다.
    private int minute;
    private int second;

    public int getHour() {                  //멤버변수의 값을 일고 변경할 수 있는 public 메서드를 제공하여
        return hour;                        //간접적으로 멤버변수의 값을 다룰 수 있도록 함
    }

    public void setHour(int hour) {     
        if (hour < 0 || hour > 23) return;
        this.hour = hour;
    }

    public int getMinute() {
        return minute;
    }

    public void setMinute(int minute) {
        if (minute < 0 || minute > 23) return;
        this.minute = minute;
    }

    public int getSecond() {
        return second;
    }

    public void setSecond(int second) {
        if (second < 0 || second > 23) return;
        this.second = second;
    }
}

생성자의 접근 제어자

  • 생성자에 접근 제어자를 사용함으로써 인스턴스 생성을 제한할 수 있다.
  • 대신 인스턴스를 생성해서 반환해주는 public 메서드를 제공하여 외부에서 이 클래스의 인스턴스를 사용하도록 할 수 있다.
  • 이 메서드는 인스턴스를 생성하지 않고도 호출할 수 있어야 하므로 public인 동시에 static이어야 한다.
class Singleton {
    ...
    private static Singleton s = new Singleton();   //getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야 한다.

    private Singleton() {
        ...
    }

    //인스턴스를 생성하지 않고도 호출할 수 있어야 하므로 static이어야 한다.
    public static Singleton getInstance() {
        return s;
    }

    class SingletonTest {
        public static void main(String args[]) {
 //         Singleton s = new Singleton();  //에러. Singleton() has private access in Singleton
            Singleton s = Singleton.getInstance();
        }
    }
}
  • 생성자가 private인 클래스는 다른 클래스의 조상이 될 수 없다.
  • 클래스 앞에 final을 추가하여 상속불가한 클래스란 것을 알려야 한다.
public final class Math {
    private Math() {}
        ...
}

다형성(polymorphism)

  • 여러가지 형태를 가질 수 있는 능력
  • 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 한다.
  • 인스턴스 타입과 참조변수의 타입이 일치하는 것이 보통이지만, 두 클래스가 서로 상속관계에 있는 경우 타입 불일치가 가능하다.
TV t = new CaptionTV(); //CaptionTV가 TV를 상속받은 자손클래스이면 타입 불일치 가능
  • 같은 타입의 인스턴스라도, 참조변수의 타입에 따라 사용할 수 있는 멤버의 갯수가 달라진다.
  • Tv타입의 참조변수로는 Tv클래스에 정의 되지 않은 멤버, text와 caption()은 참조변수 t로 사용이 불가능하다. ```java class Tv{ boolean power; int channel;

    void power(){ power = !power; } void chnnelUp(){ ++channel; } void channelDown(){ –channel; } }

class CaptionTV extends Tv { String text; void caption(){} }


```java
CaptionTv c = new CaptionTv();  //인스턴스타입과 같은 참조변수
Tv        t = new CaptionTv();  //조상타입의 참조변수
  • 반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 순 없다.
  • 참조변수(자손)가 사용할 수 있는 멤버의 개수가 인스턴스 멤버(부모)의 개수보다 많으면 존재하지 않는 멤버를 사용하고자 할 가능성이 있으므로 허용하지 않는다.
    CaptionTv c = new Tv();     //허용 불가
    

Tags:

Categories:

Updated: