[Java] Java의 정석 | Chapter 02 변수(Variable)

숙취엔 꿀물.·2023년 11월 23일

Java

목록 보기
2/13
post-thumbnail

👉 1. 변수(Variable)

1.1 변수(variable)란?

  • 단 하나의 값을 저장할 수 있는 메모리 공간

1.2 변수의 선언과 초기화

ex) int age; // age 라는 이름의 변수를 선언
  • int : 변수타입 - 변수에 저장될 값이 어떤 '타입(type)'인지를 저장하는 것

  • age : 변수이름 - '값을 저장할 수 있는 메모리 공간'의 이름

  • 변수의 종류에 따라 변수의 초기화를 생략할 수 있는 경우도 있지만, 변수는 사용되기 전에 적절한 값으로 초기화 하는 것이 좋다.

  • 지역변수는 사용되기 전에 초기화를 반드시 해야 하지만 클래스변수와 인스턴스변수는 초기화를 생략할 수 있다.


1.3 변수의 명명규칙

  • 변수의 이름 처럼 프로그래밍에서 사용하는 모든 이름을 식별자(identifier)라고 하며, 식별자는 같은 영역 내에서 서로 구분(식별)될 수 있어야한다. 그리고 식별자를 만들 때는 다음과 같은 규칙을 지켜야 한다.
  1. 대소문자가 구분되며 길이에 제한이 없다.
    • True와 true는 서로 다른 것으로 간주된다.
  2. 예약어를 사용해서는 안 된다.
    • true는 예약어라서 사용할 수 없지만, True는 가능하다.
  3. 숫자로 시작해서는 안 된다.
    • top10은 허용하지만, 7up은 허용되지 않는다.
  4. 특수문자는 '_'와 '$'만을 허용한다.
    - $harp은 허용되지만, S#arp은 허용되지 않는다.

<이 외에 필수적인 것은 아니지만 자바 프로그래머들에게 권장하는 규칙>

  1. 클래스 이름의 첫 글자는 항상 대문자로 한다.

    • 변수와 메서드의 이름의 첫 글자는 항상 소문자로 한다.
  2. 여러 단어로 이루어진 이름은 단어의 첫 글자를 대문자로 한다.

    • lastIndexOf, StringBuffer
  3. `상수의 이름은 모두 대문자로 한다. 여러 단어로 이루어진 경우 '_'로 구분한다.

    • PI, MAX_NUMBER


👉 2. 변수의 타입

기본형과 참조형

  • 기본형 변수는 실제 값(data)을 저장하는 반면, 참조형 변수는 어떤 값이 저장되어 있는 주소(memory address)를 값으로 갖는다.

  • 참조형 변수(또는 참조변수)를 선언할 때는 변수의 타입으로 클래스의 이름을 사용하므로 클래스의 이름이 참조변수의 타입이 된다. 그래서 새로운 클래스를 작성한다는 것은 새로운 참조형을 추가하는 셈이다.

    	클래스이름 변수이름; // 변수의 타입이 기본형이 아닌 것들은 모두 참조변수이다.
    	ex) Date today = new Date(); // Date 객체를 생성해서, 그 주소를 today에 저장

2.1 기본형(primitive type)

분류자료형저장 가능한 값의 범위크기(bit, byte)
논리형booleanfalse, true8bit, 1byte
문자형char'\u0000' ~ '\uffff' (0~2^16-1, 0~65535)15bit, 2byte
정수형byte-128 ~ 127 (-2^7~2^7-1)8bit, 1byte
short-32,768 ~ 32,767 (-2^15~2^15-1)16bit, 2byte
int2,147,483,648 ~ 2,147,483,647 (-2^31~2^31-1, 약 ±20억)32bit, 4byte
long-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807(-2^63~2^63-1)64bit, 8byte
실수형float1.4E-45 ~ 3.4E38 (1.4x10^-45~3.4x10^38)32bit, 4byte
double4.9E-324 ~ 1.8E308 (4.9x10^-324~1.8x10^308)64bit, 8byte

2.2 상수와 리터럴(constant & literal)

  • 상수(constant)도 '값을 저장할 수 있는 공간'이지만, 변수와 달리 한 번 값을 저장하면 다른 값으로 변경할 수 없다. 선언 방법은 변수 선언시 타입 앞에 키워드 final을 붙여주기만 하면 된다.
final int MAX_SPEED = 10; // 상수 MAX_SPEED를 선언 & 초기화

final int MAX_SPEED; 		// 에러. 상수는 선언과 동시에 초기화해야함
final int MAX_VALUE = 100;  // OK. 선언과 동시에 초기화함
MAX_VALUE = 200;			// 에러. 상수의 값은 변경 불가
  • 상수가 필요한 이유 : 상수는 리터럴에 의미있는 이름을 붙여서 코드의 이해와 수정을 쉽게 만든다.
int year = 2014; // year는 변수, 2014는 리터럴
final int MAX_VALUE = 100; // MAX_VALUE는 상수, 100은 리터럴

  • 리터럴의 타입과 접미사
종류리터럴접미사
논리형false, true없음
정수형123, 0b0101, 077, 0xFF, 100Ll , L
실수형3.14, 3.0e8, 1.4f, 0x1.0p-1f , d
문자형'A', '1', '\n'없음
문자열"ABC", "123", "A", "true"없음
- long과 float의 리터럴에 접미사를 붙이는 것만 신경쓰면 된다.

2.3 형식화된 출력 - printf()

지시자설명
%b불리언(boolean) 형식으로 출력
%d10진(decimal) 정수의 형식으로 출력
%o8진(octal) 정수의 형식으로 출력
%x, %X16진(hexa-decimal) 정수의 형식으로 출력
%f부동 소수점(floating-point)의 형식으로 출력
%e, %E지수(exponent) 표현식의 형식으로 출력
%c문자(character)로 출력
%s문자열(string)로 출력
class Main {
	public static void main(String[] args) {
    	int a = 1;
        
    	System.out.printf("a = %d\n", a);
        // 등등 동일하게
    }
}

2.4 화면에서 입력받기 - Scanner

  • 화면으로부터 입력받는 방법들은 근본적으로 모두 같으므로 차이를 비교할 필요는 없다. 그러나 알고리즘 문제를 푸는 경우에는 Scanner, BufferedReader 등에 따라 속도 차이는 있다.
import java.util.Scanner;

public class ScannerEx {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.print("두 정수 입력 : ");
        String input = sc.nextLine();
        int num = Integer.parseInt(input);

        System.out.println("입력내용 : " + input);
        System.out.printf("num = %d\n", num);
    }
}


👉 3. 진법

3.1 10진법과 2진법

  • 대부분의 컴퓨터는 2진 체계로 설계되었기 때문에, 2진법을 알지 못하면 컴퓨터의 동작원리나 데이터 처리방식을 온전히 이해할 수 없다.

3.2 비트(bit)와 바이트(byte)

  • 한 자리의 2진수를 비트(bit, binary digit)라고 하며, 1 비트는 컴퓨터가 값을 저장할 수 있는 최소단위이다.

  • 너무 작으므로 1 비트 8개를 묶어서 바이트(byte)라는 단위로 정의해서 데이터의 기본 단위로 사용한다.

  • 그 외에도 워드(word)CPU가 한 번에 처리할 수 있는 데이터의 크기를 의미한다. 1워드는 32비트 CPU에서 32bit(4byte)이고, 64비트 CPU에서는 64bit(8byte)이다.



👉 4. 기본형(primitive type)

4.1 논리형 - boolean

  • 기본값(default)은 false
  • boolean형 변수는 대답(yes/no), 스위치(on/off) 등의 논리구현에 주로 사용된다.

4.2 문자형 - char

  • 단 하나의 문자만을 저장할 수 있다.
char ch = 'A';
  • 위의 문장은 변수에 '문자'가 저장되는 것 같지만, 사실은 문자가 아닌 '문자의 유니코드(정수)'가 저장된다. 문자 'A'의 유니코드는 65 이므로, 변수 ch에는 65가 저장된다. 따라서 아래의 두 문장은 동일한 결과
char ch = 'A'; // 문자 'A'를 char 타입의 변수 ch에 저장
char ch = 65; // 문자의 코드를 직접 변수 ch에 저장
  • char형 변수에 저장된 값을 정수형(int)으로 형변환(캐스팅, casting)하는 식으로 사용하여 다양하게 문제를 해결할 수 있다.
int code = (int)ch; // ch에 저장된 값을 int타입으로 변환하여 저장한다.

인코딩과 디코딩(encoding & decoding)

'A' <-> 65
  • 문자를 코드로 변환하는 것을 문자 인코딩(encoding), 그 반대로 코드를 문자로 변환하는 것을 문자 디코딩(decoding)이라고 한다.
  • 문자를 저장할 때는 인코딩을 해서 숫자로 변환해서 저장하고, 저장된 문자를 읽어올 때는 디코딩을 해서 숫자를 원래의 문자로 되돌려야 한다.

실제로, Dialogflow라는 자연어 처리 api를 사용하면서 이 과정이 필요했던 경험이 있었는데, 인코딩 코드를 짜느라 애를 먹은 기억이... 😢

아스키(ASCII)

  • ASCII는 'American Standard Code for Information Inrerchane'의 약어로 정보교환을 위한 미국 표준 코드라는 뜻이다.
  • 프로그래밍에서 유용하게 활용됨

유니코드(Unicode)

  • 전 세계의 모든 문자를 하나의 통일된 문자집합으로 표현하고자 노력하였고 그 결과가 바로 유니코드 이다.
  • 자세한 사항이 필요하다면, 직접 검색하는 것을 추천...

4.3 정수형 - byte, short, int, long

정수형의 선택기준

  • 기본적으로 정수형 변수를 선언할 때는 int타입으로 하고,

  • int의 범위(약 ±20억)를 넘어서는 수를 다뤄야할 때는 long을 사용하면 된다.

  • byte나 short는 성능보다 저장공간을 절약하는 것이 더 중요할 떄 사용

정수형의 오버플로우

  • 타입이 표현할 수 있는 값의 범위를 넘어서는 것을 오버플로우(overflow)라고 한다.

  • 오버플로우가 발생한다고 해서 에러가 발생하는 것은 아니고, 예상했던 결과를 얻지 못할 뿐이다.

  • 따라서, 값을 예상하고 그에 맞게 변수 타입 선언을 정확히 해야한다.


4.4 실수형 - flaot, double

실수형의 범위와 정밀도

  • 실수형은 소수점수도 표현해야 하므로 얼마나 큰 값을 표현할 수 있는가뿐만 아니라 얼마나 0에 가깝게 표현할 수 있는가도 중요하다.

  • double 타입의 변수를 사용하는 경우는 대부분 저장하려는 값의 범위 때문이 아니라 보다 높은 정밀도가 필요해서이다.

  • 하여 연산속도의 향상이나 메모리를 절약하려면 float를 선택하고, 더 큰 값의 범위라던가 더 높은 정밀도를 필요로 한다면 double을 선택해야 한다.



👉 5. 형변환

5.1 형변환(캐스팅, casting)이란?

형변환이란, 변수 또는 상수의 타입을 다른 타입으로 변환하는 것

  • 예를 들어, int 타입과 float 타입의 값을 더하는 경우, 두 값을 float타입으로 변환한 다음에 더해야 한다.

5.2 형변환 방법

  • 형변환하고자 하는 변수나 리터럴의 앞에 변환하고자 하는 타입을 괄호와 함께 붙여주기만 하면 된다.

    	(타입)피연산자
  • 여기에 사용되는 괄호()는 캐스트 연산자 또는 형변환 연산자라고 하며, 형변환을 캐스팅(casting)이라고도 한다.

double d = 85.4;
int score = (int)d; // double 타입의 변수 d를 int 타입으로 형변환
  • 형변환 연산자는 그저 피연산자의 값을 읽어서 지정된 타입으로 형변환하고 그 결과를 반환할 뿐이다. 그래서 피연산자인 변수 d의 값은 형변환 후에도 아무런 변화가 없다.

기본형간의 형변환

변환수식결과
int -> char(char) 65'A'
char -> int(int) 'A'65
float -> int(int) 1.6f1
int -> float(float) 1010.0f

5.3 정수형간의 형변환

  • 작은 타입에서 큰 타입으로 변환은 값 손실이 발생하지 않으나 큰 타입에서 작은 타입으로 변환은 값에 따라 값 손실이 발생할 수 있다.

5.4 실수형 간의 형변환

  • 정수형과 마찬가지로 작은 타입에서 큰 타입으로 변환하는 경우, 빈 공간을 0으로 채운다.

  • 반대로 double타입에서 float타입으로 변환하는 경우, 지수(E)와 가수(M)가 버려지고 반올림이 발생할 수 있다.


5.5 정수형과 실수형 간의 형변환

정수형을 실수형으로 변환

  • 정수는 소수점이하의 값이 없으므로 변환이 간단하다. 그저 정수를 2진수로 변환한 다음 정규화를 거쳐 실수의 저장형식으로 저장될 뿐이다.

실수형을 정수형으로 변환

  • 실수형을 정수형으로 변환하면, 실수형의 소수점이하 값은 버려진다. 정수형의 표현형식으로 소수점 이하의 값은 표현할 수 없기 때문이다.
    ex) 1.666 (int)-> 1

5.6 자동 형변환

  • 서로 다른 타입간의 대입이나 연산을 할 때, 경우에 따라 편의상의 이유로 형변환을 생략할 수 있다. 그렇다고 형변환이 이루어지지 않는 것은 아니고, 컴파일러가 생략된 형변환을 자동적으로 추가한다.
    float f = 1234; // 형변환의 생략. float f = (float)1234;와 같음
    byte b = 1000; // 에러. byte의 범위(-128~127)를 넘는 값을 저장.
    char ch = (char)1000; // 명시적 형변환. 에러가 발생하지 않는다.
    int i = 3;
    double d = 1.0 + i; // double d = 1.0 + (double)i; 에서 형변환이 생략됨

자동 형변환의 규칙

기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환한다.


👉 참고

저는 그냥 책만 보고 공부하긴 하지만 필요한 사람이 있을까봐 남깁니다.

profile
단단하게 오래가고자 하는 백엔드 개발자

0개의 댓글