관리 메뉴

개발그래머

[자바스터디 2주차] 자바 데이터 타입, 변수 그리고 배열 본문

Java

[자바스터디 2주차] 자바 데이터 타입, 변수 그리고 배열

임요환 2023. 5. 6. 22:06

목표

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

학습할 것

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

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

  • primitive type은 자바의 기본 타입들이며 8개가 존재함
  • 프리미티브 타입은 필드 선언 시 초기화하지 않으면 기본 값으로 초기화됨
종류 타입 메모리 byte 범위 기본 값
논리형 boolean 1byte true or false false
정수형 byte 1byte -128 to 127 0
char 2byte '\u0000'(0) to '\uffff'(65535) '\u0000'
short 2byte -32,768 to 32,767 0
int(기본) 4byte -2^31 to 2^31-1 0
long 8byte -2^63 to 2^63-1 0L
실수형 float 4byte (6~7자리 정밀도) 0.0f
double(기본) 8byte (15자리 정밀도) 0.0d

Java8 부터 unsigned int, unsigned long이 추가됨

int unsigned = Integer.parseUnsignedInt("2200000000");
System.out.println(Integer.toUnsignedString(unsigned));

BigInteger bigInteger = BigInteger.valueof(2200000000L);
  • Java는 유니코드를 지원함 -> 한자 등의 모든 언어 입력 가능

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

Java Data Type
ㄴ Primitive Type
    ㄴ Boolean Type(boolean)
    ㄴ Numeric Type
        ㄴ Integral Type
            ㄴ Integer Type(short, int, long)
            ㄴ Floating Point Type(float, double)
        ㄴ Character Type(char)
ㄴ Reference Type
    ㄴ Annotation
    ㄴ Array
    ㄴ String
    ㄴ Class
    ㄴ Enumeration
    ㄴ Interface
primitive type reference type
boolean, char, byte, short, int등 이미 정해진 유형 사용자가 무제한적으로 유형을 선언
값 저장 주소 저장
call by value call by reference
메모리에 저장되는 값이 실제값 저장되는 값은 메모리의 주소
동일한 유형의 다른 변수에 값이 복사됨 다른 참조 유형에 할당되면 동일한 객체를 가르킴
메모리에서 변수의 값을 복사해서 사용하기 때문에 변수의 값을 바꾸더라도 메모리에 있는 값이 바뀌지 않음 메모리 주소를 복사해서 사용하므로 가져온 변수의 값을 바꾼다면 메모리 주소를 참조하여 사용했기 때문에 값이 바뀜
null 할당 불가 null 할당 가능
Stack에 저장 Heap 메모리 영역에 값을 저장하고 Stack에 Heap의 주소값을 저장함
new 키워드를 통해 생성된 객체의 주소를 참조함(배열, class, 열거형(enum), interface 등

리터럴

  • 리터럴 = 데이터 값 그 자체
int num = 15; // 15가 리터럴임

정수형 리터럴 표현 방식

int num = 11; //10진수 int형
int num = 011; //8진수 int형
int num = 0x11; //16진수 int형
long num = 11L; //long 형
int num = 0B11001101; //2진수 int형
int num = 1_000_000; // 큰 수의 표현은 가독성을 위해 _로 구분 가능

실수형 리터럴 표현 방식

double num = 3.1415 or 3.1415d or 3.1415D; //double형  
float num = 3.14f or 3.14F; //float형  
//추가 표현
3.4e3 == 3.4 X 10^3  
3.4e-3 == 3.4 X 10^-3  
0.5 == .5

실수형 리터럴 추가 사항

float number = 0f;  
for(int i = 0; i < 10; i++) {  
    number += 0.1f;  
}  
System.out.println(number); // 1.0000001

// 부동소수점은 정확하지 않다  
// 돈계산하는 애플리케이션을 만들 때 절대 float, double을 사용하면 안되고 BigDecimal, BigInteger를 사용해야함  
BigDecimal number = BigDecimal.ZERO;  
for(int i = 0; i < 10; i++) {  
    number = number.add(BigDecimal.valueOf(0.1)); // 멀티쓰레드 상황을 고려해야함  
}  
System.out.println(number); // 1.0

부울형 상수

boolean trueOrFalse = true or false; // boolean형, 오직 true와 false값만 가짐

문자형 상수

char ch = '한'; // char형  
char ch = 'A'; // 작은 따옴표로 구분  
char ch = '\u20AC'; // 유니코드 입력 가능  
char ch = '\b'; // 백스페이스 문자  
char ch = '\t'; // 탭 문자  
char ch = '\'; // 백 슬래시 문자  
char ch = '\''; // 작은 따옴표 문자  
char ch = '\"'; // 큰 따옴표 문자  
char ch = '\n'; // 개행 문자  
char ch = '\r'; // 캐리지 리턴 문자

String 리터럴

String str = "string"; // String형, 큰 따옴표로 표현

String 초기화 방법

String str1 = new String("abc"); 
String str2 = new String("abc"); 
System.out.println(str1 == str2); // false 
System.out.println(str1.equals(str2)); // true
  1. new를 사용
  • str1과 str2는 힙 영역에 각각의 다른 객체로 만들어짐
  • 서로 다른 메모리 주소를 가지고 있기 때문에 같지 않음(동일성)
  • 하지만 서로의 값은 같음(동등성)
String str1 = "abc"; 
String str2 = "abc"; 
System.out.println(str1 == str2); // true
  1. 리터럴로 초기화
  • 리터럴 "abc"가 상수풀 영역에 등록됨
  • str1과 str2는 상수풀에 있는 같은 "abc"를 참조함 -> str1과 str2는 같은 메모리 주소를 가짐

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

변수 선언

int a; // 타입과 변수 이름을 통해 선언 가능 
int a, b, c; // 여러개의 변수를 선언 가능

자바 변수 naming convention

convention example
첫 번째 글자는 문자이거나 특수문자 $ 또는 _ 만 가능하고 숫자로 시작할 수 없음 price, $price, _price = 가능, 1price, @price, $#price = 불가능
대소문자가 구분됨 myName != myname
첫 문자는 영어 소문자로 시작하고 다른 단어가 붙을경우 첫 문자를 대문자로 함 myName, yourName
문자 수(길이)의 제한이 없음
예약어를 사용할 수 없음

변수 초기화

class Variables {
    int instanceVar; // 0으로 초기화되는 인스턴스 변수
    static int classVar; // 0으로 초기화되는 클래스 변수
    int initInstanceVar = 10; // 명시적으로 초기화
    static int initClassVar = 10; // 명시적으로 초기화

    void method(int num) { // 매개변수는 초기화 할 수 없고, 전달받는 값을 사용만 할 수 있음
      int a; // 선언은 가능
      // int b = a; 자동으로 초기화 되지 않으므로 동작하지 않음
      a = 10; // 선언을 미리 해줬다면 이렇게 초기화 가능
      int b = a; // 선언과 동시에 초기화
    }
}

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

  • 스코프 = 변수가 유효한 범위를 의미함
Variable Type Scope Lifetime
Instance Variable (static 블록과 static 메서드를 제외한) 클래스 전체 객체가 생성되고 객체가 메모리에 살아있는 동안
Class Variable 클래스 전체 클래스가 초기화되고 프로그램이 끝날 때 까지
Local Variable 변수가 선언된 블록내부 변수 선언 이후 부터 블록을 벗어날 때까지
public class Test {
    int var1; // 인스턴스 변수, 필드, 전역 변수
    static int var2; // 클래스 변수, 정적 변수

    void doTest(int var3){ // 매개변수, 파라미터
        int var4 = 100; // 지역 변수, 로컬 변수
    }
}
public class App {  
    private static int number = 100;

    private int helloNumber() {  
        return App.number; //참조가능  
    }  
}

public class App {  
    private static int number = helloNumber(); //참조불가능 : helloNumber() 메서드는 App의 인스턴스가 생성되었을 때 사용가능하다. 하지만 number 변수는 클래스가 메모리에 로드되는 시점에 선언되어야 하므로 컴파일 에러가 발생함  

    private int helloNumber() {  
        return 100;  
    }  
}
  • 변수들이 로딩되는 시점이 다르다는 것을 인지하여야 함

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

  • 타입 변환
    • 데이터 타입을 다른 데이터 타입으로 변환하는 것
    • 강제(명시적) 타입 변환(캐스팅), 자동(묵시적) 타입 변환(프로모션)
  • 캐스팅(casting)
    • 강제 타입 변환
    • 강제적으로 큰 데이터 타입을 작은 데이터 타입으로 저장하는 것(Narrow Conversion)
    • 값이 변경 될 수 있음
    • 축소
  • 프로모션
    • 자동 타입 변환
    • 원래 타입에서 더 큰 타입으로 변경(Widening Conversion)
    • 확장
int var1 = 1234567;
byte var2 = (byte) var1; // 캐스팅

double var3 = 3.14;
int var4 = (int) var3; // var4 = 3; 값이 변경됨, 캐스팅

int var5 = 10;
long var6 = var5; // 프로모션

1차 및 2차 배열 선언하기

1차원 배열

  • 1차원 배열 선언
int[] intArr; // 주로사용
int []intArr; // 권장하지 않음
int intArr[]; // 권장하지 않음
  • 1차원 배열 초기화
int[] intArr = new int[100];
intArr[0] = 1;
System.out.println(intArr1[0]); // 1
System.out.println(intArr1[1]); // 0, 초기화 하지 않은 값은 기본 값으로 초기화됨
  • 해당 크기만큼 배열의 요소가 초기화되어 생성됨
  • 배열의 각 요소는 인덱스로 접근 가능
  • 다른 초기화 방법
int[] intArr = {
    100, 200, 300,
    400, 500, 600,
    700, 800, 900
};

int[] intArr = new int[] {100, 200, 300};
  • 배열의 길이는 중괄호 사이에 선언된 요소의 수
  • new로 생성되었으며 Java의 배열은 객체임 -> 힙 영역에 배열이 생성됨

2차원 배열

  • 2차원 배열 선언
int[][] intArr; // 선언
intArr = new int[3][3]; // 메모리 할당, 초기화
  • 다차원 배열 = 요소 자체가 배열인 배열
  • 각 요소 배열간 길이는 다를 수 있음
int[][] intArr = new int[3][]; // 첫번째 차원은 지정해야하며 지정하지않을시 컴파일 에러 발생

intArr[0] = new int[1];
intArr[1] = new int[2];
intArr[2] = new int[3];
[0]
[0, 0]
[0, 0, 0]
  • 2차원 배열 초기화
int[][] arr = {
    {1, 2, 3},
    {4, 3, 6},
    {7, 8, 9}
};

String[][] names = {
    { "Lim", "Kim", "Lee" }, // 다른 길이로도 가능
    { "Yohwan", "Younghee" }
};

String[][] names2 = new String[10][];// 요소의 길이를 초기화시 지정하지 않으면 null로 초기화
String[][] names3 = new String[10][10];// 지정 시 같은 크기로 배열 초기화
  • 이차원 배열도 요소의 인덱스로 접근
System.out.println(names[0][0] + names[1][0]); // LimYohwan
System.out.println(naems[0][2] + names[1][1]); // LeeYounghee
  • 배열의 크기는 length 속성으로 알 수 있으며 한 번 초기화하고 나면 크기를 변경할 수 없음

타입 추론, var

타입 추론이란 정적 타이핑을 지원하는 언어에서 타입이 정해지지 않은 변수에 대하여 컴파일러가 변수의 타입을 스스로 찾아낼 수 있도록 하는 기능  
= 타입을 명시하지 않아도 되어 코드량을 줄이고 가독성을 높일 수 있음
  • Java10 부터 var가 생겼고 Java11부터 람다 타입 지원도 생김
  • 컴파일러는 초기화 값을 통해 타입을 유추하므로 반드시 데이터를 초기화해야 함
public void test(){  
    var message = "Java10"; // 선언과 동시에 반드시 초기화  
    System.out.println(message instanceof String); // true  
}

var의 활용

  1. forEach문
for(String name : nameList){  
    System.out.println(name);  
}

for(var name : nameList){  
    System.out.println(name);  
}
  • 이미 List에 선언된 타입으로 var가 타입 추론을 하여 따로 String을 선언해 주지 않아도 되며 코드가 간결해지고 Object 타입으로 미리 단정 지을 필요도 없어짐
  1. 람다(Java11)
  • 람다 인자에도 var를 사용할 수 있음
  • 일반 람다의 경우 파라미터 어노테이션을 선언하지 못하여 선언하고 싶을시 따로 메서드를 생성하던가, 익명클래스로 생성했어야 함
  • Java11부터 람다에서 타입 추론의 유연성을 추가함
Consumer personConsumer = (@Nonnull var person) -> {} // @Nonnull에 의해 person값의 nullcheck부터하게됨
  1. 익명 클래스
var intVal = 20;  
var strVal = "string";  
var list = new ArrayList();
  • 심플한 var 사용은 가독성이 좋지 않아 지양해야 함
var supply = new Supplier(){  
    @Override  
    public String get(){  
        //logic  
    }  
}

var supply = () -> {}; //람다식은 컴파일 오류
  • 익명 클래스는 정의가 거대하고 유지하기 쉬우며 선언한 다음에 변수가 바뀌는 일이 없으므로 사용하기 좋음