[자바] static 키워드

Gammi·2022년 10월 19일
0

JAVA

목록 보기
13/35
post-thumbnail

< 자바 프로그램 실행 과정 >

  1. 소스 코드 작성 및 컴파일 후 클래스 실행
  2. 클래스 로딩(static 변수 및 메서드 메모리에 로딩)
  3. main() 메서드 호출
  4. 인스턴스 생성(인스턴스 변수 및 메서드 메모리에 로딩)
  5. 인스턴스 메서드 호출(로컬 변수 메모리에 로딩)
  6. 결과 출력
  7. 프로그램 종료



📚 static 키워드


  • 클래스, 메서드, 변수의 제한자로 사용

  • 메서드 또는 변수에 static 키워드 사용할 경우 인스턴스 생성과 관계없이 클래스가 로딩되는 시점에 메모리에 로딩됨

    -> 참조변수 없이 클래스명만으로 멤버에 접근 가능

    (인스턴스 생성 없이도 접근 가능한 멤버)

  • 인스턴스 멤버가 아닌 클래스 멤버로 취급


< 기본 문법 >

클래스명.변수명
클래스명.메서드명()





📕 static 변수


  • 멤버변수에 static 키워드 사용할 경우 클래스 멤버로 취급

  • 인스턴스 생성 전, 클래스가 메모리에 로딩될 때 함께 로딩

    -> 모든 인스턴스에 하나의 변수 공유

    -> 클래스 당 하나만 생성됨

    -> 인스턴스 생성 없이도 사용 가능


< 기본 문법 >

클래스명.멤버변수명


public static void main(String[] args) {
  NormalMeber n1 = new NormalMeber(); // 인스턴스 생성
  NormalMeber n2 = new NormalMeber(); // 인스턴스 생성
  
  system.out.println("n1.a : " + n1.a + ", n2.a : " + n2.a);
  // n1.a = 10 / n2.a = 10 출력됨
  system.out.println("n1.b : " + n1.b + ", n2.b : " + n2.b);
  // n1.b = 20 / n2.b = 20 출력됨
  
  n1.a = 99; // n1 인스턴스의 인스턴스 멤버변수 a 값 변경
  n2.b = 99; // n1 인스턴스의 인스턴스 멤버변수 b 값 변경
  
  system.out.println("n1.a : " + n1.a + ", n2.a : " + n2.a);
  // n1.a = 99 / n2.a = 10 출력됨
  system.out.println("n1.b : " + n1.b + ", n2.b : " + n2.b);
  // n1.b = 99 / n2.b = 20 출력됨
  // n1의 값만 바뀌고 n2 인스턴스의 값은 여전히 10, 20으로 동일함
  // 하나의 인스턴스에서 인스턴스 멤버변수 값을 바꾸더라도
  // 다른 인스턴스 멤버변수에는 아무런 영향이 없음!!!!
  
//=======================================================
  
  StaticMember s1 = new StaticMember(); // 인스턴스 생성
  StaticMember s2 = new StaticMember(); // 인스턴스 생성
  
  system.out.println("s1.a : " + s1.a + ", s2.a : " + s2.a);
  // s1.a = 10 / s2.a = 10 출력됨
  system.out.println("s1.b : " + s1.b + ", s2.b : " + s2.b);
  // s1.b = 20 / s2.b = 20 출력됨
  
  s1.a = 88; // static 멤버변수 a 값 변경
  s1.b = 88; // 인스턴스 멤버변수 b 값 변경
  
  system.out.println("s1.a : " + s1.a + ", s2.a : " + s2.a);
  // s1.a = 88 / s2.a = 88 출력됨
  system.out.println("s1.b : " + s1.b + ", s2.b : " + s2.b);
  // s1.b = 88 / s2.b = 20 출력됨
  // static 멤버변수 값을 변경하면 다른 인스턴스 멤버변수 값도 바뀜
  // 인스턴스 멤버변수는 값 그대로(b)
  // 따라서 하나의 인스턴스에서 값을 변경하면 모든 인스턴스가 영향 받음
}

class NormalMember {
  int a = 10;
  int b = 20;
  // 둘 다 인스턴스 멤버변수
}

class StaticMember {
  static int a = 10; // static 멤버변수
  // 이클립스에 적으면 기울어져서 적힘
  int b = 20; // 인스턴스 멤버변수
}

🔗 참고

static 멤버변수는 참조변수명 대신 클래스명만으로도 접근이 가능하다!

S1.a = 10;이 일반적인 방법이지만
StaticMember.a = 20;으로도 접근이 가능!





📕 static 메서드


  • 정적 메서드

  • 메서드 정의 시 리턴타입 앞에 static 키워드 붙여서 정의

  • 클래스가 메모리에 로딩될 때 static 변수와 함께 메모리에 로딩되므로 인스턴스 생성과 무관

  • 클래스명만으로 접근 가능


< 기본 문법 >

클래스명.메서드명()





⛔ static 메서드 정의 시 주의사항


  1. 인스턴스 변수 사용 불가
  • 원인

    -> static 메서드가 로딩 시점 : 클래스 로딩 시점

    -> 인스턴스 변수 로딩 시점: 인스턴스 생성 시점

    => static 메서드가 로딩되는 시점에서 인스턴스 변수는 존재하지 않음


  1. 레퍼런스 this 또는 super 사용 불가
  • 원인

    -> static 메서드가 로딩 시점 : 클래스 로딩 시점

    -> 레퍼런스 this 생성 시점: 인스턴스 생성 시점

    => static 메서드가 로딩되는 시점에서는 this나 super가 존재하지 않음

  • 해결책

    -> this.XXX 또는 super.XXX 대신

    => 클래스명.XXX 형식으로 접근


  1. 메서드 오버라이딩 불가



public static void main(String[] args) {
  StaticMethod.staticMethod();
  // static 메서드도 static 멤버변수처럼 인스턴스 생성 없이 클래스명만으로 접근 가능
  
  StaticMethod.setStaticVar(99);
  // private 접근제한자를 적용했기 때문에 set으로 접근해야함
  
  StaticMethod sm = new StaticMethod();
  // 인스턴스 생성해야지 일반 메서드 호출 가능
  
  sm.normalMethod(); // 일반 메서드 호출
  sm.staticMethod(); // 정적 메서드 호출 (올바른 접근 방법X)
  StaticMethod.staticMethod(); // 정적 메서드 올바른 접근
}

class StaticMethod {
  private int normalVar = 10; 
  // 인스턴스 멤버변수 선언 및 초기화
  private static int staticVar = 20; 
  // static 멤버변수(정적 멤버변수) 선언 및 초기화
  
  public void normalMethod() { // 일반 메서드
    System.out.println(normarlVar);
    System.out.println(staticVar);
    // 일반 메서드에서는 인스턴스 멤버변수와 정적 멤버변수 모두 접근 가능
    
    staticMethod();
    // 일반메서드에서 static 메서드도 호출 가능!
  }
  
  public static void staticMethod() {
    System.out.println(normarlVar);
    // !!!컴파일 에러!!!
    // 인스턴스 변수는 아직 로딩되기 전이기 때문에 접근 불가
    System.out.println(staticVar);
    // static 멤버변수는 접근 가능
    
    normalMethod(); // !!!컴파일 에러!!!
    // 위와 마찬가지로 아직 일반 메서드는 로딩 전이므로 호출 불가
  }
 
  public void setNormalVar(int normalVar) {
    this.normalVar = normalVar;
    // 인스턴스 변수 normalVar에 대한 Setter 정의
  }
  
  public static void setStaticVar(int staticVar) {
    StaticMethod.staticVar = staticVar;
    // static 메서드는 this 사용 불가!
    // 레퍼런스 this 대신 클래스명으로 변수 접근 가능!
}





< static 멤버와 인스턴스 멤버의 메모리 할당 순서 >

  1. Ex 클래스가 메모리에 로딩됨
  2. static 키워드가 선언된 모든 멤버가 메모리에 로딩됨
  3. static 멤버가 메모리에 로딩될 때 변수 a와 c에 check() 메서드 리턴값이 전달되어야 하므로 static 메서드인 check() 메서드 호출됨
  4. main() 메서드 자동으로 호출됨
  5. main() 메서드 내에서 Ex 인스턴스 생성됨
  6. Ex 인스턴스 생성 시 인스턴스 변수 b가 메모리에 로딩되며 인스턴스 변수 b가 로딩될 때 check() 메서드 호출됨
  7. Ex 인스턴스 생성 후 main() 메서드의 다른 코드 실행

⭐ 입력

public class Ex {
  int b = check("인스턴스 변수 b");
  static int a = check("static 변수 a");
  
  public static int check(String str) {
    System.out.println("check() 호출 : " + str);
    return 0;
    // 리턴값 주는 이유?
    // 인스턴스 변수 b랑 static 변수 a, c 모두 int 타입!
    // 변수에 check(String str)을 대입하고 있는데
    // int 타입에는 int 대입해야함
    // 그래서 return 해서 int 타입 대입하는 것!
  }
  
  public static void main(String[] args) {
    System.out.println("main() 메서드 호출");
    Ex ex = new Ex();
    System.out.println("Ex 인스턴스 생성 완료");
  }
  static int c = check("static 변수 c");
}

📌 출력

check() 호출 : static 변수 a
check() 호출 : static 변수 c
main() 메서드 호출
check() 호출 : 인스턴스 변수 b
Ex 인스턴스 생성 완료

  1. check() 호출 : static 변수 a
    check() 호출 : static 변수 c

    -> static 변수 먼저 로딩됨!

    -> 위에서부터 순서대로 a 먼저 출력되고 c가 출력됨

    -> static int a = check("static 변수 a")check()a에 대입하겠다는 말이니까 check()가 실행되는 것!!

    -> 리턴값 출력하고 싶으면 System.out.println(a); 출력하면 됨

    -> 리턴값은 저장은 되어 있으나 출력하지 않아서 안 나오는 것뿐...


  1. main() 메서드 호출

    -> static 변수 먼저 출력하고 이제 main() 로딩됨


  1. check() 호출 : 인스턴스 변수 b

    -> Ex ex = new Ex(); 이 코드의 출력문

    -> 왜 인스턴스 생성밖에 안했는데 출력됐지 했는데

    => Ex 인스턴스를 생성하는 순간 int b가 동시에 로딩되는 거
    그래서 check() 실행되서 출력문이 나오는 거라고 함!!!!


  1. Ex 인스턴스 생성 완료

    -> 얘는 그냥 순서대로 제일 마지막 코드 실행된 거임

profile
개발자가 되었어요⭐️

0개의 댓글