본문 바로가기

Java SE Tutorials/Class Members

Java Class Members

Java 프로그래밍, 클래스 멤버 ( Class Members )


Java 클래스를 정의할 때 멤버들이 메모리에 생성되는 시기와 특성에 따라서 2가지의 종류의 멤버를 선언할 수 있다.

인스턴스 멤버와 클래스 멤버 (멤버들이 메모리에 생성되는 특성에 따른 분류)

Instance Members : non-static Members, 인스턴스에 속하는 멤버

  • Instance Variables : 인스턴스가 생성될 때마다 Heap Memory 에 생성되는 멤버변수(객체변수)
  • Instance Methods : 인스턴스 생성 후에 인스턴스의 참조를 이용하여 호출할 수 있는 메소드

Class Members : static Members, 인스턴스와 무관, 클래스에 속하는 멤버

  • Class Variables : 클래스 이름과 도트 연산자( . )를 이용하여 접근할 수 있는 멤버변수
  • Class Methods : 클래스 이름과 도트 연산자( . )를 이용하여 호출할 수 있는 멤버 메소드
  • 해당 클래스의 인스턴스가 여러개 생성되더라도 클래스가 이미 로드된 경우에는 더 이상 클래스 멤버가 로드되지 않는다
  • 해당 클래스가 사용될 때, 단 한번만 Method Area에 로드되며 다시 로드되지 않는다.


클래스 멤버는 특정 인스턴스에 속하는 것이 아니라 클래스에 속한 멤버이다

  • 인스턴스의 참조를 이용하면 인스턴스 멤버에 접근할 수 있다.
  • 인스턴스의 참조를 이용하면 클래스 멤버에도 접근할 수 있다.
  • 클래스 이름을 이용하면 클래스 멤버에 접근할 수 있다.
  • 클래스 이름을 이용하여 인스턴스 멤버에 접근할 수는 없다


클래스가 최초로 로드되는 시기

동적 클래스 로딩 (Runtime Class Loading)

클래스는 메모리에 로드된 후에야 실행될 수 있고 인스턴스도 생성할 수 있다. Java 에서는 동적 클래스 로딩(Runtime Class Loading) 방식을 사용하므로 프로그램에서 클래스가 사용될 때 해당 클래스를 메모리에 로드하는 방법을 사용하고 있다

ClassLoader, Method Area

자바 프로그램이 실행되면 main 메소드가 호출되고 그 코드 안에서 다른 클래스가 사용될 때마다 ClassLoader 가 .class 파일을 로드하여 Method Area에 저장하면 이제부터 클래스 멤버는 사용될 수 있는 상태가 된다. 하나의 클래스는 단 한번만 로드되므로 코드의 다른 곳에서 이미 로드된 클래스의 멤버를 호출하더라도 이미 로드된 클래스라면 더 이상 클래스가 로드되는 과정은 없다

인스턴스를 생성하는 부분에서도 클래스가 로드된 상태가 아니면 먼저 클래스가 로드된 후에 인스턴스가 생성되는 절차를 거친다. 인스턴스 메소드도 클래스가 로드될 때 Method Area에 로드되지만 인스턴스를 이용하여 호출해야 하므로 반드시 인스턴스 생성 후에 그 인스턴스의 참조와 도트 연산자( . )를 이용하여 호출해야 한다. 바이트 코드에 포함된 인스턴스 메소드는 호출시에 반드시 인스턴스의 참조가 전달되어야 하는데, 그렇게 하려면 인스턴스의 참조를 이용하여 호출해야 하는 것이다. 인스턴스는 Heap Memory에 생성된다


클래스 멤버를 선언하고 사용하는 예

클래스 멤버변수가 필요한 때는 특정 클래스로부터 생성된 다수개의 객체가 한개의 변수를 공유하려는 경우이다. 아래의 예제에서는 User 클래스로터 생성된 모든 객체에서 domain 이라는 변수의 값을 공유하려는 의도가 있다는 가정하에 작성된 것이다. 

User 클래스의 객체를 다수개 생성하여 그 중 한개의 객체를 이용하여 domain 변수의 값을 변경하고 다른 객체를 통해 domain 변수의 값을 확인해보면 그 값이 변경된 것을 확인할 수 있을 것이다

public class Tutorials 
{
	public static void main(String[] args) 
	{
		User user = new User();
		user.setNum(10);
		user.setName("홍길동");
		user.setEmail("gildong@gmail.com");
		// 인스턴스의 참조를 이용해도 클래스 멤버에 접근할 수 있다
		user.setDomain("naver.com");
		
		user.printUser(); // 첫번째 객체의 참조를 이용한 출력
		
		User user2 = new User();
		user2.setNum(20);
		user2.setName("김인철");
		user2.setEmail("incholg@korea.com");
		
		user2.printUser(); // 두번째 객체의 참조를 이용한 출력
	}
}

class User
{
	private int num;     
	private String name;
	private String email;
	
	// static 키워드를 이용하여 클래스 멤버변수를 선언한다
	private static String domain = "google.co.kr";
	
	User(){}
	
	User(int num, String name, String email){
		this.num = num;
		this.name = name;
		this.email = email;
	}

	public void printUser()
	{
		System.out.println("====== 회원정보 ======");
		System.out.printf(" 번호 : %d %n", num);
		System.out.printf(" 이름 : %s %n", name);
		System.out.printf(" 메일 : %s %n", email);
		//인스턴스 멤버 안에서도 클래스 멤버에 접근이 가능하다
		System.out.printf(" 도메인 : %s %n", User.domain);
		//클래스 이름이 아니라 인스턴스 참조를 이용해도 클래스 멤버에 접근이 가능하다
		System.out.printf(" 도메인 : %s %n", this.domain);
	}
	
	// 클래스 메소드는 인스턴스와 무관하기 때문에 인스턴스 멤버에 접근할 수 없다
	public static void printDomain()
	{
		System.out.printf(" 도메인 : %s %n", User.domain);
		// 클래스 메소드 안에서는 this 키워드를 사용할 수 없다
		//System.out.printf(" 도메인 : %s %n", this.domain);
		// 클래스 메소드 안에서는 인스턴스 멤버에 접근할 수 없다
		//System.out.printf(" 번호 : %d %n", num);
	}
	
	// 클래스 getter 메소드
	public static String getDomain() {
		return domain;
	}

	// 클래스 setter 메소드
	public static void setDomain(String domain) {
		User.domain = domain;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
}


클래스 멤버로서 상수(Constants) 선언하기

static final String domain = "google.co.kr";

만약 다수개의 객체가 특정 상수를 공유하려는 경우에는 위와 같이 final 키워드를 사용하여 상수를 선언하면 된다