본문 바로가기
java/개념

static

by unhyepnhj 2024. 5. 20.

static 멤버의 선언

- static을 붙여 선언

class StaticSample{
	int n;
    void g(){...};
    
    static int m;
    static void f(){...};
 }

 

static 멤버와 non-static 멤버의 차이점

  non-static 멤버 static 멤버
선언 class Sample{
    int n;
    void g(){ ... }
}
class Sample{
    static int m;
    static void f(){ ... }
}
공간적 특성 멤버는 객체마다 별도 존재

- 인스턴스 멤버
멤버는 클래스당 하나 생성

- 객체 내부가 아닌 별도의 공간(클래스 코드가 적재되는 메모리)에 멤버 생성
- 클래스 멤버
시간적 특성 객체 생성 시 멤버 생성

- 객체가 생길 때 멤버도 생성
- 객체 생성 후 멤버 사용 가능
- 객체가 사라지면 멤버도 사라짐
클래스 로딩 시에 멤버 생성

- 객체 생성 전에 멤버 생성
- 객체 생성 전에도 멤버 사용 가능
- 객체가 사라져도 멤버는 사라지지 않음
- 멤버는 프로그램 종료 시 소멸
공유의 특성 공유되지 않음
- 멤버는 객체 내에 각각 공간 유지
동일한 클래스의 모든 객체들에 의해 공유

 

static 멤버

- 객체를 생성하지 않고도 사용할 수 있는 멤버

- 클래스다 하나만 생성됨

- 동일한 클래스의 모든 객체들이 공유

- main() 메소드가 실행되기 전에 생성

- static 멤버가 포함된 객체를 생성하기 전에도 사용 가능

- 클래스마다 하나씩 생기므로 클래스 멤버라 부르기도 함

 

non-static 멤버

- 객체가 생길 때 객체마다 생성

- 다른 객체들과 공유하지 않음

- 객체 소멸 시 non-static 멤버도 함께 소멸, 소멸 시 접근 불가

- 객체마다 하나씩 생기므로 인스턴스 멤버라 부르기도 함


static 멤버의 접근

1. 객체로 접근

2. 클래스로 접근

 

나는 처음 배울 때 이 부분이 헷갈렸다

non-static 멤버의 경우 .연산자 앞에 객체가 오고 뒤에는 멤버(필드나 메소드)가 온다.

non-static 멤버는 객체로 접근해야 한다는 뜻이다...

 

하지만 static 멤버는 객체와 클래스 두 가지 방식으로 접근할 수 있다

.연산자 앞에 객체와 클래스가 모두 올 수 있다는 뜻

class Sample{
	int n;			//non-static 멤버
	void f() { n=10; }	//non-static 멤버
	static int m;
   	static void g(){ m=20; }
}

public class Main{
	public static void main(String[] args){

		Sample sample = new Sample();
        
		sample.n=5;
		sample.f();
		//non-static 멤버인 n, f()에 객체로 접근할 수 있지만
		Sample.n=10;
		Sample.f();
		//클래스로는 접근할 수 없다
		
		sample.m=5;
		sample.g();
		//static 멤버인 m, g()에 객체로도 접근할 수 있고
		Sample.m=10;
		Sample.g();
		//클래스로도 접근할 수 있다
    }
}

코드를 실행시켜 보면 n과 f()에 Sample클래스로 접근하는 부분(라인 16~17)에 오류가 날 것이다

왜 헷갈렸나 싶었는데 아직 클래스와 메소드 부분을 확실히 몰랐었던 것 같다

다음부터는 교재 설명(나의 눈높이 설명이 더 쉬울 것이다)


 

static 멤버를 객체의 멤버로 접근

 

1. static 멤버 생성

- static 멤버가 생성되는 시점은 StaticSample이 사용되기 시작하는(로딩되는) 시점

StaticSample s1, s2;

- 위 코드가 실행되는 시점에 static 멤버 m과 f()는 이미 존재하며 사용이 가능

s1 = new StaticSample();
s2 = new StaticSample();

- static 멤버 m과 f()는 위 두 객체가 생성되기 이전에 이미 생성

- s1과 s2 객체가 생성될 때 인스턴스 멤버인 n, g(), h()만 객체마다 생성

 

2. static 멤버 접근

객체.static멤버

- non-static 멤버와 동일한 형식으로 접근 가능


static 멤버를 클래스 이름으로 접근

- static 멤버는 클래스당 하나만 있기 때문에 클래스 이름으로 바로 접근 가능

- non-static 멤버는 클래스 이름으로 접근 불가


static의 활용

 

1. 전역 변수와 전역 함수를 만들 때 활용

- 자바에서는 C++과 달리 어떤 변수나 함수도 클래스 바깥에 존재할 수 없음(캡슐화 원칙)

- 따라서 모든 클래스에서 공유하는 전역 변수나 전역 함수가 필요할 때 static 사용

- 대표적 사례: java.lang.Math 클래스

public class Math{
	public static int abs(int a);
    public static double cos(double a);
    public static int max(int a, int b);
    public static double random();
    ...
 }

- Math 클래스는 객체를 생성하지 않고 바로 호출할 수 있는 static 타입의 멤버를 제공

Math m = new Math();	//잘못된 사용법
int n = m.abs(5);

- 응용프로그램에서 Math 클래스의 멤버들을 사용하기 위해 객체를 따로 생성하지 않음

- Math 클래스의 생성자 메소드가 private이므로 객체로 접근 불가

int n = Math.abs(-5);	//올바른 사용법

- 클래스 이름인 Math로 static 멤버를 직접 호출

 

+

함수를 바로 쓰고 싶은데 매번 객체를 생성하기에는 낭비니까 자주 사용하는 것들은 클래스에서 바로 접근할 수 있게 하는 것이다

클래스의 멤버가 static이므로 원래는 객체와 클래스 모두로 접근할 수 있는데

Math 클래스의 생성자 메소드가 private 멤버이므로 이 경우 객체로 접근할 수 없다

원래는 된다 

 

2. 공유 멤버를 작성할 때 활용

- static 멤버는 하나만 생성되어 클래스의 객체들 사이에서 공유됨


static 메소드의 제약 조건

 

1. static 메소드에 non-static 멤버가 접근 불가

- static 메소드는 객체가 생성되지 않은 상황에서도 실행 가능하기 때문에 non-static 메소드와 필드 사용 불가

- non-static 메소드는 static 멤버 사용 가능

 

2. static 메소드는 this 사용 불가

- static 메소드는 객체 없이도 존재

- this는 현재 객체를 가리키므로 사용 불가


예제 4-11 전역 함수로 작성하고자 하는 abs, max, min의 3개 함수를 static 메소드로 작성하고 호출하는 프로그램 작성

 

예제 4-12 static 멤버를 이용하여 달러와 원화를 변환해주는 환율 계산기 프로그램 작성

더보기
import java.util.Scanner;
class CurrencyConverter{
	public static double currency;
	static String whatToDo;
	
	public static void setCurrency(double c) {
		currency=c;
	}

	public static void whatToConvert(int choice) {
		if(choice==1) whatToDo="dollarToWon";
		else if(choice==2) whatToDo="wonToDollar";
		else if(choice==3) whatToDo="break";
		else whatToDo="showError";
	}
	
	public static void dollarToWon(double original) {
		System.out.println(original*currency+"원");
	}
	
	public static void wonToDollar(double original) {
		System.out.println("$"+original/currency);
	}
}

public class Main {
	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		int currency;
		int choice=0;
		double original;
		
		System.out.print("환율 입력(1달러): ");
		currency=scanner.nextInt();
		CurrencyConverter.setCurrency(currency);
		
		while(true) {
			System.out.println();
			System.out.println("1. 달러를 원화로");
			System.out.println("2. 원화를 달러로");
			System.out.println("3. 종료");
			choice=scanner.nextInt();
			
			CurrencyConverter.whatToConvert(choice);
			
			if(CurrencyConverter.whatToDo=="dollarToWon") {
				System.out.print("변환할 금액(달러): ");
				original=scanner.nextInt();
				CurrencyConverter.dollarToWon(original);
			}
			else if(CurrencyConverter.whatToDo=="wonToDollar") {
				System.out.print("변환할 금액(원): ");
				original=scanner.nextInt();
				CurrencyConverter.wonToDollar(original);
			}
			else if(CurrencyConverter.whatToDo=="break") {
				System.out.println("종료합니다.");
				break;
			}
			else System.out.println("오류: 1~3 번 중 선택하세요.");
		}	
		
		scanner.close();
	}
}

 

교재 예제랑은 조금 다르게 했다

교재는 뭐에서 뭘로 변환할지 선택하는 기능, 변환할 금액 입력하는 기능 없이 환율만 입력하는 코드로 돼 있던데 밋밋해서 바꿨다

아래는 실행창

'java > 개념' 카테고리의 다른 글

상속  (0) 2024.05.21
final  (0) 2024.05.20
접근 지정자  (0) 2024.05.20
객체 소멸과 가비지 컬렉션  (0) 2024.05.20
메소드 활용 - 메소드 오버로딩  (0) 2024.05.20