[Java] Encoding, Scanner, DeepCopy

Jay Mild Lee·2022년 11월 8일
0

Java

목록 보기
4/10
post-thumbnail

I. Encoding

1. ASCII

1byte를 사용해 알파벳, 공백, 쉼표, 특수문자 등을 표현하는 문자체계. 최상위 비트는 0으로 고정되어 있으며 7bit를 사용한다. 영어를 제외한 다른 언어를 나타낼 수 없다.

2. Extended ASCII

영어를 제외한 다른 언어를 표현하기 위해 ASCII에서 비어있는 구간(128 ~ 256)에 해당하는 공간을 활용하는 체계이다. 하지만 각 언어별로 제한된 공간을 사용하는 방법이 다르다보니, 표준화된 양식을 제공하기 어렵다.

3. Unicode

국제 표준화 기구에 의해 개발된 문자체계. 2Byte를 기준으로 개발되었으며, 각 언어별로 고유한 공간을 제공받는다. 하지만 데이터양을 간소화할 수 있는 언어(ex. 영어)들도 동일하게 문자 하나에 2Byte를 사용해야한다는 점에서 단점이 존재한다.

4. UTF-8

가변 길이를 지원하는 문자체계. 언어별로 최적화된 공간에 문자를 저장하며, 영문은 1byte 한글은 3byte를 사용한다.

5. String Class에서의 적용

1) 배열을 해석할 때 Encoding 방식 지정

String [변수] = new String("문자열","인코딩 형식");

String str = new String("안녕하세요", "UTF-8");

2) String을 배열로 분해할 때 Encoding 방식 지정

byte [배열 이름][] = [String 이름].getBytes("인코딩 형식");

byte array[] = str.getBytes("unicode");

6. Compile 단계에서 적용

error: unmappable character (0xEC) for encoding x-windows-949

컴파일 시 위와 같은 에러가 발생한다면 인코딩 옵션을 추가하면 된다.

javac (...생략...) -encoding [인코딩 형식]
javac (...생략...) -encoding utf-8

II. Scanner 버퍼 초기화

1. Scanner Class 요약

Scanner로 입력을 받을 땐, 자료형을 구분하여 입력받는 것이 깔끔하다. 쓸데 없는 타입변환은 지양하자.

  • int i = scannner.nextInt();
  • String str = scanner.nextLine();
  • char c = scan.nextLine().charAt(0);
    단독으로 사용할 것이라면 System.in.read() 쓰는게 나을듯_
  • double d = scan.nextDouble();

2. 버퍼 초기화를 굳이 왜?

	Scanner scanner = new Scanner(System.in);

    System.out.print("Grid의 크기를 입력하세요(X * X): ");
    int inputNumber = scanner.nextInt();

    for (int i = 0; i < inputNumber; i++){
      String tmp = null;
      while (tmp == null){
        System.out.printf("%d번째 라인을 입력하세요: ", i+1);
        tmp = scanner.nextLine();
    }

알고리즘 문제를 풀 때 사용했던 코드를 잘라왔다. 먼저 scanner.nextInt();를 통해 입력된 정수를 받고, 이후 scanner.nextLine();를 통해 String을 받아내는 간단한 코드이다. 하지만 실행을 해보면, scanner.nextLine();의 리턴 값이 비어있는 것을 확인 할 수 있다.

1) 원인

유저에 의해 입력된 값들은 큐 형태로 저장된다. 유저가 100을 입력했다면, 큐에 저장된 내용은 다음과 같다.

Queue <- [100][Enter]

scanner.nextInt(); 메소드는 Enter나 Space를 기준으로 가장 가까운 int를 반환한다. 반환된 이후 큐에 저장된 내용과 변수에 저장된 내용은 다음과 같다.

Queue <- [Enter]

inputnumber <- [100]

scanner.nextLine(); 메소드는 Enter를 기준으로 이전에 입력된 String을 반환한다. 반환된 이후 큐에 저장된 내용과 변수에 저장된 내용은 다음과 같다.

Queue <- (비어있음)

inputnumber <- [100]
tmp <- (비어있음)

Enter 이전에 입력된 값이 없기 때문에, tmp에는 아무런 정보도 저장될 수 없으며 결국 Enter까지 큐에서 정상적으로 빠져 나왔기 때문에 컴파일에도, 실행에도 에러가 없다.

2) 해결

Enter를 중간에 빼주기만 하면 된다. 어렵게 얘기해서 버퍼 초기화지, 결국 scanner.nextLine();을 한번 더 호출해 큐에서 Enter를 제거해주면 된다.

	Scanner scanner = new Scanner(System.in);

    System.out.print("Grid의 크기를 입력하세요(X * X): ");
    int inputNumber = scanner.nextInt();
    
    scanner.nextLine(); // 버퍼초기화

    for (int i = 0; i < inputNumber; i++){
      String tmp = null;
      while (tmp == null){
        System.out.printf("%d번째 라인을 입력하세요: ", i+1);
        tmp = scanner.nextLine();
    }

III. Deep Copy

1. Shallow Copy와 Deep Copy

  • Shallow Copy : 객체의 주소값만을 복사하는 형태. 복사된 배열이나 원본배열이 변경될 때 양쪽의 값이 함께 변경된다.
  • Deep Copy : 객체의 실제값을 복사하는 형태. 복사된 배열이나 원본배열이 변경될 때 한쪽 값만 변경된다.(남발은 메모리 측면에서 비효율적)

1) Shallow Copy 예시

public class Array_Copy{
    public static void main(String[] args)  {
        int[] a = { 1, 2, 3, 4 };
        int[] b = a;
    }
}

2) Deep Copy 예시

2-1) for문을 사용한 예시

public class Array_Copy{
    public static void main(String[] args)  {
        int[] a = { 1, 2, 3, 4 };
        int[] b = new int[a.length]; 
        for (int i = 0; i < a.length; i++) {
            b[i] = a[i];
        }
    }
}

2-2) clone을 사용한 예시

public class Array_Copy{
    public static void main(String[] args)  {
        int[] a = { 1, 2, 3, 4 };
        int[] b = a.clone();
    }
}

2. 2차원 배열의 Deep Copy

Deep Copy 관련 포스트를 작성하게된 이유다. clone();을 사용해 2차원 배열을 Deep Copy하고자 했었다. Deep Copy가 안된 건 의심조차 하지 못한채 원하는 결과가 안나와 메소드 두 어개를 새로 작성하며 몇 번씩 컴파일을 했는데, 범인은 clone();이었다.

"array[x][y]" 형태의 2차원 배열 구조에서, clone();을 사용하면 y좌표를 가르키는 array[x] 부분만 Deep Copy가 된다고 한다. ㅂㄷㅂㄷ

1) 방법

방법은 크게 두 가지로, for문을 돌리는 방법과 System.arraycopy();를 사용하는 방법이 있다. 퍼포먼스 차이가 날지는 모르겠지만, Class를 호출하기보단 for문을 돌리는게 마음 편할 것 같다.

1-1) 이중 for문 사용 예시

public class Array_Copy{
    public static void main(String[] args)  {
        int a[][] = {{1,2,3},{4,5,6,},{7,8,9}};
        int[][] b = new int[a.length][a[0].length];
	    
        for(int i=0; i<a.length; i++) {
            for(int j=0; j<a[i].length; j++) {
                b[i][j] = a[i][j];  
            }
        }
    }
}

1-2) System.arraycopy(); 사용 예시

public class Array_Copy{
    public static void main(String[] args)  {
        int a[][] = {{1,2,3},{4,5,6,},{7,8,9}};
        int b[][] = new int[a.length][a[0].length];
	    
        for(int i=0; i<b.length; i++){
            System.arraycopy(a[i], 0, b[i], 0, a[0].length);
        }
    }
}

0개의 댓글