웹 브라우저에서 웹 서버로 데이터를 던지는 방법

스프링 부트에서 값을 보내는 방법

웹 브라우저에서 메서드 실행해달라고 요청할 때 뒤에 ?를 적고

서버에 전달하는 값이다.. 파라미터

파라미터명, 파라미터값

// 변수 : 값을 저장하는 메모리를 준비시키는 명령어
package com.eomcs.study.lang.variable;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController("lang.variable.exam1") // 클래스 이름이 같은 경우 충돌 방지
@RequestMapping("/lang/variable/exam1")
public class Exam1 {

  @GetMapping("/test1")
  public String test1() {
    return "클라이언트에서 받은 값 = ";
    // return "클라이언트에서 받은 값 = " + name + "," + tel + "," + gender;
  }

}

값을 받고 싶으면 값을 받을 메모리(변수)를 선언하면 됨

변수

02-자바기초2 / 2 페이지

com.eomcs.lang.ex04 변수 관련된 예제들

변수 : 값을 저장하는 메모리

변수 선언 : 메모리를 준비시키는 명령문

작성법
메모리 종류를 적는다. 메모리 이름을 적는다.

[메모리 종류] [메모리 이름];
[data type] [variable];
String str;

data type : 어떤 종류의 데이터를 담을 메모리인지

문자열 저장할 메모리 준비해!

변수 선언 (variable declaration)
메모리를 준비시키는 명령문

중간에서 스프링 부트가 이 메서드를 실행시킬 때 넘겨준다

  @GetMapping("/test1")
  public String test1(String v1) {
    return "클라이언트에서 받은 값 = " + v1;
    //    return "클라이언트에서 받은 값 = " + name + "," + tel + "," + gender;
  }

null로 나옴

값을 넘겨줄 때 이름과 변수의 이름이 일치하게 선언해야 된다.

  @GetMapping("/test1")
  public String test1(String name) {
    return "클라이언트에서 받은 값 = " + name;
    //    return "클라이언트에서 받은 값 = " + name + "," + tel + "," + gender;
  }

변수 이름은 웹 브라우저에서 보내는 이름이랑 같게 선언한다.
스프링 부트가 중간에서 그 값을 뜯어내서 이 메서드를 실행할 때 넘겨준다.
중간에 누가 개입한다? 스프링 부트!

Web Browser Spring Boot에게 보낸다.
Exam1 안에 있는 메서드를 호출하는 게 스프링 부트
웹 브라우저가 호출하는 게 아니라 스프링 부트가 요청을 받아서 대신 호출하는 거임
메소드가 작업을 하고 결과를 리턴한다. 그 리턴된 결과를 스프링 부트는 HTTP 라는 프로토콜

웹 브라우저가 스프링 부트에 보냄
스프링 부트에 접속해서 요청을 보낸다

hyper : 高 고수준의

Hyper-Text = HTML 고수준의 텍스트

HTML을 웹 브라우저와 웹 서버 사이에 주고 받다 = Transfer

웹 브라우저에서 서버에 보낼 때 규칙
서버에서 응답할 때 규칙
주고 받는 규칙 = Protocol

URL (Uniform Resource Locator)

스프링 부트 안에 웹 서버가 있음
스프링 부트가 메서드에서 리턴된 결과값을 HTTP로 응답한다.

메서드를 호출하는 건 스프링 부트
웹 브라우저가 다이렉트로 호출하는 게 아님

웹 브라우저에서 쿼리 스트링으로 데이터를 보내면 그 데이터를 스프링 부트가 받는다.
스프링 부트가 받아서 그 데이터를 쪼갠다. 쪼갠 후에 메서드를 호출할 때 넘겨준다. 메모리가 있으면 넘겨주고 메모리가 없으면 안 넘겨준다. 메모리가 있다 하더라도 클라이언트가 보낸 값의 이름과 변수명이 일치할 때만 넘겨준다.

그 데이터를 스프링 부트가 받아서 그 데이터를 쪼갠다
스프링 부트가 메모리가 있으면 넘겨주고 메모리가 없으면 안 넘겨줌
클라이언트가 보낸 값의 이름과 변수명이 일치할 때만 넘겨줌

웹 브라우저에서 값을 넘기는 방법
스프링 부트에서 변수 선언을 통해서 값을 받는 방법
2가지를 배웠다

변수의 데이터 타입

① 정수
메모리 크기에 따라서 4가지로 구분된다.
1 byte → byte a; (-128 ~ 127)
2 byte → short b; (-32768 ~ 32767)
4 byte → int c; (약 -21억 ~ 약 21억)
8 byte → long d; (약 -922경 ~ 약 922경)

② 부동소수점
4 byte → float x; (유효자릿수 7자리 ← 소수점 제외)
8 byte → double y; (유효자릿수 15자리 ← 소수점 제외)

③ 논리
기본은 4 byte인데 배열일 때는 내부적으로 1 byte 사용
(4 byte) → boolean v;
자바의 int 타입을 그대로 사용한다.
단, boolean의 배열(연속된 메모리)를 만들 때는 4 byte를 연속적으로 만드는 건 낭비니까 byte 타입(1 byte)을 쓴다.

④ 문자
2 byte → char ch; (UTF-16을 저장해야 되니까)

⟹ 총 8개 (java primitive data type)

java primitive data type
자바 원시 데이터 타입
자바 기본 데이터 타입
원시 타입
기본 타입

⑤ 레퍼런스 (메모리 주소를 저장)
Object obj;
원시 타입을 제외한 모든 데이터 타입은 레퍼런스다!
String도 레퍼런스

스택(Stack)
힙(Heap)
메소드 영역(Method Area)
객체
인스턴스
클래스(메모리 설계도)

262^6 = 64
64 / 2 = 32
양수 32개, 음수 32개
-32 ~ 31

1 byte = 8 bit
282^8 = 256
256 / 2 = 128
-128 ~ 127

소수점을 뺐을 때 최대 7자리 정도의 수를 저장하고 싶을 때 ⟹ float
float : 유효자릿수 7자리

소수점을 뺐을 때 최대 15자리 정도의 수를 저장하고 싶을 때 ⟹ double
double : 유효자릿수 15자리까지는 99.9% 저장 가능

유효자릿수 30자리를 저장하고 싶은데요?
그러면 primitive 타입으로 저장하면 안 됨. 다른 타입을 써야 함. 별도로 설계한 메모리를 사용해야 함.

4비트 = 비트가 4개 = 2³
하나 큰 게 2⁴
⁴ = 비트 개수
최대 4개의 비트로 몇 개의 숫자를 저장할 수 있습니까? 2⁴개 = 16개
16개의 숫자를 저장할 수 있다.
16개를 반으로 나눈다.
8개씩
음수 8개, 양수 8개
음수는 -1 ~ -8
양수는 0 ~ 7

최대 6개의 비트로 몇 개의 숫자를 저장할 수 있는가?
262^6 = 64개
반으로 나눈다
32개씩
음수 32개, 양수 32개
음수 -1 ~ -32
양수 0 ~ 31

1 byte 메모리 안에 저장할 수 있는 정수는 - 얼마부터 + 얼마입니까?
282^8 = 256개
반으로 나눈다
128개씩
음수 -1 ~ -128
양수 0 ~ 127

  @GetMapping("/test2")
  public String test2(byte b) {
    return "클라이언트에서 받은 값 = " + b + ",";
  }

http://localhost:8080/lang/variable/exam1/test2?b=100&s=-32768&i=2100000000&l=9220000000000000000

변수 byte s에 200을 받아보자

  @GetMapping("/test2")
  public String test2(byte b, byte s) {
    return "클라이언트에서 받은 값 = " + b + ",";
  }

http://localhost:8080/lang/variable/exam1/test2?b=100&s=-32768&i=2100000000&l=9220000000000000000

Value out of range

1 byte 안에 못 담겠다고 에러남.

넘치는 값을 넣었다고 에러남. byte 타입은 -128부터 127까지만 가능.

메모리 크기에 따라서 저장할 수 있는 값의 범위가 달라진다.

short 타입으로 변경해준다.

short s

  @GetMapping("/test2")
  public String test2(byte b, short s) {
    return "클라이언트에서 받은 값 = " + b + ",";
  }

http://localhost:8080/lang/variable/exam1/test2?b=100&s=-32768&i=2100000000&l=9220000000000000000

에러 안 남

  @GetMapping("/test2")
  public String test2(byte b, short s) {
    return "클라이언트에서 받은 값 = " + b + "," + s + ",";
  }

http://localhost:8080/lang/variable/exam1/test2?b=100&s=-32768&i=2100000000&l=9220000000000000000

long l → 8 byte 메모리를 준비시켜라!

  @GetMapping("/test2")
  public String test2(byte b, short s, int i, long l) {
    return "클라이언트에서 받은 값 = " + b + "," + s + "," + i + "," + l;
  }

부동소수점 변수 선언과 값의 범위

float f

  // 부동소수점 변수 선언과 값의 범위
  // 부동소수점 값을 저장하는 메모리를 준비시키는 명령문
  // 메모리 크기에 따른 값의 유효범위
  @GetMapping("/test3")
  public String test3(float f) {
    return "클라이언트에서 받은 값 = " + f;
  }

http://localhost:8080/lang/variable/exam1/test3?f=987.6543

http://localhost:8080/lang/variable/exam1/test3?f=987.654321

7자리 넘게 써도 에러는 안 나지만 잘린다.

정수 변수인 경우에는 범위를 넘어가면 에러가 뜨는데,
float인 경우에는 값의 범위가 넘어가면 에러는 안 나고 잘릴 뿐이다. 그래서 더 위험하다. 차라리 에러가 뜨면 잘못된 걸 알 수 있는데 에러가 안 뜨니까 정상적으로 동작했다고 착각한다.
정수보다 더 위험함

http://localhost:8080/lang/variable/exam1/test3?f=987654321.234

7자리가 넘어가면 double로 받아야 됨. 2배 더 정밀한 값을 다룰 수 있다고 해서 '배정도'라고 한다. 정밀한 정도가 배로 정밀하다. float을 기준으로 배로 정밀하다.
• 단정도 : float
• 배정도: double 정밀한 정도가 배로 정밀하다

  @GetMapping("/test3")
  public String test3(float f, double d) {
    return "클라이언트에서 받은 값 = " + f + ", " + d;
  }

http://localhost:8080/lang/variable/exam1/test3?f=987654.321234

http://localhost:8080/lang/variable/exam1/test3?f=987654.32123456789

987654.321234567까지가 15자리
그 뒤에는 반올림 처리함
15자리까지 유효한 수

987654.32123456789
987654.3212345679 ← 반올림해버림

-128에서 127 정도의 정수 값을 저장할 거야 → 1 byte 메모리 준비
-21억에서 21억 정도 정수를 다룰 거야 → 4 byte 메모리 준비
조가 넘어갈 거 같은데 → long 변수 준비
소수점을 뺐을 때 7자리까지 → float 준비
15자리까지는 돼야 될 거 같은데 → double 준비

저장하려는 수의 범위가 어느 정도인지에 따라서 메모리를 준비하면 됨

문자 변수 선언

  // 문자 변수 선언
  // 문자에 부여된 번호를 저장할 메모리를 준비시키는 명령문
  @GetMapping("/test4")
  public String test4(char c) {
    return "클라이언트에서 받은 값 = " + c;
  }

http://localhost:8080/lang/variable/exam1/test4?c=가

문자 전송과 URL 인코딩 (퍼센트 인코딩)

Web Browser에 'A'라는 문자를 보내고 싶다.

Web Browser는 Spring Boot에 'A'라는 문자를 그대로 보낸다.

영어는 변환 없이 보낸다.
누구 마음대로? HTTP 프로토콜 명세
URL을 작성할 때 문자 사용 규칙(RFC 3986)에 따라 변환한다.
영어, 숫자, 특수문자를 제외한 나머지 문자는 변환한다.

문자에 부여된 정수값을 "%-" 식으로 문자열로 변환하는 것!
⟹ 7 bit 네트워크 장비를 거쳐갈 때 데이터가 짤리지 않도록 조치하기 위함.
지금은 사실상 필요없는데 옛날부터 그렇게 해서 계속 그렇게 하는 거

문제는 한글

한글 '가'를 보낸다.

'가' → "%EA%B0%80"
문자열을 만들어서 보낸다.
RFC 3986 명세에 따라 "퍼센트 인코딩(URL 인코딩)"으로 변환
퍼센트로 시작해서 퍼센트 인코딩

https://ko.wikipedia.org/wiki/퍼센트_인코딩

퍼센트 인코딩 규약은 RFC 3986에 정의되어 있다. 이 RFC에 따르면 URL에서 중요하게 사용되는 예약(reserved) 문자가 있고, 또한 인코딩이 필요하지 않은 비예약(unreserved) 문자가 존재한다.

https://en.wikipedia.org/wiki/Percent-encoding

예)
! (0x21) → "%21"
문자에 부여된 정수값을 문자열 "%-"로 바꾼다.

# (0x23) → "%23"
문자에 부여된 정수값을 문자열 "%-"로 바꾼다.

+ (0x2B) → "%2B"
문자에 부여된 정수값을 문자열 "%-"로 바꾼다.

? (0x3F) → "%3F"

(0xEAB080) → "%EA%E0%80"
3 byte
각각의 byte를 문자열 "%-"로 바꾼다.
사용자가 헷갈릴까봐 '가'로 보여주는 거

개발자 도구에서 보면 "%EA%E0%80"로 변환되어 있는 걸 확인할 수 있다.

Web Browser가 URL을 작성할 때 문자 사용 규칙(RFC 3986)에 따라 변환한다.
모든 브라우저가 이 규칙을 지킨다.
Web Browser에서 Web Server로 url을 보낼 때 반드시 변환한다.
브라우저가 URL 인코딩 하는 거

http://localhost:8080/lang/variable/exam1/test4?c=%EA%B0%80

스프링 부트에 들어있는 웹 서버에게 그대로 A라는 문자를 보낸다.
영어는 변환 없이 보낸다.
누구 마음대로? HTTP 프로토콜 명세

'가' → Web Browser → encoding → "%EA%B0%80" → Spring Boot

"%EA%B0%80"(문자열) → URL decoding → 0xEAB080(정수, UTF-8) → decoding → 0xAC00(정수, UTF-16)

Exam1에 있는 test4를 호출한다.
호출하기 전에 할 일이 있다.
"%EA%B0%80"라는 문자열을 먼저 숫자로 바꾼다.
"%EA%B0%80" → 0xEAB080 이라는 정수로 바꾼다.
정수로 복원한다. decoding
인코딩 encoding : 규칙에 따라 데이터를 변환하는 거
디코딩 decoding : 원래대로 하는 거
URL decoding 이라고 부른다.
0xEAB080 ← 정수, UTF-8
JVM은 내부적으로 무조건 UTF-16 쓰니까 또 변환한다.
0xEAB080(UTF-8) → 0xAC00(UTF-16)
0xAC00 ← JVM이 문자를 다룰 때 사용하는 UTF-16
0xAC00을 스프링 부트가 넘겨준다.
최종적으로 char c 변수에 AC00(44,032)이 들어있다.
1010 1100 0000 0000
1110xxxx 10xxxxxx 10xxxxxx
11101010 10110000 10000000

영어 외에

퍼센트 인코딩
https://ko.wikipedia.org/wiki/퍼센트_인코딩

퍼센트 인코딩 규약은 RFC 3986에 정의되어 있다. 이 RFC에 따르면 URL에서 중요하게 사용되는 예약(reserved) 문자가 있고, 또한 인코딩이 필요하지 않은 비예약(unreserved) 문자가 존재한다.

https://en.wikipedia.org/wiki/Percent-encoding

퍼센트 인코딩(percent-encoding)은 URL에 문자를 표현하는 문자 인코딩 방법이다. 이 방법에 따르면 알파벳이나 숫자 등 몇몇 문자를 제외한 값은 옥텟 단위로 묶어서, 16진수 값으로 인코딩한다.
퍼센트 인코딩 규약은 RFC 3986에 정의되어 있다.

URL을 작성할 때 문자 사용 규칙에 따라 변환한다. (RFC 3986)
영어, 숫자, 특수문자를 제외한 나머지 문자는 변환한다.
문자에 부여된 정수값을 %- 식으로 문자열로 변환하는 것!
7 bit 네트워크 장비를 거쳐갈 때 데이터가 잘리지 않도록 조치하기 위함

RFC 3986 명세에 따라 퍼센트 인코딩(URL 인코딩)으로 변환

RFC 3986

문자열로 바꿔버림
퍼센트OO
퍼센트 인코딩

가(0xeab080) → "%EA%B0%80"

언제 이런 짓을 벌인다?
URL을 작성할 때 문자 사용 규칙에 따라 변환한다.
모든 브라우저가 이 규칙을 지킨다.

abc가각간 검색

개발자 도구 - Network 탭

Preserve log 체크, Disable cache 체크

  // 문자 변수 선언
  // 문자에 부여된 번호를 저장할 메모리를 준비시키는 명령문
  // http://localhost:8080/lang/variable/exam1/test4?c=가
  @GetMapping("/test4")
  public String test4(char c) {
    return "클라이언트에서 받은 값 = " + c + ", " + c;
  }

문자 전송 및 수신 과정

웹 브라우저 인코딩 스프링 부트

URL encoding

스프링 부트가 "%EA%B0%80"을 보냈지만 문자열을 정수로 변환

'가' → Web Browser → encoding → "%EA%B0%80"(문자열) → Spring Boot → URL decoding → 0xEAB080(정수, UTF-8) → decoding → 0xAC00(정수, UTF-16)

Spring Boot에서 Exam1에 있는 test4를 호출한다.
호출하기 전에 할 일이 있다.
"%EA%B0%80"라는 문자열을 먼저 숫자로 바꾼다.
"%EA%B0%80" → 0xEAB080 이라는 정수로 바꾼다. (URL decoding)
정수로 복원한다.
인코딩 encoding : 규칙에 따라 데이터를 변환하는 거
디코딩 decoding : 원래대로 하는 거
URL decoding 이라고 부른다.
0xEAB080 ← 정수, UTF-8
JVM은 내부적으로 무조건 UTF-16 쓰니까 또 변환한다.
0xEAB080(정수, UTF-8) → 0xAC00(정수, UTF-16) (decoding)
0xAC00 ← JVM이 문자를 다룰 때 사용하는 UTF-16
0xAC00을 스프링 부트가 넘겨준다.
최종적으로 char c라는 변수에 AC00(44032)이 들어 있다.
44032가 들어 있는지 직접 확인해 보자!

char c : 메모리 앞에 붙은 char 때문에 JVM은 44032라는 숫자를 출력하는 게 아니라 44032는 문자에 부여된 번호구나 이 자리에 44032라는 숫자를 출력하면 안 되고 44032가 가리키는 문자를 출력해야 되는구나 해서 문자를 출력함

근데 우리가 원하는 건 정수값이 뭔지 알고 싶은 거
이때는 거꾸로 문자 번호 그냥 정수값이라고 가정하고 출력해
c에 들어있는 거 정수야
(int) c c에 들어 있는 거 정수로 가정하고 문자열로 바꿈

  @GetMapping("/test4")
  public String test4(char c) {
    return "클라이언트에서 받은 값 = " + c + ", " + (int) c;
  }

44032 나옴

나의 오해
나는 아마 웹 브라우저에서 '가'라는 문자를 보내면 c에 '가'라는 문자가 저장돼서 '가'가 출력된 거라고 알고 있었을 거임. 중간에 URL encoding이니 이런 과정은 잘 몰랐을 거임.
Web Browser가 '가'를 서버에 보내기 전에 UTF-8 인코딩을 사용해서 퍼센트 인코딩으로 바꿔서 Spring Boot에게 보내면 Spring Boot가 test4라는 메소드를 호출하는데 메소드에 넘겨주는 숫자는 퍼센트 문자열을 정수값(UTF-8)으로 바꾼 다음에 JVM에서 사용하는 UTF-16으로 바꾼 다음에 그 정수값을 넘겨준다. 최종적으로 char c라는 변수에 UTF-16 값이 저장된 거다.

매번 프로그램을 짤 때마다 이런 고민을 할 필요는 없음
중간에 Spring Boot가 이런 작업들을 해줘서 신경 쓸 필요는 없지만 내부적으로 이런 과정이 일어난다는 건 알아야 됨

JVM은 UTF-8 번호를 안 씀. 중간에 Spring Boot가 test4에게 던져줄 때 EA B0 80이라는 UTF-8 숫자 대신 UTF-16 번호로 바꿔서 던져준다. 그래서 최종적으로 c 라는 변수에 저장된 값은 UTF-16 번호이다.

논리 값 전송 및 수신

  // 논리 변수 선언
  // true/false 논리 값을 저장할 메모리를 준비시키는 명령문
  // 테스트 URL :
  // - http://localhost:8080/lang/variable/exam1/test5?b=true
  // - http://localhost:8080/lang/variable/exam1/test5?b=1
  // - http://localhost:8080/lang/variable/exam1/test5?b=TRUE
  // 주의!
  // - boolean 리터럴은 true/false 이다.
  // - 논리 값으로 1/0, TRUE/FALSE 를 사용할 수 있는 이유는
  //   스프링 부트가 중간에서 true/false 값으로 변환해 주기 때문이다.
  @GetMapping("/test5")
  public String test5(boolean b) {
    return "클라이언트에서 받은 값 = " + b;
  }

TRUE ← 이거 원래 안 되는 건데 스프링 부트가 중간에서 처리해주는 거 같음

1 ← 이것도 원래 안 되는 건데 스프링 부트가 중간에서 처리해주는 거 같음

원래는 무조건 소문자 true, false만 됨

내부적으로 메모리에 저장될 때는 int 메모리가 만들어져서 4 byte int 메모리가 만들어져서 거기에 1 또는 0 (참이면 1, 거짓이면 0) true면 1, false면 0이 저장된다고 했으니까 얘도 숫자를 한 번 출력해 볼 수 있지 않나요? 안 됨!!! boolean 값은 숫자로 형 변환이 안 된다. JVM이 1 또는 0으로 저장한다고 할지라도 숫자 그대로 보여달라고 해도 안 보여줌. 문법적으로 안 됨. 컴파일 에러 뜸. 모든 게 형 변환 되는 게 아님.
기본형(primitive type)에서 boolean을 제외한 나머지 타입들은 서로 형변환이 가능하다.

com.eomcs.lang.ex04.Exam0441.java

JVM 내부에서 true, false를 정수값으로 다룬다고 해서 boolean 변수에 직접 1과 0을 저장할 수 없다.

.../test?b=true

boolean 타입의 변수 b를 선언

test5(boolean b) {...}

12시 3분 ~ 30분까지
110번부터 441번까지 공부

배열

같은 종류의 메모리를 여러 개 만드는 명령문

단축 문법 필요

int[] age = new int[30];

int age[] ← C/C++ 문법

메모리를 만들라는 명령

메모리 준비시키는 명령

0번부터 시작함

index = 메모리 순서를 가리키는 번호

배열 활용

웹 브라우저에서

테스트하는 걸 먼저 만들고 테스트 통과하는 프로그램을 따로 만든다.

Test-Driven Development
명사-형 명사

켄트 벡

@RestController("lang.variable.exam2")
클래스 이름표는 마음대로 적어도 되기는 하는데 찾기 편하게 .으로

@RequestMapping("/lang/variable/exam2")
이 클래스에 이 메소드를 호출해다오
경로

// 변수 : 값을 저장하는 메모리를 준비시키는 명령어
package com.eomcs.study.lang.variable;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController("lang.variable.exam2") // 클래스 이름이 같은 경우 충돌 방지
@RequestMapping("/lang/variable/exam2")
public class Exam2 {

  // 여러 개의 값을 받는 방법
  // 메모리를 준비시키는 명령
  @GetMapping("/test1")
  public String test1(String name1, String name2, String name3, String name4) {
    return "=> " + name1 + ", " + name2 + ", " + name3 + ", " + name4;
  }

}

http://localhost:8080/lang/variable/exam2/test1?name1=홍길동&name2=임꺽정&name3=유관순&name4=안중근&name5=윤봉길&name6=김구&name7=홍범도

// 배열 : 같은 종류의 메모리를 여러 개 만드는 명령문
package com.eomcs.study.lang.variable;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController("lang.variable.exam2") // 클래스 이름이 같은 경우 충돌 방지
@RequestMapping("/lang/variable/exam2")
public class Exam2 {

  // 여러 개의 값을 받는 방법 : 배열 사용 전
  // 메모리를 준비시키는 명령
  @GetMapping("/test1")
  public String test1(String name1, String name2, String name3, String name4, String name5, String name6, String name7) {
    return "=> " + name1 + ", " + name2 + ", " + name3 + ", " + name4 + ", " + name5 + ", " + name6 + ", " + name7;
  }

}

  // 여러 개의 값을 받는 방법 : 배열 사용 후
  @GetMapping("/test2")
  public String test2(String[] name) {
    return "=> " + name[0] + ", " + name[1] + ", " + name[2] + ", " + name[3] + ", " + name[4] + ", " + name[5] + ", " + name[6];
  }

파라미터명 다 name으로 수정하기

http://localhost:8080/lang/variable/exam2/test1?name=홍길동&name=임꺽정&name=유관순&name=안중근&name=윤봉길&name=김구&name=홍범도

배열 활용

배열과 메모리

메모리를 준비시키는 명령문

무슨 타입

정수를 저장할 종류는 정수

메모리 크기

데이터 타입에는 두 가지 의미가 담겨 있다.
데이터 종류, 메모리 크기

int a;
데이터 종류 : 정수
메모리 크기 : 4 byte

정수를 저장할 4 byte 크기의 메모리를 준비

준비할 메모리를 가리킬 때 사용할 이름

배열 : 같은 종류의 메모리를 쉽게 만드는 방법

int a, b, c, d, e, f, g, h, i, j;

int age1, age2, age3, age4, age5, age6, age7, age8, age9, age10;

↑ 만약 같은 값을 여러 개 저장해야 되는 상황이면 위와 같이 유사한 이름으로 변수명을 적을 것이다.

저장할 값의 개수가 많으면 변수 선언이 더 번거로워진다.

배열과 메모리

new 데이터타입[메모리개수]

new int[5] → 4 byte int 메모리를 연속해서 연속된 메모리 준비

배열 메모리의 각 항목을 가리키는 변호 → index

배열 메모리를 사용하려면 이름을 부여해야 한다.

new int[5]
배열 메모리를 준비한 후 그 메모리의 주소(offset address)를 리턴한다.

int 배열의 주소를 받을 변수

int[] age;

int a;
char a;
boolean a;
int[] age;
int[] ← int 배열 주소를 가리킨다.
int[] age; ← 주소를 담는 변수 = "reference"
그 주소를 찾아갈 수 있음
책 뒤에 인덱스가 있음
단어를 포함하고 있는 페이지로 찾아갈 수 있는 페이지 번호가 있음
그 단어가 들어있는 페이지의 번호가 들어 있음
가장 직관적인 게 정수

4GB
JVM이 사용하기로 한 메모리가 20MB
그 메모리에 배열이 만들어짐
이 메모리의 주소는 JVM을 기준으로 한다.
절대기준 37756
상대기준

어떤 기준점에서 떨어져 있는
위치 = address
offset address

JVM

RAM

더 이상 줄 메모리가 없을 때 out of memory 오류 발생

컴파일 오류

reference(=pointer)

이게 배열의 실체

배열과 메모리

레퍼런스와 인스턴스

int age;
4 byte 메모리가 만들어지고 메모리 이름이 age이고 int 값이 들어가는 거

int[] age = new int[5];
age에 int 배열의 메모리 주소가 들어가야 되는 거

배열 메모리에서 첫 번째 byte의 주소가 시작 주소를 의미

200은 정수값이 아니라 시작점에서 몇 번째 떨어져 있는 주소입니다

instance 실제 예 (실례)

배열의 실체 (instance)

실체를 가리키는 주소 (reference)

배열 instance
배열 reference

레퍼런스와 인덱스

int[] age = new int[5];
age[0] = 100;
age[1] = 80;
age[2] = 90;
age[3] = 100;

실행 오류 발생

실행(Runtime)
오류(Exception)

유효한 인덱스가 아니면 ArrayOutofBoundsException 발생

레퍼런스와 인스턴스

int[] arr1 = new int[3];

예를 들어서 이 주소가 200번지라면 arr1 변수에는 200이 담겨있다.

int[] arr2;

arr2 = arr1;
arr1 메모리에 저장된 값을 arr2 메모리에 복사하라!
옮긴 게 아니라 복사한 거

arr1[1] arr2[1] ← 같은 메모리. 같은 배열 항목을 가리킨다.

arr[1] 주소 변수에 들어있는 주소와

550번까지

35 ~ 50분까지 510 ~ 550번까지 공부하기

21_4748_3645

4GB 메모리 줘!

java heap size option

21억개면 21억개가 2 GB
1 byte 메모리를 21억개를 만드는 게 아니라 4 byte 메모리를 21억개 만드는 거
8 GB 넘게 설정해야 됨
9 GB로 해보자.
-Xmx9g

9 GB 만들어서 주는데 시간 걸림

레퍼런스에 주소도 안 담고
주소를 알아야지 찾아가든지 말든지 하지
아직 레퍼런스는 배열의

dangling pointer

해제된
무효한 주소를 사용한 경우가 있
블루스크린
드라이버 하드웨어를 제어하는
무효한 레퍼런스를 사용하면

dangling pointer는 없는데

arr1 = new int[3];

새로운 700번 주소

garbage

Garbage : 주소를 알고 있는 레퍼런스가 없어서 더 이상 사용할 수 없는 메모리

쓰레기 계속 쌓이면 쓸 수 없

자바 프로그램 종료되면 쓰레기는 다 사라짐
JVM이 종료되는 순간 JVM한테 줬던 메모리도 운영체제가 회수해버림
하루 24시간 365일 계속 실행되는 상태면 어떡합니까?
Garbage Collector (GC) => 메모리 부족, CPU 한가
실행하다가 메모리가 부족한 시점에
메모리가 부족 안 하면 한 번도 실행 안 할 수 있음
가비지가 생기는 즉시 회수하는 게 아니라 내비두다가
가비지 컬렉터 정책
메모리도 영역이 있음

배열 인스턴스 자동 초기화

com.eomcs.lang.ex04.Exam0560.java

배열의 초기화
배열은 생성과 동시에 자동으로 자신의 타입에 해당하는 기본값으로 초기화되므로 배열을 사용하기 전에 따로 초기화를 해주지 않아도 되지만 원하는 값을 저장하려면 아래와 같이 각 요소마다 값을 지정해 주어야 한다.

int[] score = new int[5];  // 길이가 5인 int형 배열을 생성한다.
score[0] = 50;             // 각 요소에 직접 값을 저장한다.
score[1] = 60;
score[2] = 70;
score[3] = 80;
score[4] = 90;
int[] score = {50, 60, 70, 80, 90}  // new int[] 생략 가능

로컬 변수와 달리 new 명령으로 확보된 메모리는 종류에 상관없이 기본값으로 자동 초기화된다.
따라서 배열 메모리 또한 생성되는 순간 기본값으로 자동 초기화 된다.

- 정수 배열(byte[], short[], int[], long[]) : 0
- 부동소수점 배열(float[], double[]) : 0.0
- 논리 배열(boolean[]) : false 
- 문자 배열(char[]) : '\u0000'
- 주소 변수(Object[]) : null

new 명령으로 확보된 메모리는 종류에 상관없이 기본값으로 자동 초기화 된다.

값을 저장할

0개의 댓글