클래스 static, 접근제한자 private

2019. 12. 22. 19:23개인공부/자바

클래스는 객체를 만들기 위한 설계도이다. 클래스에는 객체를 생성하기 위한 필드와 생성자, 메소드가 정의되어 있다.

필드와, 메소드는 멤버라고 하며, 멤버는 객체를 생성해야 사용할 수 있는 인스턴스 멤버와 클래스에 고정된 정적 멤버가 있다. 정적 멤버는 클래스 멤버라고도 하며, 객체를 생성하지 않고도 사용할 수 있다. 객체를 생성하지 않고도 사용할 수 있는 이유는 그림과 같다.

프로그램이 실행되고 클래스 파일(바이트 코드)이 클래스 로더에 의해 메소드 영역에 올라가기 때문에 객체를 생성하기 전에도 멤버에 접근할 수 있다. (인스턴스 멤버는 객체가 생성될 때 만들어진다.)

1.
그렇다면 언제 정적 멤버를 사용할까?
사람이라는 클래스를 만든다고 가정해보자.

public class 사람{
           int
머리카락수;
           int
심장수=1;
         int
치아개수;
}
모든 사람은 심장을 하나 가지고 있으므로 심장의 개수는 굳이 객체마다 가지고 있을 필요가 없는 공용적인 데이터이다. 따라서 다음과 같이 정적으로 선언하여 메모리 낭비를 줄일 수 있다.

public class 사람{
           int
머리카락수;
           static int
심장수=1;
           int
치아개수;
}
클래스 멤버는 모든 인스턴스(객체)들이 공유하고 있으므로 클래스 필드의 값이 변경되면 모든 객체에서 접근하는 값이 바뀐다.

Person p1=new Person();
System.out.println("p1:"+p1.simjang);//1
출력
Person.simjang=2;
System.out.println("p1:"+p1.simjang);//2
출력

따라서 모든 객체가 공통의 값을 공유해야 한다면 정적 멤버로 선언하는 것이 좋다

2.
정적 메소드와 블록 선언 시 주의 점.

정적 멤버(정적 메소드+정적 필드)는 클래스의 바이트 코드가 메소드 영역에 올라갈 때부터 사용할 수 있으므로, 객체가 없어도 실행이 된다. 하지만 이런 특징 때문에 정적 메소드에서 인스턴스 멤버를 사용하거나, 정적 블록에서 인스턴스 필드에 접근하는 경우 컴파일 에러가 발생한다.

ex)
public class
사람{
//
인스턴스 필드, 메소드
int
머리카락;
void
머리카락개수출력(){  }
//
정적 필드와 메소드
static int
심장개수;
static void
심장개수출력(){  }

//정적 블록
static{
머리카락=100000; // 컴파일에러
머리카락개수출력();// 컴파일에러
심장개수=0; // 가능
심장개수출력(); // 가능

//정적 메소드
static void
심장과머리카락개수합출력{
System.out.println(
심장개수+this.머리카락개수); //컴파일 에러
}

인스턴스 멤버는 인스턴스(객체)가 생성될 때 함께 생성되므로, 클래스 멤버의 메소드에 사용될 수 없다. 컴파일 에러가 발생한다.

 

 

3. 접근제한자

main()메소드를 가지지 않는 대부분의 클래스는 외부 클래스에서 이용할 목적으로 설계된 라이브러리 클래스이다. 라이브러리 클래스를 설계할 때에는 외부 클래스에서 접근할 수 있는 멤버와 접근할 수 없는 멤버로 구분해서 필드, 생성자, 메소드를 설계해야 한다.

접근 제한자를 통해서 객체 생성을 막거나 객체의 특정 데이터를 보호하고 특정 메소드를 호출할 수 없도록 제한할 수 있다.

접근 제한자는 public, protected, default, private와 같이 네 가지 종류가 있다.
먼저 클래스에 사용되는 접근 제한자는 publicdefault인데, 다른 패키지에서는 사용할 수 없게 하려면 default로 선언하면 된다.
ex)
default class Car{
…}
위와 같이 선언하면 다른 패키지에서는 Car 클래스에 접근할 수 없다. 다른 패키지의 클래스에서 Car클래스를 이용해 객체를 생성한다면, 컴파일 에러가 발생한다.

생성자, 필드, 메소드에는 public, protected, default, private을 모두 사용할 수 있는데
default
는 같은 패키지 내에서만, private은 동일 클래스에서만 사용도록 제한할 수 있다.

ex) private 메소드를 외부 클래스에서 사용하기
Person.java
public class Person{

    public void methodPublic(){

        methodPrivate(); //private 메소드를 public메소드 안에 심는다.

    }

    private void methodPrivate(){

        System.out.println("private메소드 실행");

    }

}

 

Main.java

public class Main

{

           public static void main(String[] args) {

                       Person p1=new Person();

                       p1.methodPublic();//정상실행

                       p.1methodPrivate(); //컴파일에러

                       }

}

 

+ 생성자에 접근제한자를 이용하여 싱글톤 생성
public class Person{

   

    private static Person A = new Person(); //외부 클래스에서 직접접근 X, 정적메소드를 이용한 반환.(static)

   

    private Person(){}

   

    public static Person getInstance(){

        return A;

    }

       

    public void Hello(){

        System.out.println("hello world"); //인스턴스 메소드..객체를 생성하지 않고 메소드 실행불가.

    }

}

 

--

public class Main
{
public static void main(String[] args) {
Person p1=Person.getInstance();
p1.Hello();
}
}

'개인공부 > 자바' 카테고리의 다른 글

참조타입 변수  (0) 2019.12.22