ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JAVA] Static이란? / Static변수 및 메소드 호출
    Language/Java 2019. 10. 6. 17:20

     

     

    지난 포스팅에서 Static키워드를 사용하면 프로그램 실행 시 메모리에 할당되고 이는 프로그램 종료 시까지 유지된다고 했습니다.

     

    이러한 이유때문에 static변수나 static메소드들은 해당 클래스의 객체를 생성하지 않고도 접근할 수 있다는 특징이 있습니다. 이 내용을 설명하기에 앞서 non-static변수, 메소드에 접근하는 방법에 대해 먼저 설명을 해야 할 것 같은데요.

     

    이제 조금 익숙한 그림입니다.

     

    프로그램을 실행한 직후에는 Heap영역에 Car객체가 없을 것입니다. 그림에 보시는 것과 같이 메모리에 객체가 생성되는 것은 new키워드를 통해 Car객체를 생성했을 시점인데요.

     

    public class Test{
    
    	  public static void main(String [] args){
    	    
    	    Car benz = new Car();		// 바로 요 시점!
    	    System.out.println("--------------벤츠--------------");
    	    benz.setPrice(300);
    	    benz.setColor("blue");
    	    benz.drive(80);
    	    System.out.println("price : "+benz.getPrice());
    	    System.out.println("color : "+benz.getColor());
    	    System.out.println("benz : "+benz);
    
    	    ...
    	    
    	  }
    	}

     

    그렇기 때문에 일반적인(non-static)경우 해당 클래스의 객체를 생성하지 않으면 그 클래스 내의 멤버 변수(전역 변수)나 메소드에 접근할 수 없습니다. (객체를 생성하지 않으면 메모리에 해당 데이터 자체가 없기 때문이죠.)

     

    그렇다면 static키워드를 사용하는 경우에는 어떻게 다를까요? Car class의 drive메소드와 stop메소드에 static키워드를 붙여주고, 다른 class에서 메소드를 호출해보겠습니다.

     

    public class Car {
    
    	private int price;
    	private String color;
    
    	public static void drive(int speed) {
    		System.out.println(speed + "km/h 로 주행합니다.");
    	}
    
    	public static void stop() {
    		System.out.println("주행을 멈춥니다.");
    	}
    
    	public int getPrice() {
    		return price;
    	}
    
    	public void setPrice(int price) {
    		if (price >= 0 && price < 500) {
    			this.price = price;
    		}
    	}
    
    	public String getColor() {
    		return color + " color";
    	}
    
    	public void setColor(String color) {
    		this.color = color;
    	}
    
    }
    public class Test2 {
    
    	public static void main(String[] args) {
    		Car.drive(70);
    		Car.stop();
    		Car.getPrice(); // getPrice()메소드는 현재 메모리에 할당되지 않은 상태
    	}
    
    }

     

    다음과 같이 코드를 작성해서 실행시켜보면 getPrice() 메소드를 호출하는 부분에서 에러가 발생함을 확인할 수 있습니다. Car 클래스의 객체가 생성되지 않은 상태이기 때문에 현재 메모리에는 getPrice() 메소드가 할당되어있지 않고, 접근할 수 없는 상태입니다. 해당 코드라인을 지운 후 실행하면 정상적으로 실행되는데요, drive메소드와 stop메소드는 static메소드이기 때문에 프로그램 실행과 동시에 메모리에 적재되기 때문에 문제없이 실행될 수 있는 것입니다.

     

    그렇다면 Car 클래스에서 getPrice() 메소드를 static메소드로 선언하면 안 되는 걸까요?

    getPrice() 메소드를 static메소드로 수정해보면 에러가 발생하는 것을 확인할 수 있는데요, 그 이유는 getPrice() 메소드 내에서 사용하는 price변수 때문입니다.

     

    public class Car {
    
    	private int price;
    	private String color;
    
    	public static void drive(int speed) {
    		System.out.println(speed + "km/h 로 주행합니다.");
    	}
    
    	public static void stop() {
    		System.out.println("주행을 멈춥니다.");
    	}
    
    	public static int getPrice() {		// 에러 발생
    		return price;
    	}
    
    	...
        
    }

     

    다음과 같이 작성된 Car class의 getPrice() 메소드를 Test2 class에서 호출해봅시다. Test2 class에서는 Car객체를 생성하지 않고 바로 getPrice() 메소드를 호출하고 있습니다. 가능하죠. getPrice() 메소드는 static메소드이기 때문입니다. 

     

    하지만 getPrice() 메소드 내에서 사용하는 price변수는 static변수가 아닙니다. 그렇기때문에 Car객체를 생성하지 않으면 price변수는 메모리에 할당되지 않은 상태인 것이죠. getPrice() 메소드 내에서는 호출된 시점에 Car객체가 생성되었는지 아닌지 여부를 확인할 방법이 없습니다. 따라서, 에러가 발생하는 것입니다.

     

    그렇다면 price변수도 static변수로 선언하면 되는 것이 아닌가? 하는 생각을 할 수 있습니다.

     

    결론부터 말씀드리자면, 에러는 발생하지 않겠지만 개발자가 원하는 결과는 아닐 수 있습니다. static키워드를 사용하게 되면 Heap메모리가 아닌 별도의 메모리 공간에 할당된다고 했습니다. 이렇게 할당된 static변수는 새로운 객체를 생성해도 같은 변수를 공유하게 됩니다.

     

    다음 코드를 통해 확인해보겠습니다.

    price변수와 setPrice(), getPrice() 메소드를 static키워드로 선언하고 다음과 같이 메소드를 호출해보았습니다.

     

    public class Test2 {
    
    	public static void main(String[] args) {
    		System.out.println("price : "+Car.getPrice());		// 결과> 0
            
    		Car.setPrice(100);
    		Car bmw = new Car();
    		System.out.println("price : "+Car.getPrice());		// 결과> price : 100
    		System.out.println("bmw price : "+bmw.getPrice());	// 결과> bmw price : 100
            
    		bmw.setPrice(200);
    		System.out.println("price : "+Car.getPrice());		// 결과> price : 200
    		System.out.println("bmw price : "+bmw.getPrice());	// 결과> bmw price : 200
    	}
    }
    

     

    초기에 멤버 변수는 0에 준하는 값으로 초기화되기 때문에 데이터 타입이 int인 price변수는 0으로 초기화가 됩니다. 그래서 처음 price값은 0입니다.

     

    setPrice() 메소드를 통해 price변수의 값을 100으로 할당한 후, bmw라는 이름을 가진 Car객체를 생성했습니다. 앞선 포스팅에서 new 키워드를 통해 생성한 각각의 객체들은 모두 별개의 객체라는 것을 확인했습니다. 하지만 bmw객체의 getPrice() 메소드를 호출한 결과값은 0이 아닌 100이 출력됐습니다.

     

    마찬가지로 bmw객체의 setPrice() 메소드를 통해 price값을 200으로 할당하고, getPrice() 메소드를 호출한 결과 둘 다 200으로 값이 변경된 것을 확인할 수 있습니다.

     

    이로써 static변수가 해당 클래스의 객체들 간에 공유된다는 것을 확인할 수 있습니다.

Designed by Tistory.