본문 바로가기

IT/Java

09_클래스 : 접근제한자(Access Modifier), static 멤버(정적 멤버), 싱글톤(singleton), final, 상수, getters and setters

00. 접근제한자(Access Modifier)

- public > protected > default(생략) > private

- 클래스에서는 protected와 private 접근제한자를 사용할 수 없다.

public protected default(package friendly) private
아무나 접근 가능 나 + 동일한 패키지의 클래스 +  자식 클래스 동일한 패키지의 클래스 나만 접근 가능

01. static 멤버 (정적 멤버)

- static멤버란 클래스에 고정된 멤버를 뜻한다.

- 필드와 메소드 선언시 static 키워드를 붙여서 만든다.

- 객체를 따로 생성하지 않고 클래스가 메모리로 로딩되었을 때 바로 사용할 수 있다.

- 클래스이름.필드; 클래스이름.메소드; 의 형태로 도트(.) 연산자를 통해 접근한다.

 

static필드와 static 메소드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Calculator {
    static double pi = 3.14159;
    
    static int plus(int x, int y) {
        return x + y;
    }
    
    static int minus(int x, int y) {
        return x - y;
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

 Calculator 객체를 생성하지 않고 클래스 이름으로 바로 접근하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CalculatorExample {
    public static void main(String[] args) {
        double result1 = 10 * 10 * Calculator.pi;
        int result2 = Calculator.plus(10,  5);
        int result3 = Calculator.minus(10,  5);
        
        //물론 객체를 통해서도 접근할 수 있으나 static 멤버는 클래스 이름을 통해 접근하는 것이 좋다.
        //Calculator calc = new Calculator();
        //int result4 = calc.plus(10,  4);
       
        System.out.println("result1 : " + result1);
        System.out.println("result2 : " + result2);
        System.out.println("result3 : " + result3);
    }
 
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

02. 정적 블록

- 정적 필드는 보통 선언과 동시에 초기값을 준다. 

- 하지만 정적필드의 선언과 동시에 초기값 할당이 불가능한 경우가 있다(예: 계산이 필요한 경우)

- 정적 필드는 (객체 없이도 사용해야 하므로) 인스턴스 필드와 달리 생성자의 매개값을 통해 초기화를 할 수 없다.

- 이 때 정적 블록을 선언하여 블록 내부에서 정적 필드를 초기화 할 수 있다.

 

Television 클래스이다. static 필드 중 info는 계산이 필요하므로 static 블록 내부에서 초기화 되었다.

1
2
3
4
5
6
7
8
9
public class Television {
    static String company = "Samsung";
    static String model = "LCD";
    static String info;    //계산 필요
 
    static {
    info = company + "-" + model;
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

실행 클래스에서 info의 값을 불러올 때, 객체를 생성하지 않고 클래스로 직접 접근하였다.

1
2
3
4
5
6
7
public class TelevisionExample {
    public static void main(String[] args) {
        System.out.println(Television.info);
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

정적 블록 또는 정적 메소드 내부에서는 인스턴스 멤버와 this 키워드 사용이 불가능하다. static이 메모리에 먼저 로딩되기 때문이다. 인스턴스 멤버를 꼭 사용하고 싶다면 객체를 먼저 생성하고 참조 변수로 접근해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Car {
    int speed;
    
    void run() {
        System.out.println(speed + "로 달립니다");
    }
 
    public static void main(String[] args) {    //static임
        //컴파일 에러 - static 공간에서는 인스턴스 멤버를 사용할 수 없음
        //speed = 60;    run();
        
        //꼭 필요하다면 아래와 같이 객체를 생성하여 참조변수로 접근한다.
        Car myCar = new Car();
        myCar.speed = 60;
        myCar.run();
        
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

03. 싱글톤(Singleton)

 

- 전체 프로그램에서 단 하나의 객체만 만들도록 보장해야 하는 경우, 그 유일한 객체를 싱글톤이라고 한다.

- private으로 객체를 생성한다.

- 생성자 앞에 역시 private 접근자를 붙여 클래스 외부에서 생성자를 호출할 수 없도록 막는다.

- getInstance()와 같은 메소드를 만들어 싱글톤 객체를 리턴하도록 하고, 외부에서는 이 메소드를 통해 리턴 받은 객체만 사용할 수 있도록 만든다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
    // private 싱글톤 객체 생성
    private static Singleton singleton = new Singleton();
 
    // private 생성자
    private Singleton() {
    }
 
    // 객체 리턴해주는 메소드
    static Singleton getInstance() {
        return singleton;
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

아래의 코드를 실행하면 당연히 같은 singleton객체라고 출력된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class SingletonExample {
    public static void main(String[] args) {
//        Singleton obj1 = new Singleton();    //불가능!
        
        Singleton obj1 = Singleton.getInstance();
        Singleton obj2 = Singleton.getInstance();
        
        if(obj1 == obj2) {
            System.out.println("같은 Singleton 객체 입니다.");
        } else {
            System.out.println("다른Singleton 객체 입니다.");
        }
                
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

04. final 필드 

- fina 필드의 경우 초기값이 최종값이 된다. 따라서 실행 도중에 수정할 수 없다. final 필드는 상수가 아니다.

- final 필드의 초기값을 주는 방법

  1) 단순 값 : 필드 선언시 초기값을 줌

  2) 복잡한 코드가 필요한 경우 : 생성자에서 초기값을 줌

 

1
2
3
4
5
6
7
8
9
10
11
12
public class Person {
    final String nation = "Korea";
    final String ssn;    
    String name;    //주민번호와 이름은 사람마다 다르므로 지금 초기화 할 수 없음
    
    public Person(String ssn, String name) {
        this.ssn = ssn;
        this.name = name;
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class PersonExample {
    public static void main(String[] args) {
        Person p1 = new Person("123456-1234567""계백");    //생성자를 통해 ssn과 name의 값을 
        
        System.out.println(p1.nation);
        System.out.println(p1.ssn);
        System.out.println(p1.name);
        
//        p1.nation = "USA";
//        p1.ssn = "123456-9876543";
        p1.name = "을지문덕";    //name은 final이 아니었음.
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

05. static final(상수)

 - final 필드는 불변의 값이긴 하나, 객체마다 따로 저장되며 생성자의 매개값을 통해 여러가지 값을 가질 수 있다. 예를 들어, 바로 위의 코드에서 주민등록번호는 사람마다 다른 값이 부여되었다.

- 반면, static final은 static이라는 특성 때문에 공용성을 가지므로 객체마다 저장할 필요가 없다. 따라서 static final이 붙으면 상수라고 하며, 관습적으로 대문자로 작성한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
package ex06_final;
 
public class Earth {
    // static final : 상수
    static final double EARTH_RADIUS = 6400;
    static final double EARTH_SURFACE_AREA; // 계산 필요
 
    static {
        EARTH_SURFACE_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS;
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

상수 역시 static 키워드가 붙었으므로 클래스이름으로 바로 접근할 수 있다.

1
2
3
4
5
6
7
public class EarthExample {
    public static void main(String[] args) {
        System.out.println("지구의 반지름 : " + Earth.EARTH_RADIUS);
        System.out.println("지구의 표면적 : " + Earth.EARTH_SURFACE_AREA);
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

06. Getters, Setters

- 객체의 데이터를 외부에서 마음대로 변경할 경우 악의적이거나 잘못된 조작으로 인해 데이터가 훼손되어 객체의 무결성이 깨질 수 있다.

- 이것을 방지하기 위해 데이터(필드)는 private으로 선언하여 접근을 막고 메소드는 공개한다.

- 외부에서는 이 메소드를 통해서 데이터에 접근하도록 유도한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Car {
    //필드(private)
    private int speed;
    private boolean stop;
    
    //생성자
    
    //메소드(public)
    public int getSpeed() {
        return speed;
    }
    
    public void setSpeed(int speed) {
        if(speed < 0) {
            this.speed = 0;
            return;
        } else {
            this.speed = speed;
        }
    }
    
    public boolean isStop() {
        return stop;
    }
    
    public void setStop(boolean stop) {
        this.stop = stop;
        this.speed = 0;
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

속도는 음수값을 가질 수 없다.

만약 Car 클래스에서 필드를 public으로 선언했다면 (myCar.speed = -50;) 과 같은 코드를 통해 외부에서 speed의 값을 음수로 조작하는 것이 가능해진다. 

 

하지만 지금처럼 setSpeed() 메소드를 통해서만 speed값을 변경하게 한다면, 메소드 내부에서 매개값을 검사한 후 올바른 값(0)으로 변경해준다. 잘못된 조작으로부터 데이터를 보호할 수 있는 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class CarExample {
    public static void main(String[] args) {
        Car myCar = new Car();
        
        //잘못된 속도 변경
        myCar.setSpeed(-50);
        
        // speed의 setter에서 매개값 검사 후 0으로 변경해줌
        System.out.println("현재 속도 : " + myCar.getSpeed());    
        
        //올바른 속도 변경
        myCar.setSpeed(60);
        
        //멈춤
        if(!myCar.isStop()) {
            myCar.setStop(true);
        }
        
        System.out.println("현재 속도 : " + myCar.getSpeed());
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter