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와 같이 네 가지 종류가 있다.
먼저 클래스에 사용되는 접근 제한자는 public과 default인데, 다른 패키지에서는 사용할 수 없게 하려면 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();
}
}