[Java] 자바 스태틱 블록 (static block), 인스턴스 블록 (instance block), 생성자


1. static block (스태틱 블록)

-클래스가 로딩되고 클래스 변수가 준비된 후 자동으로 실행되는 블록

- 한 클래스 안에 여러 개의 static 블록을 넣을 수 있다.

- 용도 :

  주로 클래스 변수를 초기화시키는 코드를 둔다.


static block 예제


  static class Student {

    static String name = "홍길동"; // 변수 선언에 값을 초기화시키는 문장을 포함할 수 있다.
    static {
      System.out.println("static...1");
      name = "임꺽정";
    }
    static {
      System.out.println("static...2");
      name = "유관순";
    }

  }


- 실행 순서 :

  1) 클래스가 로딩된다. 

  2) 클래스 변수가 있으면 메모리를 생성한다..

  3) static 블록이 선언된 순서대로 실행된다.



* 참고 : 클래스 로딩 절차


 1) JRE 라이브러리 폴더에서 클래스를 찾는다.

 2) 없으면, CLASSPATH 환경 변수에 지정된 폴더에서 클래스를 찾는다.

 3) 찾았으면, 그 클래스 파일이 올바른 바이트코드인지 검증한다.

 4) 올바른 바이트코드라면, Method Area 영역으로 파일을 로딩한다.

 5) 클래스 블록이 있으면 순서대로 그 블록을 실행한다.

 6) 클래스 안에 static block (스태틱 블록)들이 있으면 순서대로 그 블록을 실행한다.



static block (스태틱 블록)과 변수의 호출 코드


public static void main(String[] args) {

    Student.name = "하하하";
    System.out.println(Student.name);

  }

- 실행 결과

static...1

static...2

하하하






2. instance block (인스턴스 블록)

- 인스턴스가 생성된 후 자동으로 실행하는 블록

- 한 클래스 안에 여러 개의 인스턴스 블록을 넣을 수 있다.

- 용도 : 

  인스턴스 변수를 초기화시키는 코드를 둔다.

  어떤 생성자가 호출되든 그 전에 공통으로 초기화시키고 싶은 작업이 있다면

  인스턴스 블록에서 처리하면 된다.



instance block 예제


static class Student {

    static String name = "홍길동"; // 변수 선언에 값을 초기화시키는 문장을 포함할 수 있다.
   
    int age = 20;
    static {
      System.out.println("static {...}");
      name = "임꺽정";
    }
    { // 인스턴스 블록
      // 인스턴스 블록은 인스턴스 주소를 보관한 this라는 변수가 내장되어 있다.
    
      System.out.println(age);
      System.out.println("{인스턴스 블록 실행...1}");
      this.age = 30;
    }
    {
      System.out.println("{인스턴스 블록 실행...2}");
    }

  }


- 실행 순서 :

  1) 인스턴스를 생성한다.

  2) 생성자가 호출되기 전에 인스턴스 블록이 선언된 순서대로 실행된다.



 instance block (인스턴스 블록)과 변수의 호출 코드 

public static void main(String[] args) {

    new Student();
    System.out.println("---------------------------");
    new Student();

  }

-실행 결과 :


static {...}

20

{인스턴스 블록 실행...1}

{인스턴스 블록 실행...2}

-------------------------

20

{인스턴스 블록 실행...1}

{인스턴스 블록 실행...2}






3. 생성자 (constructor)

- 인스턴스를 생성한 후 자동으로 호출되는 특별한 메서드

- 인스턴스 변수와의 차이점 :

  파라미터를 받아서 인스턴스 변수를 특정 값으로 초기화 시킬 수 있다.

- 여러 개의 생성자를 가질 수 있다. 다만, 그 중에서 한 개만 호출된다.

  호출되는 생성자를  

- (1) 문법 :

  클래스명(파라미터선언) {...}

   => 리턴타입 x

  (2) 문법

  new 클래스명(아규먼트, ...)


 * 주의!

   클래스를 작성할 때 생성자를 만들지 않으면,

   컴파일러가 자동으로 기본 생성자를 만든다.

   => 이 말인 즉슨, 모든 클래스는 생성자를 한 개 이상 갖게 된다는 의미이다.


   new 명령으로 인스턴스를 생성할 때 반드시 어떤 생성자를 호출할 것인지 지정해

   야 한다.



constructor 생성자 예제 1


static class Student {

    static String name = "홍길동"; // 변수 선언에 값을 초기화시키는 문장을 포함할 수 있다.
   
    int age = 20;
    static {
      System.out.println("static {...}");
    }
    { // 인스턴스 블록
      System.out.println("{인스턴스 블록 실행...1}");
    }
   
    // 이렇게 파라미터가 없는 생성자를 기본 생성자(default constructor)라고 한다.
    Student() {
      System.out.println("Student()... 호출");
    }

  }


- 실행 순서 :

  인스턴스 생성 --> 인스턴스 블록 싱행 --> 생성자 호출




생성자 호출 코드


public static void main(String[] args) {

    new Student();
    System.out.println("---------------------------");
    new Student();

  }

- 실행 결과
static {...}
{인스턴스 블록 실행...1}
Student()... 호출
---------------------------
{인스턴스 블록 실행...1}
Student()... 호출
















블로그 이미지

필로그래머

,
[Java] 클래스 변수의 개념과 예제

클래스 변수

- 클래스 내에서 선언된 변수
- 개별적이고 독립적으로 값이 생성/저장되는 인스턴스 변수와 달리, 모든 영역에서
  값을 공유하는 변수
- 인스턴스마다 값을 개별적으로 관리할 필요가 없고, 공용하고 싶을 때 사용한다.

1) 클래스 변수의 예제


public class Test01_1 {

   static class Student {
    static String name;
    static int age;
    static boolean working;
  }
 


위 예제에서 아래 부분이 클래스 변수를 생성하는 명령어이다.

 

static String name;

static int age;
static boolean working;


문법


- 변수 선언 앞에 static을 붙인다.

- 클래스를 사용하는 시점에 생성된다.

 

* 클래스를 사용하는 시점이란? 

 1) new 명령으로 사용하여 인스턴스를 생성할 때

 2) 클래스 변수를 사용하려 할 때

 3) 클래스 메서드를 사용하려 할 때


(위에서 언급한 세가지 경우에 해당 클래스의 파일을 찾아 메모리에 로딩한다. 

즉 ***.class 파일을 메모리의 "Method Area" 영역으로 읽어들인다.

우리는 이것을 "클래스를 로딩한다"라고 표현한다.)




2) 클래스 변수 생성 및 호출 코드



public static void main(String[] args) {
    Student s = new Student(); // 클래스 변수 생성
    s.name = "홍길동"; // 클래스 변수에 "홍길동" 값 저장
    System.out.println(s.name);  // 출력

}







블로그 이미지

필로그래머

,

[Java] 인스턴스 변수의 개념과 예제


인스턴스 변수


- new 명령을 통해 생성하는 변수이다.

- 인스턴스는 값을 개별적으로 구분해서 관리할 필요가 있을 때 사용한다.

- 클래스가 로딩될 때 생성되지 않는다.

- 인스턴스 주소를 통해 접근 가능하다.

- 인스턴스 주소를 잃어버리면 해당 변수는 사용할 수 없게 된다.

- 변수 선언에 static을 붙이지 않는다.


인스턴스 변수는 기본 값으로 0을 갖는다.



1) class Student 코드


static class Student {

    // 인스턴스 변수는 기본 값으로 0을 갖는다.
    // 주소 변수 : null
    // 정수 변수(byte, short, int, long, char) : 0
    // 부동소수점 변수(float, double) : 0.0
    // 논리 변수(boolean) : false
    //  => 사실 null이나 false, 0.0 모두 메모리가 0으로 셋팅된다는 것을 의미한다.
     String name;
     int age;
     boolean working;

  }


* 주의! 

많은 사람들이 오해하는 게 있다. 위 클래스에서 선언된 String name 'name'은 

인스턴스 변수가 아니다. 그 어떤 변수도 아니다. name 이라는 이름을 가진 String

타입의 메모리를 만들라는 '명령어'일 뿐이다. 인스턴스 변수 인스턴스가 생성된

후, '메모리에 실제로 저장되는 변수' 값이다.




2) 인스턴스 호출 및 출력 코드


public static void main(String[] args) {

    // 인스턴스 변수 사용법:
    // 인스턴스의주소.변수명
    Student s1 = new Student(); // new Student() -> 인스턴스 생성!
    Student s2 = new Student();
   
    System.out.println(s1.name); 
// 항상 로컬 변수는 값을 설정한 다음에 사용해야 한다.
    System.out.println(s1.age);
    System.out.println(s1.working);
    System.out.println("-------------------------");
   
    s1.name = "홍길동";
    s1.age = 20;
    s1.working = true;
    System.out.println(s1.name);
    System.out.println(s1.age);

    System.out.println(s1.working);


* s2 값은 s1 값과 전혀 관계가 없다.



블로그 이미지

필로그래머

,

[Java] 클래스 로딩과 메모리 영역 (stack, heap, method area)


클래스 로딩


1. 클래스를 사용하는 시점에 해당 클래스의 바이트코드가 들어 있는 파일을 찾는다.

2. 찾은 파일은 메모리에 로딩된다.

   클래스의 바이트 코드는 "Method Area" 영역에 로딩된다. 


JVM이 관리하는 주요 메모리 영역


 1) Stack (스택)

메서드가 호출될 때마다 그 메서드의 로컬 변수를 준비하는 메모리 영역

메서드 호출이 끝나면 그 메서드를 위해 준비했던 모든 변수가 스택에서 제거된다.


 2) Heap (힙)

new 명령을 통해 생성된 인스턴스 변수가 놓이는 메모리 영역

가비지 컬렉터에 의해 관린된다.

가비지 컬렉터가 메모리를 해제하기 전까진 계속 유지된다.


 3) Method Area (메서드 영역)

클래스의 코드가 로딩되는 메모리 영역

메서드 코드가 이 영역에 존재한다. 


* JVM이 종료되면 JVM이 사용한 모든 메모리는 OS에 자동으로 반납된다.

  - OS의 메모리 관리 정책에 따라 프로세스가 종료되면 그 프로세스가 사용한 모든 

    메모리를 강제로 해제시킨다.

블로그 이미지

필로그래머

,

[Java] 생성자(constructor)


생성자(constructor)




class Student3 {
  String name;
  int[] scores = new int[3];
  int total;
  float aver;
 
 public Student3(String name, int kor, int eng, int math) { // 생성자
    this.name = name;
    this.scores[0] = kor;
    this.scores[1] = eng;
    this.scores[2] = math;
  }
  public void compute() {
    this.total = this.scores[0] + this.scores[1] + this.scores[2];
    this.aver = this.total / 3f;
  }
 
  public void print() {
    System.out.printf("%s, %d, %d, %d, %d, %f \n",
        this.name, this.scores[0], this.scores[1], this.scores[2],            this.total, this.aver);
  } 

}


위 예제를 보면 class Student3 안에 public Student3(..){..}라는 메서드가 있는 것을 

알 수 있다. 이 메서드는 new Student3(..) 명령어를 써주었을 때 인스턴스가 생성됨과

동시에 호출이 된다. 이런 메서드를 "생성자"라고 한다. 이 메서드 안에 있는 this는 

생성된 인스턴스의 주소 값을 가리키며 name과 scores[] 값을 초기화시키고 있는데,

 

1) 생성자(메서드)의 이름은 반드시 클래스 이름과 같아야 하고

2) 보통 인스턴스 변수의 값을 초기화시키는 코드를 써주는 게 일반적이다.

3) 리턴 타입을 선언하지 않는다.


* main()에서 class Student3 안에 compute() 메서드를 호출시키는 코드


Student3 s = new Student("홍길동", 100, 100, 100); 

// 생성자(메서드) 호출, 값 초기화


s.compute(); 

// 인스턴스의 주소 값이 저장된 s에서 compute()라는 메서드를 찾아 실행한다.


블로그 이미지

필로그래머

,
[Java] 클래스(class) - 인스턴스 메소드 (instance method), this 문법
 
클래스 - 인스턴스 메소드


예제)


class Student {
  String name;
  int[] scores = new int[3];
  int total;
  float aver;
  // 이렇게 클래스 블록 안에 묶여서 호출할 때마다 클래스 이름으로
  // 호출해야 하는 메서드를 "클래스 메서드(=스태틱 메서드)"라 부른다.
  public void init(Student s, String name, int kor, int eng, int math) {
    s.name = name;
    s.scores[0] = kor;
    s.scores[1] = eng;
    s.scores[2] = math;
  }
  public void compute(Student s) {
    s.total = s.scores[0] + s.scores[1] + s.scores[2];
    s.aver = s.total / 3f;
  }
 
  public void print(Student s) {
    System.out.printf("%s, %d, %d, %d, %d, %f \n",
        s.name, s.scores[0], s.scores[1], s.scores[2], s.total, s.aver);
  }

}



=> class Student 안에 static이 붙지 않은 init(), compute(), print()과 같은 메서드를 "인스턴스 메서드"라 부른다.

ex) 위 클래스에서 init 메서드를 호출하는 코드
Student s1 = new Student();
Student.init(s1, "홍길동", 100, 100, 100);

=> init(), compute(), print() 함수는 모두 Student 인스턴스(s)를 파라미터로 넘겨서 그 인스턴스에 값을 저장해 사용하고 있다. 그러나 이런 Student 인스턴스를 쓰지 않고 사용할 수 있는 문법이 있는데, 그것이 바로 this 문법이다.


=> 메서드 앞에 놓은 인스턴스 주소를 메서드 안에서 어떻게 사용할까?
- 인스턴스 주소가 그 메서드의 내장 변수 this에 자동 저장된다.




위 예제를 다음과 같이 바꿀 수 있다!





클래스 - this의 사용


예제)


class Student {
  String name;
  int[] scores = new int[3];
  int total;
  float aver;
 
  // => static이 붙지 않은 메서드를 "인스턴스 메서드"라 부른다.
  // => 인스턴스 메서드는 호출할 때 반드시 인스턴스 주소를 줘야 한다.
  //    예) 인스턴스주소.메서드명();
  // => 이렇게 메서드를 호출할 때 앞에 놓인 인스턴스의 주소는
  //    그 메서드의 내장 변수 this에 자동 보관된다.
  public void init(String name, int kor, int eng, int math) {
    this.name = name;
    this.scores[0] = kor;
    this.scores[1] = eng;
    this.scores[2] = math;
  }
  public void compute() {
    this.total = this.scores[0] + this.scores[1] + this.scores[2];
    this.aver = this.total / 3f;
  }
 
  public void print(Student2 s) {
    System.out.printf("%s, %d, %d, %d, %d, %f \n",
        this.name, this.scores[0], this.scores[1], this.scores[2],            this.total, this.aver);
  }
}



=> 이렇게 클래스에 정의한 인스턴스 메소드를 호출할 때는  main () 에서
Student s1 = new Student();

s1.init("홍길동", 100, 100, 100)



무엇이 변화했는가?



Student s1 = new Student();
Student.init(s1, "홍길동", 100, 100, 100);


위 코드가


Student s1 = new Student();

s1.init("홍길동", 100, 100, 100)


이렇게 직관적이고 간결하게 바뀌었다. 

블로그 이미지

필로그래머

,