2020. 11. 20.

2주차 과제: 자바 데이터 타입, 변수 그리고 배열

https://github.com/whiteship/live-study/issues/2

목표

자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.

학습할 것

  • 프리미티브 타입 종류와 값의 범위 그리고 기본 값
  • 프리미티브 타입과 레퍼런스 타입
  • 리터럴
  • 변수 선언 및 초기화하는 방법
  • 변수의 스코프와 라이프타임
  • 타입 변환, 캐스팅 그리고 타입 프로모션
  • 1차 및 2차 배열 선언하기
  • 타입 추론, var


1. 프리미티브 타입 종류와 값의 범위 그리고 기본 값

byte
8-bit signed two's complement integer (8bit 부호있는 2의 보수 정수)
-128 ~ 127(포함)

  • 바이트 데이터 유형은 메모리 절약이 중요한 대형 배열에 메모리를 절약하는데 유용할 수 있습니다.
  • 또한 제한이 코드를 명확히 하는 데 도움이 되는 곳에 int형 대신 사용할 수 있습니다. 변수의 범위를 제한한다는 사실은 문서화의 한 형태로 제공될 수 있습니다.

short
16-bit signed two's complement integer (16bit 부호있는 2의 보수 정수)
-32,768 ~ 32,767(포함)

  • 바이트와 마찬가지로 동일한 지침이 적용됩니다. 메모리 절약이 실제로 중요한 상황에서 short를 사용하여 큰 배열의 메모리를 절약할 수 있습니다.

int
32-bit signed two's complement integer (32비트 부호있는 2의 보수 정수)
-231 ~ 231-1

  • Java SE 8 이상에서는 int 데이터 타입을 사용해 최솟값 0 ~ 최댓값 232-1 unsigned 32-bit integer (부호 없는 32bit 정수)를 표현할 수 있습니다.
  • Integer 클래스를 사용해 int 데이터 유형을 부호없는 정수로 사용합니다. compareUnsigned, divideUnsigned 등과 같은 static methods가 Integer 클래스에 추가되어 unsigned integer에 대한 산술 연산을 지원합니다.

long
64-bit two's complement integer (62bit 2의 보수 정수)
-263 ~ 263-1

  • Java SE 8 이상에서는 long 데이터 타입을 사용해 최솟값 0 ~ 최대값 264-1 unsigned 64-bit long (부호 없는 64bit long)을 표현할 수 있습니다.
  • int에서 제공하는 것보다 더 넓은 값 범위가 필요한 경우 이 데이터 유형을 사용하십시오.
  • Long 클래스에는 unsigned long에 대한 산술 연산을 지원하는 compareUnsigned, divideUnsigned 등의 method도 포함되어 있습니다.

float
single-precision 32-bit IEEE 754 floating point (단정밀도 32bit IEEE 754 부동소수점)

  • 값의 범위는 이 주제의 범위를 벗어나지만, Java 언어 명세서에 부동 소수점 유형, 형식, 값이 명시돼 있습니다.
  • byte나 short의 권장 사항과 마찬가지로 부동 소수점 숫자의 큰 배열에 메모리를 절약해야 하는 경우 double 대신 float를 사용하십시오.
  • 이 데이터 타입은 통화와 같은 정확한 값에 사용해서는 안 됩니다. 이를 위해 대신 java.math.BigDecimal 클래스 사용해야 합니다.
  • 숫자나 문자열은 Java 플랫폼에서 제공하는 BigDecimal이나 다른 유용한 클래스들이 처리를 도와줍니다.

double
double-precision 64-bit IEEE 754 floating point (배정밀도 64bit IEEE 754 부동소수점)

  • 값의 범위는 이 주제의 범위를 벗어나지만, Java 언어 명세서에 부동 소수점 유형, 형식, 값이 명시돼 있습니다.
  • 기본적으로 10진수 입니다.
  • 위에서 언급했듯이 이 데이터 유형은 통화와 같은 정확한 값에 사용해서는 안 됩니다.

boolean
boolean 데이터 유형은 true와 false 두가지 값만 있습니다.

  • 참/거짓 조건을 추적하는 간단한 flag 데이터 타입으로 사용합니다.
  • 이 데이터 타입은 1bit의 정보를 표현하지만 "크기"는 정확하게 정의된 것이 아닙니다.

char
single 16-bit Unicode character (싱글 16bit 유니코드 문자)
'\u0000' (또는 0) ~ '\uffff' (또는 65,535 포함)

기본값

필드(field)가 선언될 때 항상 값을 할당할 필요는 없습니다. 선언되었지만 초기화되지 않은 필드는 컴파일러에 의해 적절한 기본값으로 설정됩니다. 일반적으로는 데이터 타입에 따라 기본값이 0 또는 null입니다. 그러나 기본값에 의존하는 것은 일반적으로 잘못된 프로그래밍 스타일로 간주합니다.

기본값은 다음과 같습니다.


2. 프리미티브 타입과 레퍼런스 타입

Primitive type (기본형 타입)

  • 메모리에 기본형 타입이 보유한 실제 데이터를 저장합니다.
  • 기본형 값이 동일한 유형의 다른 변수에 지정되면 사본이 만들어집니다.
  • 기본형이 메소드에 전달되면 기본형의 복사본만 전달됩니다. 호출된 메소드는 오리지널 기본형 값에 엑세스할 수 없음으로 변경할 수 없습니다. 호출된 메소드는 복사된 값을 변경할 수 있습니다.

Reference type (참조형 타입)

  • 사용자가 정의한 무제한 참조 유형입니다.
  • 메모리에 데이터에 대한 참조를 저장합니다.
  • 참조 유형이 다른 참조 유형에 할당되면 둘 다 동일한 객체를 가리킵니다.
  • 객체가 메소드에 전달되면 호출된 메소드는 전달된 객체의 내용을 변경할 수 있지만 객체의 주소는 변경할 수 없습니다.


3. 리터럴

기본형 타입 변수를 초기화할 때 new 키워드를 사용하지 않는다는 것을 보셨을 겁니다.
기본형 타입은 언어에 내장된 특수 데이터 유형입니다. 클래스에서 생성된 객체가 아닙니다.
리터럴은 고정된 값의 소스 코드 표현입니다. 계산 없이 코드에서 직접 표현됩니다.
아래와 같이 기본형 타입 변수에 리터럴을 할당할 수 있습니다.

boolean result = true;
char capitalC = 'C';
byte b = 100;
short s = 10000;
int i = 100000;


4. 변수 선언 및 초기화하는 방법

int num = 0;
//타입 변수이름 = 값;

//example
int myNum = 5;
float myFloatNum = 5.99f;
char myLetter = 'D';
boolean myBool = true;
String myText = "Hello";


5. 변수의 스코프와 라이프타임

public class MyStudyClass {
  int x = 0; // 인스턴스 변수
  static int result = 0; // 클래스 변수
  
  void method1() {
    int x=0; // 지역 변수
  }
}

인스턴스 변수
클래스 내부에 선언되었지만, 메소드 및 블록 외부에 선언된 변수
스코프: 정적 메소드를 제외한 클래스 전체
라이프타임: 클래스 객체가 메모리에 남아있는 동안

클래스 변수
클래스 내부, 모든 블록 외부에서 선언되고 static으로 선언된 변수
스코프: 클래스 전체
라이프타임: 프로그램이 끝날 때까지

지역 변수
인스턴스 또는 클래스 변수가 아닌 다른 모든 변수
스코프: 선언된 블록 내부 라이프타임: 컨트롤이 선언된 블록을 떠날 때까지


6. 타입 변환, 캐스팅 그리고 타입 프로모션

확대(widening) 캐스팅 (자동적으로) - 작은 타입을 큰 타입으로 변환
byte → short → char → int → long → float → double

public class Main {
  public static void main(String[] args) {
    int myInt = 9;
    double myDouble = myInt; // 자동 캐스팅

    System.out.println(myInt);      // 출력 9
    System.out.println(myDouble);   // 출력 9.0
  }
}

축소(narrowing) 캐스팅 (수동적으로) - 큰 타입을 작은 타입으로 변환
double → float → long → int → char → short → byte

public class Main {
  public static void main(String[] args) {
    double myDouble = 9.78;
    int myInt = (int) myDouble; // 수동 캐스팅

    System.out.println(myDouble);   // 출력 9.78
    System.out.println(myInt);      // 출력 9
  }
}

타입 프로모션은 자동으로 작은 범위의 타입을 큰 범위의 타입으로 승격(promotion)한 후 연산합니다.

class Test {			
  public static void main (String [] args) {
    int i = (int)12.5f;  // i 출력 12 (narrowing)
    float f = i; // f 출력 12.0 (widening)
    f = f * i; // i의 타입이 flot로 승격 후 folat*float로 연산
  }
}


7. 1차 및 2차 배열 선언하기

class ArrayDemo {
  public static void main(String[] args) {
    // integer 배열 선언
    int[] anArray;

    // 10개의 integer 배열 선언
    anArray = new int[10];
    
    // 이 양식은 관례상 권장하지 않습니다.
    float anArrayOfFloats [];
    
    // 2차원 배열 선언
    String[][] names = {
        {"Mr. ", "Mrs. ", "Ms. "},
        {"Smith", "Jones"}
    };
    // Mr. Smith
    System.out.println(names[0][0] + names[1][0]);
    // Ms. Jones
    System.out.println(names[0][2] + names[1][1]);
    }
}


8. 타입 추론, var

var a = 1;            // Legal
var b = 2, c = 3.0;   // Illegal: multiple declarators
var d[] = new int[4]; // Illegal: extra bracket pairs
var e;                // Illegal: no initializer
var f = { 6 };        // Illegal: array initializer
var g = (g = 7);      // Illegal: self reference in initializer

var a = 1;                // a has type 'int'
var b = java.util.List.of(1, 2);  // b has type List
var c = "x".getClass();   // c has type Class
var d = new Object() {};  // d has the type of the anonymous class
var e = (CharSequence & Comparable) "x";
                          // e has type CharSequence & Comparable
var f = () -> "hello";    // Illegal: lambda not in an assignment context
var g = null;             // Illegal: null type

왜 Java에 var가 있어야 하나요?

로컬 변수는 Java의 핵심 요소입니다. 로컬 변수를 사용해 메소드는 중간 값을 저렴하게 저장하여 중요한 결과를 계산합니다. 필드와 달리 로컬 변수는 동일한 블록에서 선언, 초기화하고 사용합니다. 로컬 변수의 이름과 초기화는 종종 타입보다 독자의 이해를 위해 더 중요합니다. 일반적으로 이름과 초기화는 타입만큼 많은 정보를 제공합니다.

Person person = new Person()

로컬 변수 선언에서 var의 역할은 이름과 초기화를 강조하도록 타입 자리를 대신하는 것입니다.

var person = new Person()

컴파일러는 초기화시 로컬 변수의 타입을 유추합니다.

이것은 특히 이럴때 가치가 있습니다.
타입이 와일드 카드로 매개 변수화 된 경우
또는 초기화에서 타입이 언급 된 경우.
(This is especially worthwhile if the type is parameterized with wildcards, or if the type is mentioned in the initializer.)
※모르는 부분이 많고 이해가 잘 안 돼서 다시 들여다봐야 할 부분

var를 사용하면 가독성을 떨어 뜨리지 않고 코드를 더 간결하게 만들 수 있으며 경우에 따라 중복성을 제거하여 가독성을 향상시킬 수 있습니다.

출처: http://openjdk.java.net/projects/amber/LVTIFAQ.html

댓글 없음:

댓글 쓰기