。゚(*´□`)゚。

코딩의 즐거움과 도전, 그리고 일상의 소소한 순간들이 어우러진 블로그

[네이버클라우드] 클라우드 기반의 개발자 과정 7기/웹프로그래밍

[NC7기-34일차(6월13일)] - 웹프로그래밍 15일차

quarrrter 2023. 6. 13. 19:50

인스턴스, 스태틱 변수, 클래스 로딩, 어떤 메모리 영역에 생성되는 지 

 

 

 

자바랭 셋팅에 include 있기때문에 그냥 java lang에서 gradle eclipse하면 됨 

app 까지 가서 이클립 import  하기

eclipse 아이콘에 느낌표떠서 안 되면 eclipse clean하고 다시 grade ecalipse 해서 refresh하면 됨 

 

 

s는 레퍼런스지 객체가 아님 . 그냥표현을 ㅇ객체의 필드값을 설정한다고하는 것. s가 가르키는 객체의 name인데 그냥 줄여서 s객체의 name이라고 하는 것
javac 컴파일 오류

ex01

+++ oop 0510 정리하기 

+++ oop 0740정리하기 

void 먼지

 

3교시 변수의 종류 

스태틱필드는 당연히 main과 별도로 생성됨 

메인메서드는 메서드 에리어에 생성되고 

메인메서드에서 사용할 로컬변수들이 jvm stack에 생성됨 

논스태틱 필드만 heap에 생성됨 

인스턴스 변수 = 논스태틱 변수

heap에 생성됨 

메인메서드는 바로 되지만. 다른 클래스 로딩은 new 명령을 만났을 때 로딩됨.

static이 안 붙은  변수들이 heap 생성됨 .

 

메모리 생성 과정 

package com.eomcs.oop.ex03;

public class Exam0120 {
  static class Score {
    String name;
    int kor;
    int eng;
    int math;
    int sum;
    float average;
  }
  public static void main(String[] args) {
    Score s1 = new Score(); 
    Score s2 = new Score();
    Score s3 = new Score();

    s1.name = "홍길동";
    s1.kor = 100;
    s1.eng = 90;
    s1.math = 80;
    s1.sum = s1.kor + s1.eng + s1.math;
    s1.average = s1.sum / 3f;

    s2.name = "임꺽정";
    s2.kor = 100;
    s2.eng = 100;
    s2.math = 100;
    s2.sum = s2.kor + s2.eng + s2.math;
    s2.average = s2.sum / 3f;

    s3.name = "유관순";
    s3.kor = 100;
    s3.eng = 90;
    s3.math = 60;
    s3.sum = s3.kor + s3.eng + s3.math;
    s3.average = s3.sum / 3f;

  }
}

// # 클래스 변수
//
package com.eomcs.oop.ex03;

public class Exam0130 {

  // 지금 당장 A 클래스 앞에 붙은 static은 고민하지 말라!
  // 이 예제의 목표는 스태틱 변수이다.
  static class A {

    // 클래스 변수 = 스태틱 변수
    // - static 이 붙은 변수이기 때문에 "스태틱 변수"라고도 부른다.
    // - 클래스를 로딩하는 순간 자동 생성된다.
    // - 클래스와 함께 "Method Area" 영역에 존재한다.
    // - 클래스 이름으로 접근
    //   클래스 이름으로 접근한다고 해서 "클래스에 소속된 변수", "클래스 변수"라 부른다.
    // - 문법
    //     static 데이터타입 변수명;
    //
    static int v1;
    static boolean v2;
  }

  public static void main(String[] args) {

    // 클래스 변수 사용법
    // 클래스명.스태틱변수명 = 값;
    // 클래스를 사용하는 순간 클래스가 로딩되고, 스태틱 변수는 자동 생성된다.
    A.v1 = 100;
    A.v2 = true;

    System.out.printf("%d, %b\n", A.v1, A.v2);
  }
}

// JVM을 실행하는 동안 한 번 클래스가 로딩되면 같은 클래스에 대해 중복 로딩되지 않는다. 
// 클래스 변수는 클래스가 로딩될 때 자동 생성되기 때문에
// 클래스에 대해 딱 한 번 생성된다.
//

// ## 클래스 로딩
// - 외부 저장장치(예: HDD, USB 메모리, DVD-ROM 등)에 있는 .class 파일을
//   JVM이 관리하는 메모리로 로딩하는 것.
// - 클래스의 코드를 사용하는 시점에 메모리(Method Area 영역)에 로딩된다.

// ## 클래스의 코드를 사용하는 시점?
// - 스태틱 멤버(필드와 메서드)를 사용할 때
//     예) A.v1 = 200; <--- 스태틱 변수 v1 사용
//     예) System.out.println(A.v1); <--- 스태틱 변수 out 사용 
//     예) Integer.parseInt(..); <--- 스태틱 메서드 parseInt() 사용
// - new 명령을 사용하여 인스턴스를 생성할 때
//     예) new A();
// - 한 번 클래스가 로딩되면 JVM을 종료할 때까지 유지한다.
// - 물론 강제로 클래스를 unloading 할 수 있다. 
//   그리고 다시 로딩할 수 있다.

// ## 주의! 클래스를 로딩할 거라고 착각하는 경우
// - 다음과 같이 레퍼런스 변수를 선언할 때는 클래스를 로딩하지 않는다. 
//   로딩하지 않는다! 로딩하지 않는다! 로딩하지 않는다!
// 예) A obj;
// 예) String str;

// ## 클래스 로딩 과정
// $ java com.eomcs.oop.ex03.Exam0130
// 1) 클래스 파일 'Exam0130.class'을 찾는다.
//    - JDK에서 제공하는 기본 라이브러리에서 찾는다.
//    - JVM을 실행할 때 -classpath(또는 -cp) 지정한 CLASSPATH 디렉토리에서 찾는다.
//    - CLASSPATH에 없으면 JVM을 실행하는 현재 폴더에서 찾는다. 
//    - 그래도 없으면 오류를 띄운다.
// 2) 바이트코드 검증(Verify)
//    - 클래스의 바이트코드 유효성을 검사한다.
// 3) Exam0130.class를 "Method Area 영역"에 로딩한다.
//    - 즉 클래스를 외부 저장소(HDD)에서 내부 저장소(RAM)로 로딩한다.
//    - bytecode를 분석하여 코드(생성자, 메서드)와 상수를 따로 분리하여 보관한다.
// 4) 스태틱 필드 및 메서드 테이블 준비(Prepare)
//    - Method Area 에 스태틱 필드 생성한다.
//    - 클래스 내부에서 사용하는 이름(변수명, 메서드명, 클래스명 등) 목록을 준비한다.
// 5) 참조하는 외부 클래스나 인터페이스 검사(Resolve)
//    - 로딩된 클래스가 참조하는 외부 클래스나 인터페이스의 유효성을 검사한다.
// 6) 클래스 초기화시키기
//    - 스태틱 블록(static initializers)을 실행한다.
// 7) main() 메서드를 호출한다.
//    - 클래스를 실행하는 것이라면 main() 메서드를 찾아 실행한다.

// ## Exam0130의 main() 메서드 호출
// 1) main() 메서드에 선언된 로컬 변수를 "JVM 스택 영역"에 생성한다.
//    - args 변수를 스택 영역에 생성한다.
// 2) main()의 코드를 실행한다.
//    - A.v1 = 100;
//      => A.class 를 "Method Area"에 로딩한다.
//      => A의 클래스(스태틱) 필드를 "Method Area"에 생성한다.
//      => `A.v1 = 100` 문장을 실행한다.
//    - A.v2 = true;
//      => A 클래스가 이미 로딩되었기 때문에 다시 로딩하지 않는다.
//      => `A.v2 = true` 문장을 실행한다.
//    - System.out.printf() 를 실행한다.
//

// ## JVM이 관리하는 메모리 영역
// 1) Heap
//    - new 명령으로 생성한 인스턴스 변수가 놓인다.
//    - 즉 인스턴스 필드가 이 영역에 생성된다.
//      - 메서드는 생성하지 않는다!
//    - 가비지 컬렉터는 이 메모리의 가비지들을 관리한다.
// 2) JVM Stack
//    - 각 스레드가 개인적으로 관리하는 메모리 영역이다.
//    - 스레드에서 메서드를 호출할 때 메서드의 로컬 변수를 이 영역에 만든다.
//    - 메서드가 호출될 때 그 메서드가 사용하는 로컬 변수를 프레임에 담아 만든다.
//    - 메서드 호출이 끝나면 그 메서드가 소유한 프레임이 삭제된다.
// 3) Method Area
//    - JVM이 실행하는 바이트코드(.class 파일)를 두는 메모리 영역이다.
//      - 바이트코드를 그대로 메모리에 두는 것이 아니라, 멤버의 종류에 따라 적절하게 분류한다. 
//    - 즉 클래스 코드가 이 영역에 놓이는 것이다.
//    - JVM은 코드를 실행할 때 이 영역에 놓은 명령어를 실행하는 것이다.
//    - 개발자가 작성한 클래스, 메서드 등 이런 코드들이 이 영역에 놓이는 것이다.
//    - 스태틱 필드를 이 영역에 생성한다.
//    - 주의! 
//      Heap에는 개발자가 작성한 명령어가 없다.
//

클래스를 사용하는 순간 or new명령어로 클래스로딩되고 스태틱 변수는 자동 생성됨. (그 밑에 딸려서)

 

 

오후 수업 0140

Method Area는 Heap 영역의 일부임. 근데 이해하기 좋게 분리시켜서 그림그리고 이해.

가비지컬렉터는 new로 만들어진 heap영역만 다룸. 

$java ***.java 하면 ,,

-cp 따라 자바파일을 찾음 

Method Area에 exam0140 class를 메모리 로딩함. 

클래스에 스태틱필드가 있는지 확인 하고 있으면 같이 로딩함. 

exam0140 안에는 main 메서드가 들어있음. (main이 무조건 있어야함)

main을 실행해야하는데 실행 전에 main()메서드 사용할 로컬 변수를 준비하기 위해 jvm stack에 main 프레임 생성

프레임안에 로컬변수가 생성됨. (실행 전에 로컬변수가 미리 다 준비됨. 컴파일할때 로컬변수들 따로 준비시킴.)

a클래스의 스태틱변수(필드)인 v1에 (클래스가 가리키는 건 무조건 스태틱필드임)에 100을 넣어라 . 를 하려면 

method area에 a클래스 로딩되고 스태틱필드 v1이 같이 생성. 거기다가 100넣기 

a클래스의 인스턴스를 만들고 그 주소를 p레퍼런스에 저장한다. 

a클래스의 인스턴스란 a클래스의 non static 변수를 말하는 거임. ( non static 변수 +알파(인스턴스 정보))

어떤 클래스에 인스턴스 변수가 없다하더라도 알파(인스턴스 정보가 담겨있는)메모리가 hepa에 만들어짐

생성된 인스턴스의 주소를 p에 저장한다. 

p레퍼런스가 가리키는 v2인스턴수 변수에 200을 넣어라 

a 설계도에 따라 heap에 인스턴스 필드를 준비하라. 생성된 인스턴스 주소를 p2 레퍼런스에 담는다. 

p2가 가리키는 인스턴스 변수 v2에 300을 집어넣어라 

 

// # 클래스 변수와 인스턴스 변수 생성 시점과 메모리 영역
//
package com.eomcs.oop.ex03;

public class Exam0140 {

  static class A {
    static int v1;
    int v2;
  }

  public static void main(String[] args) {

    // 클래스 변수는 클래스가 로딩되는 순간 바로 사용할 수 있다.
    // 클래스가 로딩되는 경우:
    // - 클래스 변수나 클래스 메서드를 사용할 때
    // - 인스턴스를 생성할 때
    // - 단 중복 로딩되지 않는다.
    //
    A.v1 = 100;

    // v2 는 인스턴스 변수이기 때문에 사용하기 전에 new 명령으로 먼저 생성해야 한다.
    // A.v2 = 200; // 컴파일 오류!

    A p = new A();
    // 이제 v2 변수는 Heap에 생성되었다.
    // A클래스의 인스턴스를 만들 때
    // static 이 안붙은 변수(non-static 변수 = 인스턴스 변수)가 그 대상이다.
    //
    // v2 인스턴스 변수는 인스턴스 주소를 통해 사용해야 한다.
    // 클래스이름으로 사용할 수 없다.
    //    A.v2 = 200; // 컴파일 오류!

    p.v2 = 200; // OK!

    // 인스턴스 변수는 인스턴스를 만들 때 마다 생성된다.
    A p2 = new A(); // 새 v2 변수가 생성된다.
    p2.v2 = 300;

    System.out.printf("A.v1=%d, p.v2=%d, p2.v2=%d\n", A.v1, p.v2, p2.v2);
  }
}

 

 

 

 

 

 

0210

 

// 인스턴스 메서드와 클래스 메서드
//
package com.eomcs.oop.ex03;

public class Exam0210 {
  static class A {
    //1) 클래스 메서드 = static 메서드
    //   => static 붙은 메서드이다.
    //   => 클래스 이름으로 호출할 수 있다.
    static void m1() {
      System.out.println("m1()");
    }

    //2) 인스턴스 메서드 = non-static 메서드
    //   => static 이 붙지 않은 메서드이다.
    //   => 인스턴스 주소가 있어야만 호출할 수 있다.
    void m2() {
      System.out.println("m2()");
    }
  }

  public static void main(String[] args) {

    // 클래스 메서드 호출
    // 문법) 클래스명.메서드명();
    A.m1(); // OK!

    // => 인스턴스 메서드는 클래스 이름으로 호출할 수 없다.
    //    A.m2(); // 컴파일 오류!

    A obj1 = new A();

    obj1.m1(); // OK! 그런데, 이렇게 하지 말라!
    // 물론 "클래스 메서드"를 인스턴스 주소를 사용하여 호출할 수 있지만,
    // 다른 개발자가 그냥 "인스턴스 메서드"인 줄 착각할 수 있기 때문에
    // 이렇게 호출하지 말기를 권고한다!
    obj1.m2(); // OK! 인스턴스 메서드는 반드시 인스턴스 주소를 사용하여 호출해야 한다.

    A obj2 = null;
    obj2.m2(); // 컴파일은 OK! 실행은 오류!
    // 왜? obj2 변수에 들어 있는 인스턴스 주소가 무효하기 때문이다.
  }
}

// 결론!
// 클래스 메서드(=스태틱 메서드)
//   => 인스턴스 변수를 사용하지 않을 경우 클래스 메서드로 선언하라!
// 인스턴스 메서드
//   => 인스턴스 변수를 사용할 경우 인스턴스 메서드로 선언하라!
//
// 실무
// => 일단 인스턴스 메서드로 무조건 만들라!
// => 인스턴스 변수를 완전히 사용하지 않음을 확신하면 
//    그 때 클래스 메서드로 전환하라!
//

 

 

 

 

 

컨트롤 쉬프트 o  / 컨트롤 스페이스: 이클립스 자동 import 

 

 

시리얼라이즈  바이트코드로 바꾸는거

디시리얼라이즈 바이트코드에서 다시 원상태로 바꾸는거 

 

System.out.printf("%tY-%tm-%td\n", date, date, date) //(%tY-%t1$m-%t1$d) 하고 date는 한 번만 써도 됨