본문 바로가기
Backend/Java-Spring

[Java] Math과 Random의 비교로 살펴보는 static의 역할

by 벨롭 (valop) 2023. 9. 6.

0~9 사이의 난수를 생성하기 위해서는 대표적으로 두 가지 방법이 있다.

 

 

1. Math.random() 사용

 

int randomNum = (int) (Math.random() * 10);

 

 

2. Random클래스의 인스턴스 생성 후 nextInt 메서드 사용

 

Random rand = new Random();
int randomNum = rand.nextInt(10);

 

 

두 가지 방법을 비교할 때 가장 큰 차이점은 객체 생성 유무다.

Math 클래스는 객체를 생성하지 않았는데도 random 메서드에 접근할 수 있었다.

하지만 Random 클래스는 new 연산자를 이용해 객체를 생성한 다음에야 메서드를 사용할 수 있다.

 

 

 

 

 

각 메서드가 어떻게 선언되어있는지를 확인해보자, 

출처: Java Platform Standard Edition 8 Documentation

Math클래스의 random메서드에는 static이라는 키워드가 추가되어 있다.

그러면 static 키워드의 역할은 무엇일까?

 

 

 

 

이를 알기 위해 먼저 필드와 메서드는 인스턴스(instance) 멤버와 정적(static) 멤버의 차이를 짚고 가야 한다.

인스턴스 멤버는 객체에 소속된 필드와 멤버이다. 객체에 소속되어 있기 때문에 객체를 생성해야만 접근할 수 있다.

정적 멤버는 클래스에 고정된 멤버이다. 그렇기 때문에 객체를 통하지 않고 바로 클래스를 통해서 접근할 수 있다.

 

static은 바로 이 정적 멤버를 선언하기 위한 키워드이다.

 

class Person{
	
	// 정적 멤버 선언
	static void starve() {
		System.out.println("굶습니다.");
	}
    
	// 인스턴스 멤버 선언  
	void eat() {
		System.out.println("밥을 먹습니다.");
	}
    
}

 

 

 

eat() 메서드와 starve() 메서드는 호출 방법또한 다르다.

 

// 정적 멤버 - 객체 생성이 필요 없음
person.starve();

// 인스턴스 멤버 - 객체 생성 후 메서드 호출
Person p1 = new Person();
p1.eat();

 

 

 

 

 

static의 역할을 기억한 상태에서 다시 Math.random()과 Random클래스의 nextInt()메서드로 돌아가보자

출처: Java Platform Standard Edition 8 Documentation

 

둘 중 정적 멤버와 인스턴스 멤버를 구분할 수 있는가?

그렇다. 바로 Math클래스의 random은 정적 멤버, Random클래스의 nextInt()는 인스턴스 멤버이다.

그래서 전자에서는 클래스에서 바로 random 메서드로 접근했지만 nextInt()는 Random클래스의 인스턴스를 생성한 후에 객체를 통해 접근했던 것이다.

 

 

 

 

 

그렇다면 클래스를 선언할 때 인스턴스 멤버와 정적 멤버는 각각 어떤 상황에서 사용하면 좋을까?

 

우선 인스턴스 필드와 정적 필드가 메모리 상에서 어떻게 관리되는지를 생각해보자.

인스턴스 필드는 heap영역상에 생성된 객체에 포함되어 생성된다. 그렇기 때문에 같은 클래스를 인스턴스화 하더라도 객체마다 따로 존재하게 된다. 그렇기 때문에 각 객체마다 값을 다르게 저장해야할 필요가 있다면 인스턴스 필드를 사용하는 것이 좋다.

정적 필드는 각 객체가 아닌 메소드 영역에 위치한다. 그렇기 때문에 동일한 클래스의 객체가 여러개 있더라도 항상 같은 값을 공유한다. 만약 모든 객체가 같은 값을 공유해야한다면 정적 필드를 주로 사용한다.

 

 

필드의 케이스와 달리, 인스턴스 메서드와 정적 메서드는 모두 메모리 내의 메소드 영역에 위치한다. 그러면 왜 구분해서 사용하는 것일까?

정적 메서드는 객체를 생성하지 않아도 실행된다. 그렇기 때문에 객체를 생성해야만 접근할 수 있는 인스턴스 필드나 다른 인스턴스 메서드를 사용할 수 없다. 또한 객체 자신을 참조하는 this도 사용할 수 없다. 그렇기 때문에 인스턴스 멤버를 이용하는 메서드는 인스턴스 메서드로 선언해야만 하고, 인스턴스 멤버를 이용하지 않는다면 정적 메서드로 선언하게 된다.

 

(참고로 정적 멤버에서 인스턴스 멤버를 사용하고 싶다면 블럭 내에서 객체를 먼저 생성해야한 한다. )