본문 바로가기
[Naver Cloud Camp 7] 교육 정리

네이버 클라우드 캠프 25일차 230530

by 우기37 2023. 5. 30.

#1 교육정리

1) 배열

2) 콘솔로 출력하기

3) 키보드 입력받기

4) 반복문

5) HDD Track Sector

 

 

#2 배열

배열이란)

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

문법 : 메모리종류[] 메모리이름 = new 메모리종류[개수] & 데이터타입[] 변수명 = new 데이터타입[개수]

 

배열의 개수는 int 타입의 최대값과 같습니다. 즉, 2147483647개

 

배열의 크기는 int 타입의 최대값에서 2를 뺀 값입니다.

배열의 최대 크기 = Integral.MAX_VALUE - 2

 

오류 : 

    int[] arr3 = new int[2147483647]; // 실행 오류 => VM의 배열 크기 제한을 초과
    // Exception in thread "main" java.lang.OutOfMemoryError: Requested array size
    // exceeds VM limit

    int[] arr3 = new int[2147483645]; // 이론상 OK! 실제로는 배열의 크기가 너무 커서 제약
    int[] arr3 = new int[Integer.MAX_VALUE - 2]; // 이론상 OK! 실제로는 배열의 크기가 너무 커서 제약

    // 실행 오류 발생!
    // => Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    // => JVM이 OS로부터 사용 허가를 받은 메모리 크기를 벗어났기 때문에 발생한 것이다.

    // 해결책?
    // => JVM을 실행할 때 최대 힙(heap) 메모리의 크기를 늘리면 된다.
    // => JVM 실행 옵션에 다음을 추가하라!
    // -Xmx메모리크기
    // 예) $ java -Xmx20000m ...

 

 

배열 메모리에 접근 방법)

문법 : 배열변수[인덱스] = 값;

ex) arr1[0] = 100;

배열의 인덱스는 0부터 시작합니다. 인덱스의 범위는 0 ~ (배열개수 - 1) 입니다.

 

 

 

변수에 들어 있는 값의 합계 구하기)

public class Exam0521 {
  public static void main(String[] args) {

   // int a1, a2, a3, a4, a5;
   // a1 = 100;
   // a2 = 90;
   // a3 = 80;
   // a4 = 70;
   // a5 = 60;

    // 변수에 들어 있는 값의 합계를 구해 보자!
   // int sum1 = a1 + a2 + a3 + a4 + a5; => 배열 하지 않고 값을 구할 때

    int[] arr1;
    arr1 = new int[5];
    arr1[0] = 100;
    arr1[1] = 90;
    arr1[2] = 80;
    arr1[3] = 70;
    arr1[4] = 60;

    // 배열 변수에 들어 있는 값의 합계를 구해 보자!
    int sum2 = 0;

    //1.
    for (int i = 0; i < arr1.length; i++) {
    sum2 = sum2 + arr1[i];
    }

    //2.
    for (int item : arr1) {
      sum2 = sum2 + item;
    }

    System.out.println(sum2);

  }
}


400

 

 

배열 레퍼런스와 배열 인스턴스1)

int[] arr1 = new int[5];

배열 선언문 분석 : 

    arr1
      - 배열 메모리의 주소를 담는 변수이다.
      - 이렇게 메모리의 주소를 보관하는 변수를 '레퍼런스'라 부른다.
    
    new int[5]
      - new 명령은 사용할 메모리를 확보하는 명령이다.
      - 즉 연속된 5 개의 int 타입 메모리를 준비하라는 명령이다.
      - 사용할 메모리를 확보한 후 그 메모리의 찾아 갈 수 있도록 시작 주소를 리턴한다.
      - 이렇게 값을 저장하기 위해 확보된 메모리를 "인스턴스"라 부른다.
    
    new 명령은 메모리를 확보하는 명령이다.
    - 리턴 값은 확보된 메모리의 시작 주소이다.

 

레퍼런스란 : 값이 아닌 메모리의 주소를 담는 변수입니다.

인스턴스란 : 값을 저장하는 메모리 입니다.

 

 

배열 레퍼런스와 배열 인스턴스2)

public class Exam0540 {
  public static void main(String[] args) {

    // 배열 레퍼런스만 따로 선언할 수 있다.
    int[] arr1;

    // 주의!
    // 아직 레퍼런스는 배열의 메모리를 알지 못하기 때문에 사용할 수 없다.
    //    arr1[0] = 100; // 컴파일 오류!

    // 레퍼런스에 그 레퍼런스 타입의 배열 주소를 넘겨야 한다.
    //    arr1 = new float[5]; // 컴파일 오류!

    // 배열 인스턴스를 생성하고 그 주소를 레퍼런스에 저장한다.
    arr1 = new int[5];

    // 이제 레퍼런스는 배열 메모리를 알기 때문에 레퍼런스를 통해 배열 인스턴스에 값을 담을 수 있다.
    arr1[0] = 100;

    // 배열 인스턴스에 저장된 값을 출력해보자!
    System.out.println(arr1[0]);
  }
}

 

 

배열 레퍼런스와 배열 인스턴스3)

public class Exam0550 {
  public static void main(String[] args) {

    int[] arr1;
    arr1 = new int[5];
    
    // 언제든 배열 인스턴스의 주소를 다른 레퍼런스에 담을 수 있다.
    int[] arr2 = arr1;
    
    // arr2와 arr1은 같은 배열 인스턴스를 가리킨다.
    arr2[0] = 100;
    
    // arr2를 통해 값을 저장한 후, arr1을 통해 값을 꺼낼 수 있다.
    System.out.println(arr1[0]);
  }
}

 

 

배열 레퍼런스와 null)

public class Exam0551 {
  public static void main(String[] args) {

    int[] arr1;
    arr1 = new int[5];

    // 배열 레퍼런스를 초기화시키고 싶다면 null로 설정하라.
    arr1 = null; // 0으로 설정. 즉 레퍼런스가 아무것도 가리키지 않음을 의미.

    // 레퍼런스가 배열 인스턴스를 가리키지 않은 상태에서 사용하려 하면?
    System.out.println(arr1[0]); // NullPointerException 실행 오류!
  }
}

 

 

배열 인스턴스 메모리의 기본 값)

public class Exam0560 {
  public static void main(String[] args) {

    // 로컬 변수는 값을 저장하지 않고 사용할 수 없다.
    int v;
    // System.out.println(v); // 컴파일 오류!

    // 로컬 변수와 달리 new 명령으로 확보된 메모리는 종류에 상관없이 기본 값으로 자동 초기화 된다.
    // 따라서 배열 메모리 또한 생성되는 순간 기본 값으로 자동 초기화 된다.
    // - 정수 배열(byte[], short[], int[], long[]) : 0
    // - 부동소수점 배열(float[], double[]) : 0.0
    // - 논리 배열(boolean[]) : false
    // - 문자 배열(char[]) : '\u0000'
    // - 주소 변수(Object[]) : null
    //

    int[] arr1 = new int[5];
    float[] arr2 = new float[5];
    boolean[] arr3 = new boolean[5];
    char[] arr4 = new char[5];
    Object[] arr5 = new Object[5];

    System.out.println(arr1[0]);
    System.out.println(arr2[0]);
    System.out.println(arr3[0]);
    System.out.println(arr4[0]);
    System.out.println(arr5[0]);
  }
}

 

 

배열 메모리 초기화)

public class Exam0570 {
  public static void main(String[] args) {
    // 배열 선언
    int[] arr1 = new int[5]; // OK!

    // 배열 메모리를 특정 값으로 초기화
    arr1[0] = 100;
    arr1[1] = 90;
    arr1[2] = 80;
    arr1[3] = 70;
    arr1[4] = 60;

    // 1) 배열 선언 + 초기화 명령
    int[] arr2 = new int[] { 100, 90, 80, 70, 60 }; // OK!
    // int[] arr2 = new int[5]{100, 90, 80, 70, 60}; // 문법오류! 배열 개수 지정하면 안된다.

    // 2) 배열 선언 + 초기화 명령 II
    int[] arr3 = { 100, 90, 80, 70, 60 }; // new int[] 생략 가능

    // 그러나 배열 변수를 선언한 후 따로 초기화시킬 때는
    // 다음과 같이 new 명령을 생략할 수 없다.
    int[] arr4;
    // arr4 = {100, 90, 80, 70, 60}; // 컴파일 오류!

    // 배열 초기화 명령을 따로 실행할 때는 new int[] 를 생략할 수 없다.
    int[] arr5;
    arr5 = new int[] { 0, 0, 0, 0, 0 };

    System.out.println(arr1);
    System.out.println(arr2);
    System.out.println(arr3);
    System.out.println(arr5);

  }
}


[I@5e91993f
[I@1c4af82c
[I@379619aa
[I@cac736f

 

 1) 배열 선언 + 초기화
데이터타입[] 변수명 = new 데이터타입[]{값, 값, 값};
- 배열 메모리를 초기화시킬 때는 배열 개수를 지정해서는 안된다.
- 배열을 초기화시키는 값의 개수 만큼 메모리가 만들어진다.
- 즉 다음은 값 개수만큼 int 메모리가 3개가 생성된다.
ex) int[] arr = new int[]{10, 20, 30};
- 다음과 같이 new 명령을 생략할 수 있다.
데이터타입[] 변수명 = {값, 값, 값};
ex) int[] arr = {10, 20, 30};


  2) 배열 선언 후 따로 배열 초기화 문장 실행
데이터타입[] 변수명;
변수명 = new 데이터타입[]{값, 값, 값};
ex) int[] arr1;
arr1 = new int[]{10, 20, 30};
- 변수를 선언한 후 따로 배열을 초기화시킬 때는
new 명령을 생략할 수 없다.

 

 

배열 인스턴스와 가비지)

## 가비지(garbage)
- 주소를 잃어 버려 사용할 수 없는 메모리
- 특정 조건이 되면 가비지 수집기(garbage collector)에 의해 메모리 해제된다.
  메모리 해제? 다른 용도로 사용할 수 있도록 표시한다는 의미다.
   
## 가비지 수집 조건 = 가비지 컬렉터가 동작할 때
- 메모리가 부족할 때
  - 운영체제로부터 메모리를 추가로 받기 전에 먼저 기존에 사용하던 메모리에서 
    가비지를 제거한다.
- CPU가 한가할 때
  - 24시간 365일 내내 실행하는 서버 프로그램인 경우, 실행 중간에 CPU가 한가할 때 
    가비지를 제거한다.
- 주의!
  - 프로그램(JVM)을 종료하면 JVM 사용한 메모리를 운영체제가 모두 회수한다.
   
## 가비지를 강제로 지우도록 명령하는 방법?
- 자바는 없다!
- C 언어 => free(메모리주소);
- C++ 언어 => delete 객체주소;
- 요즘 언어의 트랜드는 사용하지 않는 메모리를 개발자가 직접 해제하는 것이 아니라 
  VM이 해제하는 것이다.
  예) JavaScript, C#, Python, PHP, Go, Java 등
- 요즘 언어의 트랜드는 VM으로 실행하는 것이다.
  왜? 직접 기계어로 전환되면 메모리를 관리를 자동으로 수행할 수 없다.
   
## 가비지 컬렉터를 강제로 실행하는 방법?
- 없다!
- 단 원래 계획보다 가능한 빨리 실행하라고 독촉하는 방법은 있다.
  System.gc() 메서드 호출
- 그런데 바로 실행할 지 나중에 실행할 지 그 시점을 보장하지는 않는다. 

 

public class Exam0580 {
  public static void main(String[] args) {

    int[] arr1;
    arr1 = new int[5];
    arr1[0] = 100;
    
    // 레퍼런스에 다른 배열 인스턴스의 주소를 담을 수 있다.
    arr1 = new int[] {200, 200, 200};
    // 주의!
    // - arr1이 보관하고 있던 주소는 잃어버렸기 때문에 이전 배열 인스턴스는 사용할 수 없다.
    // - 이렇게 주소를 잃어버려 사용할 수 없는 인스턴스(메모리)를 '가비지(garbage)'라 부른다.
    //
    
    // 새 배열 인스턴스의 값 출력하기
    System.out.println(arr1[0]);
  }
}


200

 

 

 

#3 콘솔로 출력하기

콘솔로 출력하기)

public class Exam0110 {
  public static void main(String[] args) {
    // 값 출력하기
    // println() = 출력 + 줄바꿈
    System.out.println(20);
    System.out.println(3.14f);
    System.out.println("Hello");
    System.out.println('Y');
    System.out.println(true);

    // 값을 주지 않으면 줄바꿈만 수행한다.
    System.out.println();

    // print() 는 출력만 한다. 줄바꿈 없다.
    System.out.print(20);
    System.out.print(3.14f);
    System.out.print("Hello");
    System.out.print('Y');
    System.out.print(true);

    // 이스케이프 문자를 통해 줄바꿈을 수행한다.
    System.out.print('\n');

    System.out.print("OK!\n"); // ==> println("Ok!")
    System.out.print("Hi!\n"); // ==> println("Hi!");

  }
}


20
3.14
Hello
Y
true

203.14HelloYtrue
OK!
Hi!

 

 

콘솔로 출력하기2)

public class Exam0120 {
  public static void main(String[] args) {

    //형식을 지정하지 않으면 print()와 같다. 
    System.out.printf("Hello!\n");

    // %s : 지정한 자리에 문자열을 삽입한다.
    //      삽입할 값은 오른쪽에 설정한다.
    System.out.printf("이름: %s\n", "홍길동");
    System.out.printf("안녕하세요! %s입니다.\n", "임꺽정");

    // %d : 정수 값을 10진수 문자열로 만들어 삽입한다.
    // %x : 정수 값을 16진수 문자열로 만들어 삽입한다.
    // %c : 정수 값을 문자로 만들어 삽입한다.
    // %b : true/false 값을 문자열로 만들어 삽입한다.
    System.out.printf("%d %x %c %b\n", 65, 65, 65, false);

    // 한 개의 값을 여러 곳에 삽입할 수 있다.
    // %[n$]s : n은 문자열에 삽입될 값의 순서이다. 순서는 1부터 증가한다.
    System.out.printf("%d %1$x %1$c\n", 65);
    System.out.printf("%3$d %1$x %2$c\n", 65, 66, 67); // 3$(67), 1$(65), 2$(66)

    // 값을 삽입할 때 사용할 공간을 지정할 수 있다.
    // 문자열을 삽입할 때: 
    //   %[-][사용할공간너비]s : -는 왼쪽 정렬이다. 안 붙이면 기본 오른쪽 정렬이다.
    System.out.printf("'%-10s' '%10s'\n", "홍길동", "임꺽정");
    System.out.printf("'%-10d' '%10d'\n", 12345, 12345);

    // 정수를 삽입할 때:
    //   %[0][사용할공간너비]d : 앞의 빈자리는 0으로 채운다.
    //   %[+][0][사용할공간너비]d : +는 숫자 앞에 부호를 붙인다.
    System.out.printf("'%010d' '%07d'\n", 12345, 12345);
    System.out.printf("'%+010d' '%+07d'\n", 12345, -12345);
  }
}


Hello!
이름: 홍길동
안녕하세요! 임꺽정입니다.
65 41 A false
65 41 A
67 41 B
'홍길동       ' '       임꺽정'
'12345     ' '     12345'
'0000012345' '0012345'
'+000012345' '-012345'

 

 

콘솔로 출력하기3)

형식을 갖춰서 날짜 값 출력하기

public class Exam0130 {
  public static void main(String[] args) {
    // 현재 날짜 및 시각 정보를 생성한다.
    // java.lang 패키지의 멤버를 사용할 때는 그냥 이름을 지정하면 된다.
    // 그 외 다른 패키지의 멤버를 사용할 때는 반드시 패키지 이름을 함께 지정해야 한다.
    java.util.Date today = new java.util.Date();

    // %t[날짜 및 시각 옵션]
    // 날짜 및 시간 옵션
    // Y : 날짜 및 시각 데이터에서 년도를 추출하여 4자리로 표현한다.
    // y : 날짜 및 시각 데이터에서 년도를 추출하여 뒤의 2자리로 표현한다.
    System.out.printf("%1$tY, %1$ty\n", today); // 1$ : 콤마(,) 다음에 첫번째 값 = 'today'

    // B : 날짜 및 시각 데이터에서 월을 추출하여 전체 이름으로 표현한다. ex) January
    // b : 날짜 및 시각 데이터에서 월을 추출하여 단축 이름으로 표현한다. ex) Jan
    System.out.printf("%1$tB, %1$tb\n", today);

    // m : 날짜 및 시각 데이터에서 월을 추출하여 2자리 숫자로 표현한다. ex) 12, 01
    System.out.printf("%1$tm\n", today);

    // d : 날짜 및 시각 데이터에서 일을 추출하여 2자리 숫자로 표현한다. ex) 01, 22
    // e : 날짜 및 시각 데이터에서 일을 추출하여 1자리 숫자로 표현한다. ex) 1, 22
    System.out.printf("%1$td %1$te\n", today);

    // A : 날짜 및 시각 데이터에서 요일을 추출하여 긴 이름으로 표현한다. ex) Sunday
    // a : 날짜 및 시각 데이터에서 요일을 추출하여 짧은 이름으로 표현한다. ex) Sun
    System.out.printf("%1$tA %1$ta\n", today);

    // H : 날짜 및 시각 데이터에서 시각을 추출하여 24시로 표현한다.
    // I : 날짜 및 시각 데이터에서 시각을 추출하여 12시로 표현한다.
    System.out.printf("%1$tH %1$tI\n", today);

    // M : 날짜 및 시각 데이터에서 시각을 추출하여 분을 표현한다.
    System.out.printf("%1$tM\n", today);

    // S : 날짜 및 시각 데이터에서 시각을 추출하여 초를 표현한다.
    // L : 날짜 및 시각 데이터에서 시각을 추출하여 밀리초를 표현한다.
    // N : 날짜 및 시각 데이터에서 시각을 추출하여 나노초를 표현한다.
    System.out.printf("%1$tS %1$tL %1$tN\n", today);

    // p : 오전 오후 출력하기
    //     소문자 p를 사용하면 am 또는 pm으로 출력하고, 
    //     대문자 P를 사용하면 AM 또는 PM으로 출력한다.
    //     한글은 대소문자가 없기 때문에 의미없다.
    System.out.printf("%1$tp\n", today);

    // 년-월-일 시:분:초를 출력하라! 예) 2019-01-04 12:04:30
    System.out.printf("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS\n", today);
  }
}


2023, 23
5월, 5월
05
30 30
화요일 화
18 06
50
22 641 641000000
오후
2023-05-30 18:50:22

 

 

 

#4 키보드 입력 받기

System.out
- 표준 출력 장치.
- 즉 콘솔(모니터, 명령창)을 가리킨다.
System.in
- 표준 입력 장치.
- 즉 키보드를 가리킨다.

 

 

키보드 입력 받기1)

public class Exam0210 {
  public static void main(String[] args) {
    // 1) 키보드로 입력한 데이터를 읽을 때 사용할 도구를 준비한다.
    java.io.InputStream keyboard = System.in;

    // 2) InputStream은 바이트 단위로 읽는 기능이 있다.
    //    바이트 단위로 읽어서 int나 문자열로 바꾸려면 또 코딩해야 하는 불편함이 있다.
    //    이런 불편함을 줄이기 위해 자바에서는 바이트를 개발자가 원하는 값으로
    //    바꿔주는 기능이 들어 있는 도구를 제공한다.
    //    그 도구가 java.util.Scanner 이다.
    // => 키보드를 스캐너에 연결한다.
    java.util.Scanner keyboardScanner = new java.util.Scanner(keyboard);

    // print()는 문자열을 출력한 후 줄 바꿈을 하지 않는다.
    System.out.print("팀명? ");
    System.out.println("팀명? ");
    System.out.printf("팀명? ");
    

    // nextLine()
    // - Scanner 도구를 사용하여 키보드로부터 한 줄의 문자열을 
    //   가져올 때 사용하는 명령이다.
    // - 동작은?
    //   사용자가 한 줄 입력할 때까지,
    //   즉 입력 데이터에 줄바꿈을 의미하는 0d0a 2바이트가 들어올 때까지 대기한다.
    //   사용자가 엔터키를 누르면, 
    //   입력값으로 0d0a 2바이트 값이 들어오고,
    //   nextLine()은 그 전까지 들어온 데이터를 문자열로 만들어 리턴한다.
    String str = keyboardScanner.nextLine();

    // 사용자가 입력한 문자열을 출력한다.
    System.out.println(str);

    // 스캐너는 사용 후 키보드와의 연결을 끊고 닫는다.
    keyboardScanner.close();  // close는 메서드(명령어) & 메서드 '콜'(호출) 한다고 한다.
  }
}


팀명? 팀명? 
팀명? ABC
ABC

 

 

키보드 입력 받기2 - 문자열 한 줄 읽기)

public class Exam0220 {
  public static void main(String[] args) {
    java.io.InputStream keyboard = System.in;
    java.util.Scanner keyboardScanner = new java.util.Scanner(keyboard);

    // 팀 멤버의 정보를 입력 받아 출력하라.
    // 이름, 전화, 이메일, 나이, 재직여부

    System.out.print("이름? ");
    System.out.println(keyboardScanner.nextLine());
    System.out.print("전화? ");
    System.out.println(keyboardScanner.nextLine());
    System.out.print("이메일? ");
    System.out.println(keyboardScanner.nextLine());
    System.out.print("나이? ");
    System.out.println(keyboardScanner.nextLine());
    System.out.print("재직여부? ");
    System.out.println(keyboardScanner.nextLine());

    // 예)
    // 이름? 홍길동
    // 홍길동
    // 전화? 1111-2222
    // 1111-2222
    // 이메일? hong@test.com
    // hong@test.com
    // 나이? 20
    // 20
    // 재직여부? y
    // y

    keyboardScanner.close();	//keyboardScanner 를 닫는 역할, 객체가 더 이상 사용되지 않을 때
    						// 자원 누수를 방지하고 프로그램의 안정성과 성능을 향상시킬 수 있습니다.
  }
}

 

 

키보드 입력 받기3 - int, float, boolean 값 읽기)

public class Exam0230 {
  public static void main(String[] args) { 
    java.util.Scanner keyScan = new java.util.Scanner(System.in);

    System.out.print("int: ");
    int i = keyScan.nextInt();
    // nextInt()는 한 개의 토큰(token)을 읽을 때가지 기다린다.
    // 한 개의 token을 읽으면 4바이트 정수 값으로 바꾼 다음에 리턴한다.
    // 토큰(token)?
    // => 토큰이란 공백으로 구분되는 단어를 뜻한다.
    // 공백(whitespace)?
    // => 스페이스(space), 탭, 줄바꿈 코드를 말한다.
    // 예) aaa    bbb cc ==> aaa, bbb, cc
    // 중간에 여러 개의 공백이 들어가더라도 한 개의 공백으로 간주한다.

    System.out.print("float: ");
    float f = keyScan.nextFloat();

    System.out.print("boolean: ");
    boolean b = keyScan.nextBoolean();

    keyScan.close();

    System.out.printf("%d, %f, %b\n", i, f, b);
  }
}


int: 10
float: 10
boolean: true
10, 10.000000, true

 

 

키보드 입력 받기4 - 여러 종류의 데이터를 섞어 입력 받기)

public class Exam0240 {
  public static void main(String[] args) { 
    java.util.Scanner keyboardScanner = new java.util.Scanner(System.in);

    System.out.print("나이? ");
    int age = keyboardScanner.nextInt(); // <- 여기서 값과 enter를 입력하지 않으면 출력을 정지한다.
    // nextInt()는 한 개의 토큰을 읽은 후에 줄 바꿈 코드는 읽기 전 상태로 내비둔다.
    // 따라서 다음에 nextLine()을 호출하면 의도치 않게 빈 문자열을 가진 한 줄을 
    // 읽는 상황이 된다. 
    // nextInt() 다음에 nextLine()을 호출할 때 이런 상황이 발생한다.
    // 해결 방법? nextInt()를 호출한 후 남아있는 엔터 코드를 읽어서 제거하라.
    keyboardScanner.nextLine(); // 남아 있는 빈 문자열의 한 줄(LF 코드)을 읽어서 버린다.

    System.out.print("이름? ");
    String name = keyboardScanner.nextLine();

    keyboardScanner.close();

    System.out.printf("%d(%s)\n", age, name);
  }
}


나이? 99
이름? 홍길동
99(홍길동)

 

 

키보드 입력 받기5 - 여러 개의 데이터를 한번에 입력하고 쪼개서 읽기)

 

public class Exam0250 {
  public static void main(String[] args) { 
    java.util.Scanner keyboardScanner = new java.util.Scanner(System.in);

    System.out.print("나이, 이름, 취업여부? ");
    int age = keyboardScanner.nextInt();  // 'enter'를 입력할 때까지 계속 기다림

    // 한 개의 토큰을 읽을 때 유용하다.
    String name = keyboardScanner.next();

    boolean working = keyboardScanner.nextBoolean();

    keyboardScanner.close();

    System.out.printf("%d, %s, %b\n", age, name, working);
  }
}


나이, 이름, 취업여부? 99 홍길동 true
99, 홍길동, true

 

 

키보드 입력 받기6 - 토큰 단위로 문자열 읽기)

public class Exam0260 {
  public static void main(String[] args) { 
    java.util.Scanner keyboardScanner = new java.util.Scanner(System.in);

    // next()
    // - 토큰 단위로 입력 데이터를 잘라서 읽을 때 유용하다. 
    System.out.print("입력: ");
    String token1 = keyboardScanner.next();
    String token2 = keyboardScanner.next();
    String token3 = keyboardScanner.next();

    keyboardScanner.close();

    System.out.printf("%s, %s, %s\n", token1, token2, token3);
  }
}

입력: A
B
C
A, B, C

 

 

 

#5 반복문

반복문을 배우기 앞서 약 20개의 데이터를 손수 입력 및 출력 해보고 배웠습니다.

 

흐름 제어문1 - 반복문 while)

 

문법1 : while (조건) 문장;

=> 조건이 참인 동안 문장을 계속 실행합니다.

public class Exam0310 {
	public static void main(String[] args) {
    int count = 0;
    while (count < 5) System.out.println(count++);
    }
}


0
1
2
3
4

 

문법2 : while (조건)

                    문장;

=> 조건이 참인 동안 문장을 계속 실행한다.

public class Exam0310 {
	public static void main(String[] args) {
    	count = 0;
        while (count < 5)
        	System.out.println(count++);
    }
}


0
1
2
3
4

 

문법3 : while (조건) {}

=> 여러개의 문장을 반복 실행하려면 블록으로 묶기

public class Exam0310 {
	public static void main(String[] args) {
    	count = 0;
        while (count < 5) {
        	System.out.println(count);
            count++;
    }
}


0
1
2
3
4

 

흐름 제어문2 - 반복문 while - break와 continue 활용)

1부터 100까지 합은?

public class Exam0320 {
  public static void main(String[] args) {
    int count = 0;
    int sum = 0;

    // 1부터 100까지의 합은?
    while (count < 100) {
      //count++;
      //sum += count; // sum = sum + count;
      sum += ++count;
    }
    System.out.printf("count=%d, sum=%d\n", count, sum);
  }
}


count=100, sum=5050

 

1부터 100가지의 짝수의 합은?

public class Exam0321 {
  public static void main(String[] args) {
    int count = 0;
    int sum = 0;


    // 1부터 100까지의 짝수의 합은?
    // => continue 사용 전
    count = 0;
    sum = 0;
    while (count < 100) {
      count++;
      if ((count & 1) == 0) { // count & 1 ==> count & 0x01 ==> count % 2 //count & 1 : 'count'와 1을 비트 AND 연산하여 결과를 얻어 'count'가 짝수가 됌을 의미함.
        sum += count;
      }
    }
    System.out.printf("count=%d, sum=%d\n", count, sum);

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

    // => continue 사용 후
    count = 0;
    sum = 0;
    while (count < 100) {
      count++;
      if (count % 2 == 1) // => 'count' 가 홀수일 경우 'sum'에 값을 더하지 않도 다음 반복으로 넘어감
        continue; // 다음 문장을 실행하지 않고 즉시 조건 검사로 이동한다.
      sum += count; // 'sum'에 1부터 100까지의 짝수의 합이 저장
    }
    System.out.printf("count=%d, sum=%d\n", count, sum);
  }
}


count=100, sum=2550
------------------------
count=100, sum=2550

 

1부터 100까지의 카운트를 하는데 합은 50까지만 계산

public class Exam0322 {
  public static void main(String[] args) {
    int count = 0;
    int sum = 0;

    // 1부터 100까지의 카운트를 하는데 단 합은 50까지만 계산한다.
    // => break 사용 전
    count = 0;
    sum = 0;
    while (count < 100) {
      count++;
      if (count > 50) // 50을 넘어가면 합을 수행하지 않지만 100까지 계속 반복한다.
        continue;
      sum += count;
    }
    System.out.printf("count=%d, sum=%d\n", count, sum);

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

    // => break 사용 후
    count = 0;
    sum = 0;
    while (count < 100) {
      count++;
      if (count > 50)
        break; // 즉시 반복문을 종료하고 나간다.
      sum += count;
    }
    System.out.printf("count=%d, sum=%d\n", count, sum);

  }
}


count=100, sum=1275
------------------------
count=51, sum=1275

 

 

흐름 제어문3 - 반복문 while - 중첩된 반복문 탈출)

구구단

public class Exam0330 {
  public static void main(String[] args) {
    int x = 2, y = 1;

    // 5 * 5 까지만 출력하라!
    //
    while (x <= 9) {	// 'x'가 2부터 9까지 증가하는 동안 반복

      while (y <= 9) {	// 'y'가 1부터 9까지 증가하는 동안 반복
        System.out.printf("%d * %d = %d\n", x, y, x * y);
        if (x == 5 && y == 5)
          break; // 이 break는 자신이 소속된 가장 가까운 반복문을 나간다.
        y++;
      }

      System.out.println();
      x++;	// 'x'를 증가시키고
      y = 1;	// 'y'를 1로 초기화
    }
    System.out.println("종료!!");
  }
}


2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
2 * 4 = 8
2 * 5 = 10
2 * 6 = 12
2 * 7 = 14
2 * 8 = 16
2 * 9 = 18

3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
3 * 4 = 12
3 * 5 = 15
3 * 6 = 18
3 * 7 = 21
3 * 8 = 24
3 * 9 = 27

4 * 1 = 4
4 * 2 = 8
4 * 3 = 12
4 * 4 = 16
4 * 5 = 20
4 * 6 = 24
4 * 7 = 28
4 * 8 = 32
4 * 9 = 36

5 * 1 = 5
5 * 2 = 10
5 * 3 = 15
5 * 4 = 20
5 * 5 = 25

6 * 1 = 6
6 * 2 = 12
6 * 3 = 18
6 * 4 = 24
6 * 5 = 30
6 * 6 = 36
6 * 7 = 42
6 * 8 = 48
6 * 9 = 54

7 * 1 = 7
7 * 2 = 14
7 * 3 = 21
7 * 4 = 28
7 * 5 = 35
7 * 6 = 42
7 * 7 = 49
7 * 8 = 56
7 * 9 = 63

8 * 1 = 8
8 * 2 = 16
8 * 3 = 24
8 * 4 = 32
8 * 5 = 40
8 * 6 = 48
8 * 7 = 56
8 * 8 = 64
8 * 9 = 72

9 * 1 = 9
9 * 2 = 18
9 * 3 = 27
9 * 4 = 36
9 * 5 = 45
9 * 6 = 54
9 * 7 = 63
9 * 8 = 72
9 * 9 = 81

종료!!

 

라벨을 주고 소속된 문장을 나가기

라벨명 : 반복문1 { 반복문2 { break 라벨명;}}

라벨 문법 : 

        라벨 : 문장;

        라벨 : {문장1, 문장2, ...}

public class Exam0331 {
  public static void main(String[] args) {
    int x = 2, y = 1;

    myloop:  // myloop 라벨
      while (x <= 9) {

        while (y <= 9) {
          System.out.printf("%d * %d = %d\n", x, y, x * y);
          if (x == 5 && y == 5)
            break myloop; // myloop 라벨에 소속된 문장을 나간다.
          y++;
        }

        System.out.println();
        x++;
        y = 1;
      }
    System.out.println("종료!!");

    System.out.println("-----------------------------");
  }
}


2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
2 * 4 = 8
2 * 5 = 10
2 * 6 = 12
2 * 7 = 14
2 * 8 = 16
2 * 9 = 18

3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
3 * 4 = 12
3 * 5 = 15
3 * 6 = 18
3 * 7 = 21
3 * 8 = 24
3 * 9 = 27

4 * 1 = 4
4 * 2 = 8
4 * 3 = 12
4 * 4 = 16
4 * 5 = 20
4 * 6 = 24
4 * 7 = 28
4 * 8 = 32
4 * 9 = 36

5 * 1 = 5
5 * 2 = 10
5 * 3 = 15
5 * 4 = 20
5 * 5 = 25
종료!!
-----------------------------

 

 

흐름 제어문4 - 반복문 do ~ while)

do ~ while
- 최소 한 번은 반복한다.
- 한 번 이상 반복하면 do ~ while
- 0 번 이상 반복하면 while

  do
    문장1;
  while (조건);

  do {
    문장1;
    문장2;
    문장3;
  } while (조건);

 

public class Exam0340 {
  public static void main(String[] args) {
    int i = 0;

    // 1부터 10까지 출력하기
    do
      System.out.println(++i);
    while (i < 10);

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

    // 여러 개의 문장을 반복할 때는 블록으로 묶어라!
    i = 0;
    do {
      i += 1;
      System.out.println(i);
    } while (i < 10);
  }
}


1
2
3
4
5
6
7
8
9
10
---------------------
1
2
3
4
5
6
7
8
9
10

 

 

흐름 제어문5 - 반복문 for)

public class Exam0410 {
  public static void main(String[] args) {
    // for (변수선언 및 초기화; 조건; 증감문) 문장;
    // for (변수선언 및 초기화; 조건; 증감문) {문장1; 문장2; ...}

    // for 문의 전형적인 예
    for (int i = 1; i <= 5; i++)
      System.out.println(i);
    // 실행 순서
    // 1) 변수초기화  => int i = 1
    // 2) 조건 => i <= 5
    // 3) 문장 => System.out.print(i + " ")
    // 4) 변수증가문 => i++
    // 조건이 참인 동안 2 ~ 4를 반복한다.

    // for 문에서 선언한 변수는 그 for 문 안에서만 사용할 수 있다.
    //    System.out.println(i); // 컴파일 오류!
  }
}


1
2
3
4
5

 

public class Exam0411 {
  public static void main(String[] args) {
    // for (변수선언 및 초기화; 조건; 증감문) 문장;
    // for (변수선언 및 초기화; 조건; 증감문) {문장1; 문장2; ...}

    // 증감문 제거
    for (int i = 1; i <= 5;    ) {
      System.out.println(i);
      i++;	// <= 증가문을 for문에서 제거 후 입력
    }

  }
}

 

public class Exam0412 {
  public static void main(String[] args) {
    // for (변수선언 및 초기화; 조건; 증감문) 문장;
    // for (변수선언 및 초기화; 조건; 증감문) {문장1; 문장2; ...}

    // 변수 선언 및 초기화 문장 제거
    int i = 1;
    for (    ; i <= 5;    ) {	// 조건문만 두고 변수선언 및 초기화와 증감문 제거
      System.out.println(i);
      i++;
    }

    // for 문을 종료한 후에도 i 변수를 사용할 수 있다.
    System.out.println(i);
  }
}


1
2
3
4
5
6

 

public class Exam0413 {
  public static void main(String[] args) {
    // for (변수선언 및 초기화; 조건; 증감문) 문장;
    // for (변수선언 및 초기화; 조건; 증감문) {문장1; 문장2; ...}

    // 조건문 제거
    int i = 1;
    for (  ;  ;  ) {	// 변수선언 및 초기와, 조건, 증감문 다 제거
      if (i > 5)
        break;
      System.out.println(i);
      i++;
    }

  }
}


1
2
3
4
5

 

 

 

#6 HDD Track Sector

이미지 출처 : 처 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=capemay&logNo=220221154613

 

데이터는 디스크의 트랙(Track)이라는 부분에 기록 되는데 이는 그림처럼 플래터 위의 동심원입니다.

트랙은 숫자가 붙여져 있으며 플래터 바깥면부터 0으로 시작 됩니다.

 

트랙은 섹터(Sector)라는 작은 단위들로 나누어져 있으며, 자체적으로 주소를 가지고 있는 스토리지의 단위입니다. 최근에는 하나의 트랙에 다수의 섹터들이 들어가 있으며 플래터에 수천개의 트랙들이 있을 수 있습니다.

 

실린더(Cylinde)는 각 드라이브 플래터 표면에 동일한 트랙들의 집합으로 헤드는 트랙번호가 아닌 실린더 번호르 참조하게 됩니다.

 

대표적으로 섹터는 512byte의 유저 데이터를 가지고 있지만, 몇 디스크들은 더 큰 섹터 사이즈로 초기화 되어 있기도 합니다. 추가적으로 섹터는 유저 데이터뿐만 아니라 다른 정보도 가지고 있는데, 섹터 번호, 헤드번호 또는 플래터 번호 그리고 트랙번호 등이 있습니다.

 

따라서 초기화(Formatted)된 디스크와 초기화가 되지 않은(Unformatted) 디스크에서 용량 차이가 발생하게 되며, 드라이브 제조사 또한 이러한 정보를 알리고 있습니다.

 

 

 

#7 CPU & CACHE

이미지출처 : https://woozzang.tistory.com/155

 

캐시 메모리는 최상단 티어에 위치한 메모리이며, 메인 메모리보다 훨씬 작고 가격이 매우 비싸며 속도가 빠른 것이 특징입니다.

레지스터 다음으로 CPU 코어 가까이에 위치해있기 때문입니다.

 

캐시는 프로그램에서 직접 읽거나 쓸 수 없고, 하드웨어 메모리 관리 시스템에서 내부적으로 제어합니다. 그래서 프로그래머가 코드상에서 접근할 수 있는 방법이 없습니다.

 

캐시를 관통하는 중요한 개념은 데이터 지역성입니다. 데이터 지역성을 활용하여 메인 메모리에 있는 데이터를 캐시 메모리에 불러와두고, CPU가 상대적으로 접근 시간이 느린 메인 메모리 대신 캐시 메모리에 우선적으로 접근하게 하면 성능의 향상을 기대할 수 있습니다.

 

데이터 지역성은 시간 지역성, 공간 지역성, 순차적 지역성으로 분류됩니다.

시간 지역성은 한번 참조된 데이터는 잠시 후에 또 참조될 가능성이 높다는 것입니다.

 

공간 지역성은 A[0], A[1] 로 구성되는 배열과 같이 참조된 데이터 근처의 데이터가 잠시후에 사용될 가능성이 높다는 것입니다. 해당 배열이 위치한 메모리 공간의 내용은 for-in 순회가 끝나기 전까지 계속 쓰일 확률이 높습니다.

 

순차적 지역성은 비순차적 실행이 아닌 이상 명령어들이 메모리에 저장된 순서대로 실행되는 특성을 고려하여 다음 순서의 데이터가 곧 사용될 가능성이 높다는 것입니다.

 

캐시는 CPU와 메인 메모리 사이의 속도 간극을 줄여주는 완충재이며, 버퍼라고도 불립니다.

 

이미지출처 : https://mblogthumb-phinf.pstatic.net/20120820_259/rmflqhd_13454427767370VDpR_JPEG/3.jpg?type=w2

 

시스템에 장착된 캐시의 용량과 성능이 점점 증가하면서 캐시의 캐시로 사용되는 메모리가 추가되었습니다.

이것을 적용된 순서대로 L(Level) 1, L2, L3 ... 라고 호칭합니다.

 

우리 말로 하면 '1차 캐시', '2차 캐시', '3차 캐시 메모리'가 됩니다.

L1에 가장 고성능이자 고가인 작은 용량의 집적회로가 사용되고, L1캐시에서 데이터를 퍼가기 위한 캐시로 사용하기 위해 그보다는 용량이 크지만 그 대신 약간 더 느린 저장공간 L2가 추가되었습니다.

 

보통 L1 캐시 메모리에는 명령어 캐시와 데이터 캐시가 따로 있습니다.

그 중 데이터 캐시는 CPU 가 직전에 사용한 데이터를 저장하거나, 바로 실행되어야 하는 중요한 파일을 저장해 놓는데에 사용합니다.

" It is used to store data that was accessed by the processor recently, critical files that need to be executed immediately and it is the first cache to be accessed and processed when the processor itself performs a computer instruction. "

 

L1 캐시 메모리는 CPU에 직접 데이터를 공급해 주기 때문에 빠른 접근 지연 시간(Access latency)이 매우 중요한데,

명령어는 보통 공간 지역성이 높고 데이터는 보통 시간 지역성이 높습니다.

 

그러므로 이 둘을 나누어 서로 다른 지역성을 이용할 수 있습니다.

또한 명령어와 데이터를 동시에 읽어올 수 있게 함으로써 CPU의 파이프라이닝 성능을 향상시킬 수 있게 됩니다.

 

L2 캐시 메모리는 딱히 둘의 구분 없이 하나의 캐시 메모리로 구성되어있습니다.

L1 캐시는 보통 8~64KB 정도의 용량으로 CPU가 가장 빠르게 접근하게 되며, 여기서 데이터를 찾지 못하면 이제 L2 캐시 메모리로 넘어가서 찾습니다.