[JAVA] ACCESS MODIFIER, STATIC, SINGLETON

dafault, private, public, static, sington pattern

Posted by iheese on April 12, 2022 · 8 mins read

Access Modifier

  • private : 같은 클래스 내부에서만 접근 가능, 외부 클래스, 상속 관계에서도 접근 불가하다.
  • default (아무것도 안쓴 것) : 같은 패키지 내부에서만 접근 가능하다. (상속관계라도 패키지 다르면 접근 불가하다.)
  • protected : 같은 패키지와 상속관계 클래스에서만 접근 가능하다.
  • public : 클래스의 외부, 내부 어디서든 접근 가능하다.


static 변수 (클래스 변수, 정적 변수)

  • 여러 인스턴스가 공유하는 변수가 필요할 때 사용한다.
  • 인스턴스와 다르게 처음 프로그램이 메모리에 로딩될 때 할당된다. (static 남용은 메모리 낭비가 될 수 있다.)
  • 인스턴스 생성과는 연관이 없기 때문에 클래스 이름으로 참조된다.

static 변수 사용 예제, 학번 붙이기

Student.java

public class Student{
	public static int studentClass =1; // 1로 공유되는 static 변수
    
}

StudentTest.java

public class StudentTest {
	public static void main(String[] args) {

        System.out.println(Student.studentClass); //1
        Student.studentClass++;
        System.out.println(Student.studentClass); //2
        
        Student lee= new Student();
        System.out.println(lee.studentClass); //2 
    }
}

  • 직접 클래스 이름으로 접근할 수 있으며 값을 변경하면 다른 공유되는 값도 변경된다.
  • 또한 클래스를 통해 인스턴스를 생성해도 static으로 생성한 변수는 공유된다.


static 메소드

  • static 변수와 마찬가지로 클래스 이름 자체로 접근한다.
  • static 메소드 안에서는 멤버 변수를 사용할 수 없다. (인스턴스 생성 전에 호출될 수 있기 때문이다.)
  • 객체를 생성하여 메소드를 호출하기 부담스러울 때 사용한다.

Student.java

public class Student{
	public static int studentClass =1; // 1로 공유되는 static 변수	
    public String studentName; //멤버 변수 선언
    
    public static int getStudentClass(){
    		return studentClass;
    }
    
    public static void setStudentClass(int studentClass){
    	// studentName ="lee";//오류: 멤버변수 사용불가
    	Student.studentClass=studentClass; //this도 사용불가
    } //클래스 이름 자체로 접근하고 있다. 
    
}

StudentTest.java

public class StudentTest {
	public static void main(String[] args) {

        System.out.println(Student.getStudentClass()); //1
        Student.setStudentClass(100);
        System.out.println(Student.getStudentClass()); //100

    }
}
  • 지역 변수 : 함수 내부에서 선언되고, 내부에서만 사용됨, 스택 메모리에서 사용된다.
  • 멤버 변수(인스턴스 변수) : 클래스 내부에서 사용되며, private이 아니면 다른 클래스에서도 사용 가능, 힙 메모리에 생성되고 가비지 컬렉터가 수거해간다.
  • static 변수(클래스 변수) : 클래스 내부에서 사용되며, private이 아니면 다른 클래스에서 사용가능, 프로그램이 시작할 때 데이터 영역에 제일 먼저 저장되고 프로그램이 끝날 때 소멸된다.
    • static 블럭: static {} 을 이용하면 main 메소드 보다 먼저 실행되는 영역을 만들 수 있다.


싱글톤 패턴 (Singleton pattern)

  • 객체(인스턴스)가 하나만 생성되어야 하는 경우 사용한다.
  • Ex)
    • 학생 객체는 많이 필요하지만 학교 객체는 하나만 존재해야 한다.
    • 직원 객체는 많이 필요하지만 회사 객체는 하나만 존재해야 한다.

싱글톤 패턴 만들어보기(School 싱글톤 패턴)

1 . School 클래스의 생성자를 private으로 만들어 접근할 수 없게 한다.

School.java

class School {
    private School() {} // private 생성자 생성
}

2 . 하나의 private static 인스턴스를 선언한다.

School.java

class School {
    private School() {} // private 생성자 생성
    private static School instance;
}

3 . getInstance() 메소드를 만들어 하나의 객체만 존재하게 한다.

School.java

class School {
    private School() {} // private 생성자 생성
    private static School instance;
    
    public static School getInstance() {
        if(instance==null) {
            instance = new School();
        }
        return instance;
    }
}

4 . 싱글톤 패턴이 잘 동작하는지 실행해본다.

SchoolTest.java

public class SchoolTest{
    public static void main(String[] args) {
        School school1 = School.getInstance();
        School school2 = School.getInstance();
        System.out.println(school1 == school2);  // true
    }
}
  • 위 코드 실행 결과 같은 객체가 생성된 것을 알 수 있다.


싱글톤 실습

  • Test 코드를 실행시키기
  • 자동차 공장은 유일한 객체이다.
  • 자동차는 고유 번호가 존재하고 생성될 때마다 1씩 번호가 증가한다.

CarFactoryTest.java

public class CarFactoryTest {

	public static void main(String[] args) {
		CarFactory factory = CarFactory.getInstance();
		Car mySonata = factory.createCar();
		Car yourSonata = factory.createCar();
		
		System.out.println(mySonata.getCarNum());     //10001 출력
		System.out.println(yourSonata.getCarNum());   //10002 출력
	}
}
  • CarFactory, Car 클래스가 필요할 것 같다.
  • CarFactory는 getInstance, createCar 메소드가 필요하고 싱글톤 패턴으로 만들어야겠다.
  • Car 클래스에는 CarNum을 static으로 선언하고 getCarNum()은 호출할 때 마다 1씩 더해야겠다.

CarFactory.java

public class CarFactory {
	
    private CarFactory() {} // 생성자 private으로 생성
	private static CarFactory instance;
    // private 인스턴스 선언
	
	public static CarFactory getInstance() {
		if (instance==null) {
			instance =new CarFactory();				
		}
		return instance;
	}
	//getInstance 메소드
    
	public Car createCar() {
		return new Car();
	} // Car 인스턴스 생성 메소드
}

Car.java

public class Car {
	private static int firstCarNum=10001; //인스턴트끼리 공유되어질 변수값 할당
    private int carNum; //공유되지 않은 변수값을 생성한다. 

    public Car() {
		carNum = firstCarNum; 
		firstCarNum++; 
	}
	// 생성자가 생성될 때 첫 인스턴스는 10001 값을 가지고, static 변수값을 1 올린다. 그러면 다음 인스턴스는 10002 값을 가지게 됟다. 
	public int getCarNum() {
		return carNum; //차량은 순서대로 고유 번호를 가지게 된다.
	}
}


Reference: