8. static


1. static

a. 메모리영역

  • 메서드 영역 : 메서드의 바이트코드, static 변수
  • stack 영역 : 값 타입, 지역변수, 매개변수 등
  • heap영역 : 참조타입, 인스턴드 등 / 메서드는 공유하지만 객체는 영역을 따로 할당

  • heap메모리영역
// 참조타입 메모리 영역 확인
class Person{
	//1. 멤버변수
	private String name;
	private int age;
	public int count; // 카운트 변화 확인
	
	//2. 생성자
	Person(String name, int age){
		this.name = name;
		this.age = age;
    System.out.println(++count); // 객체 생성될 때 카운트를 찍어 변화하는지 확인
	}
	
	//3. 메서드
	public void display() {
		System.out.println("이름:" + name);
		System.out.println("나이:"+ age+"\n");
	}
}

public class PersonTest {

	public static void main(String[] args) {
		Person hong = new Person("홍길동", 20); //heap 영역에 hond 이라는 객체 생성
		hong.display(); // 카운트 1

		
		Person kim = new Person("김길동", 20); // heap 영역에 kim 이라는 객체 생성
		kim.display(); // 카운트 1, 카운트가 변화하지 않는다

	}
}
  • 메서드 영역
class Person{
	//1. 멤버변수
	private String name;
	private int age;
	public static int count; // 카운트 변화 확인 (static변수)
	
	//2. 생성자
	Person(String name, int age){
		this.name = name;
		this.age = age;
    System.out.println(++count); // 객체 생성될 때 카운트를 찍어 변화하는지 확인
	}
	
	//3. 메서드
	public void display() {
		System.out.println("이름:" + name);
		System.out.println("나이:"+ age+"\n");
	}
}

public class PersonTest {

	public static void main(String[] args) {
		Person hong = new Person("홍길동", 20); //heap 영역에 hond 이라는 객체 생성
		hong.display(); // 카운트 1

		
		Person kim = new Person("김길동", 20); // heap 영역에 kim 이라는 객체 생성
		kim.display(); // 카운트 2, static변수는 공유

	}
}

b. static 변수 (정적멤버)

  • 개별 객체에 소속되지 않는다
  • 클래스에 직접 소속된다.
  • 메서드 영역에 메모리가 저장된다.
  • 메모리에 딱 한번 생성되며 모든 객체가 공유한다.
  • 객체로 생성되어 참조하지 않고 클래스 차원에서 바로 호출 가능
    • 클래스의 이름으로 접근
  • 초기화 시점
    • jvm에 의해 클래스가 메모리 공간에 올라가는 순간 ```java class BankAccount{ //1. 멤버변수 //1.1 인스턴스변수 private int balance;

    //1.2 static 변수 public static final double INTEREST_RATE = 0.02; private static int totalBalance;

    //2. 생성자 public BankAccount(int balance) { this.balance=balance; }

    //3. get,set public int getBalance() { return balance; } public void serBalance(int balance) { this.balance=balance; } public static int getTotalbalance(){ return totalBalance; } public static void setTotalbalance(int totalBalance) { //static에는 this 사용 불가 BankAccount.totalBalance=totalBalance; }

    //4. 메서드 public void findTotal() { totalBalance+=balance; }

}

public class AccountStatic {

public static void main(String[] args) {
	BankAccount acc1 = new BankAccount(100000);
	BankAccount acc2 = new BankAccount(200000);
	
	acc1.findTotal();
	acc2.findTotal();
	
	System.out.println("계좌1의 원금 : " + acc1.getBalance());
	System.out.println("계좌2의 원금 : " + acc2.getBalance());
	System.out.println("이율 : " + BankAccount.INTEREST_RATE);
	System.out.println("전 계좌의 원금의 합계 : " + BankAccount.getTotalbalance());

} } ```

final : 읽기전용, 값을 바꿀 수 없도록 묶음

c. static 변수 초기화

  • static 초기화 블럭
    • 생성자와 비슷하지만 블럭 내에서 조건문 등을 사용할 수 있다.
    • 초기화 작업이 복잡하여, 단순 초기화(명시적 초기화)로 부족한 경우 사용

      static{ }

class StaticBlock{
	static int[] arr = new int[10]; // 명시적 초기화
	
	//static 초기화 블럭
	static {
		for(int i=0; i<arr.length;i++) {
			arr[i] = (int)(Math.random()*10+1);
		}
	}//초기화 블럭 내 for구문을 통해 arr변수 초기화
}

public class StaticBlockTest {

	public static void main(String[] args) {
		for(int i=0;i<StaticBlock.arr.length;i++) {
			System.out.println(StaticBlock.arr[i]);
		}
	}
}
  • 변수별 초기화 시기 및 순서
    • 클래스변수
      • 클래스가 처음 로딩될 때 한번 초기화
      • default값 -명시적초기화 -static초기화블럭
    • 인스턴스변수
      • 인스턴스가 생성될 때마다 각 인스턴스별로 초기화
      • default값 -명시적초기화 -생성자

d. static 메서드

  • 클래스에 소속
  • 개별 객체에 대한 동작이 아닌, 클래스 차원의 동작 처리
  • 객체에 대한 처리가 아니기 때문에, 객체에 대한 참조자 this 사용 불가
  • 생성된 객체가 없어도 호출 가능
  • 클래스 소속의 static 필드만 액세스 할 수 있음
    • 인스턴스 필드는 아직 메모리에 올라가기 전이기 때문
    • static메서드는 static 멤버변수만 사용
  • 자주 사용하는 메서드를 static 처리, 클래스 차원에서 호출
    • 메서드를 사용하기 위해 매번 인스턴스 전체를 불러오는 것을 방지
    • 메모리 효율
  • static / instance 메서드 호출 예)
class Calculator{
	//static 메서드
	public static int add(int a, int b) {
		return a+b;
	}
	
	//instance 메서드
	public int subtract(int a, int b) {
		return a-b;
	}
}

public class CalculatorTest {

	public static void main(String[] args) {
		//static 메서드 호출 : 클래스명.메서드();
		int result = Calculator.add(10,30);
		System.out.println("합" + result);
		
		//int n = Integer.parseInt("123");  static 메서드
		
		//instance 메서드 호출 : 객체 생성 후 참조변수.메서드();
		Calculator cal = new Calculator();
		result = cal.subtract(50,20);
		System.out.println("차"+result);
		
		//Scanner sc = new Scanner(System.in); //Scanner 객체 생성
		//int num = sc.nextInt(); // instance 메서드
	}

}
  • static메서드의 static/instance 접근 예)
public class StaticTest {
	private int num1 = 10; // 인스턴스 변수
	private static int num2=20; // static 변수
	
	public int add() { //인스턴스 메서드
		return num1+num2; // static 변수 접근 가능
	}
	
	/*
	public static int mul() {
		return num1*num2; // error 인스턴스 변수 num1에 접근불가
	}
	*/
	
	public static int mul(int a, int b) {
		return a*b;
	}
			

	public static void main(String[] args) {
		int result = mul(4,4); // static 메서드 호출 : 클래스명.메서드()
								// 같은 클래스이므로 클래스명 생략, 메서드()
		System.out.println(result);

		//add(); //main 또한 static메서드 - 인스턴스 메서드 호출 불가, 객체생성 필요
		StaticTest a = new StaticTest();
		result = a.add();
		System.out.println(result);
	}

}

e. 변수의 종류

  • 멤버변수 : 클래스 영역에 선언
    • static 변수
      • 모든 객체가 공유, 클래스 차원에서 단 하나만 생성
      • 클래스가 로딩될 때 생성, 프로그램 종료까지 유지
      • default 값으로 초기화
    • 인스턴스 변수
      • 객체를 생성할 때 만들어진다
      • 객체마다 다른 값을 가질 수 있다
      • 0, false, null값으로 초기화
  • 지역변수 : 메서드 내부에서 선언된 변수
    • 메서드가 시작될 때 생성
    • 메서드를 빠져나갈 때 사라짐
    • 블럭변수
      • 메서드 내 또다른 블록(if, for 등) 내에서 선언된 변수