[Java의 정석] 2. 변수

0woogie·2022년 9월 11일
0

1. 변수

1.1 변수(variable)란?

"변수란, 단 하나의 값을 저장할 수 있는 메모리 공간."

1.2 변수의 선언과 초기화

변수를 사용하려면 먼저 변수 선언이 필요하다.

int age; //age라는 이름의 변수를 선언

코드에서의 int는 변수타입, age는 변수이름이다.

  • 변수타입: 변수에 저장될 값이 어떤 '타입(type)'인지를 지정하는 것
  • 변수이름: 메모리 공간에 이름을 붙여주는 것, 이름을 이용해서 저장공간에 값을 저장하고, 저장된 값을 읽어오기도 할 수 있음

변수를 선언하면, 메모리의 빈 공간에 '변수타입'에 알맞은 크기의 저장공간이 확보되고, 앞으로 이 저장공간은 '변수이름'을 통해 사용할 수 있게 된다.

메모리에 쓰레기 값이 남아있을 수 있기 때문에 변수를 선언하고 나서는 '초기화'해야 한다.

"변수의 초기화란, 변수를 사용하기 전에 처음으로 값을 저장하는 것"

int age = 25; //변수 age를 선언하고 25로 초기화

위의 코드의 경우, 변수의 선언과 동시에 초기화가 이루어졌다.
변수의 종류에 따라 변수의 초기화를 생략할 수 있는 경우도 있지만, 변수는 사용되기 전에 적절한 값으로 초기화 하는 것이 좋다.
(지역변수는 사용되기 전에 초기화를 반드시 해야 하지만, 클래스변수와 인스턴스변수는 초기화 생략 가능함. 자세한 내용은 6장에서)

1.3 변수의 명명규칙

프로그래밍에서 사용하는 모든 이름을 '식별자(identifier)'라고 하며, 식별자는 같은 영역 내에서 서로 구분될 수 있어야 한다. 식별자를 만들 때는 다음의 규칙을 지켜야 한다.

  • 대소문자가 구분되며 길이에 제한이 없다.
  • 예약어를 사용해서는 안 된다.
  • 숫자로 시작해서는 안 된다.
  • 특수문자는 '_'와 '$'만을 허용한다.

위의 규칙의 경우 틀리면 에러가 발생하기 때문에 크게 문제가 되는 부분이 아니다. 오히려 주의하고 신경써야 하는 부분은 이제부터 언급될 'Code Convention'에 대한 내용이다.

  1. 목적에 맞는 이름을 붙이는 것이 좋다.
    예를 들어 변수 이름이 sum이라고 하면 합을 저장하는 변수라는 것을 금방 알지만, s라고 하면 어떤 용도로 쓰이는 변수인지 알기 어렵다.
  2. 이름의 길이에 연연하지 말고 충분히 긴 이름으로 붙이는 것이 좋다.
    자판기 클래스의 이름은 AVM보다 AutoVendingMachine이 더 좋다.
  3. 이름을 붙이는 관습을 따르는 것이 좋다.
    • 클래스 이름
      클래스 이름의 첫 번째 문자는 대문자로 시작, 여러 단어 복합되면 각 단어의 첫 번째 문자만 대문자로 표시
    public class HelloWorld {}
    class AutoVendingMachine {}
    • 변수, 메소드 이름
      변수와 메소드 이름은 첫 단어는 소문자로 표기하고 이후 각 단어의 첫 번째 문자만 대문자로 표기
    int myAge;
    boolean isSingle;
    public int getAge() {return 20;}
    • 상수 이름
      상수는 이름 전체를 대문자로 표기, 여러 단어로 이루어진 경우 '_'로 구분
    final double PI = 3.141592;
    final int MAX_NUMBER = 100;
    • 또한 클래스와 변수는 명사여야 하고, 메소드의 경우 동사로 시작하는 것이 일반적이다. (물론 필요에 따라 예외적인 경우도 있음)

이처럼 Code Convention을 준수한다면 readablity가 높아져 코드 리팩토링에도 큰 도움을 줄 수 있다.

2. 변수의 타입

2.0 기본형과 참조형

  • 기본형(primitive type)
    - 논리형(boolean), 문자형(char), 정수형(byte,short,int,long), 실수형(float,double)
    - 실제 값(data)을 저장, 총 8개
  • 참조형(reference type)
    - 객체의 주소를 저장, 8개의 기본형을 제외한 나머지 타입

참조형 변수를 선언할 때는 변수의 타입으로 클래스의 이름을 사용하므로 선언은 클래스이름 변수이름;의 형식을 따른다. 아래의 구체적인 코드를 보자.

Date today = new Date(); //Date 객체를 생성해서, 그 주소를 today에 저장

객체를 생성하는 연산자 new의 결과는 생성된 객체의 주소이다. 이 주소가 참조형 변수 today에 저장된 것으로, 이제 today를 통해서 생성된 객체를 사용할 수 있게 된다.

2.1 기본형(primitive type)

기본형에는 모두 8개의 자료형이 있으며, 크게 논리형, 문자형, 정수형, 실수형으로 구분된다.

  • 논리형(boolean)
    다른 기본형과의 연산이 불가능, boolean을 제외한 나머지 7개의 기본형은 서로 연산과 변환이 가능
  • 문자형(char)
    문자를 내부적으로 정수(유니코드)로 저장하기 때문에 정수형과 별반 다르지 않음, 정수형 또는 실수형과 연산도 가능
  • 정수형(byte, short, int, long)
    일반적으로 int를 많이 사용, 효율적인 실행보다 메모리를 절약하려면 byte나 short
  • 실수형(float, double)
    저장 가능한 값의 범위뿐만 아니라 정밀도도 중요, 주로 double을 많이 사용

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

변수(variable): 하나의 값을 저장하기 위한 공간
상수(constant): 값을 한번만 저장할 수 있는 공간, 키워드 'final' 붙임
리터럴(literal): 그 자체로 값을 의미하는 것

JDK1.6부터 상수를 선언과 동시에 초기화 하지 않아도 되며, 사용하기 전에만 초기화하면 되도록 바뀜. 그래도 상수는 선언과 동시에 초기화하는 습관을 들이자.

int year = 2014; //변수(year), 리터럴(2014)
final int MAX_VALUE = 100; //상수(MAX_VALUE), 리터럴(100)

리터럴의 타입과 접미사

변수에 타입이 있는 것처럼 리터럴에도 타입이 있다. 논리형과 문자형의 경우 접미사는 없다.

  • 정수형
    - long타입의 리터럴은 접미사 'l' 또는 'L'을 붙인다.
    - int타입의 리터럴은 접미사를 생략한다.
    - byte와 short타입의 리터럴은 별도로 존재하지 않으며, byte와 short타입의 변수에 값을 저장할 때는 int타입의 리터럴을 사용한다. (단, 해당 타입의 변수가 저장할 수 있는 범위에 속해야!)
  • 실수형
    - float타입의 리터럴은 접미사 'f' 또는 'F'를 붙인다.
    - double타입의 리터럴은 접미사 'd' 또는 'D'를 붙이며 생략 가능하다.
float pi = 3.14; //에러. float타입 변수에 double타입 리터럴 저장불가
double rate = 1.618; //OK. 접미사 d는 생략할 수 있다.

리터럴에 접미사가 붙는 타입은 long, float, double뿐인데, double은 생략가능하므로 long과 float의 리터럴에 접미사를 붙이는 것만 신경쓰면 된다.

타입의 불일치

리터럴의 타입은 저장될 변수의 타입과 일치하는 것이 보통이지만, 타입이 달라도 저장범위가 넓은 타입에 좁은 타입의 값을 저장하는 것은 허용된다.

int i = 'A'; //OK. 문자 'A'의 유니코드인 65가 변수 i에 저장된다.
long l = 123; //OK. int보다 long타입이 더 범위가 넓다.
double d = 3.14f; //OK. float보다 double타입이 더 범위가 넓다.

그러나 리터럴의 값이 변수 타입의 범위를 넘어서거나, 리터럴의 타입이 변수의 타입보다 저장범위가 넓으면 컴파일 에러가 발생한다.

int i = 0x123456789; //에러. int타입의 범위를 넘는 값을 저장
float f = 3.14; //에러. float타입보다 double 타입의 범위가 넓다.

값의 크기에 상관없이 double타입의 리터럴을 float타입의 변수에 저장할 수 없다는 것만 주의하자. (보다 자세한 내용은 '형변환' 파트에서,,)

문자 리터럴과 문자열 리터럴

작은따옴표로 문자 하나를 감싼 것을 '문자 리터럴', 큰 따옴표로 두 문자 이상을 감싼 것을 '문자열 리터럴'이라고 한다. char타입의 변수는 단 하나의 문자만 저장할 수 있으므로 문자열을 저장하기 위해서는 String타입을 사용해야 한다.

문자열 + any type -> 문자열 + 문자열 -> 문자열

덧셈 연산자(+)는 피연산자가 모두 숫자일 때는 두 수를 더하지만, 피연산자 중 어느 한 쪽이 String이면 나머지 한 쪽을 먼저 String으로 변환한 다음 두 String을 결합한다. (7+"7"의 경우 "77"의 결과를 얻음)

2.3 형식화된 출력 - printf()

printf()는 '지시자(specifier)'를 통해 변수의 값을 여러 가지 형식으로 변환하여 출력하는 기능을 가지고 있다. '지시자'는 값을 어떻게 출력할 것인지 지정해주는 역할을 한다.

  • printf()의 지시자 중에서 자주 사용되는 것들
    - %b: 불리언(boolean) 형식으로 출력
    - %d: 10진(decimal) 정수의 형식으로 출력
    - %o: 8진(octal) 정수의 형식으로 출력
    - %x, %X: 16진(hexa-decimal) 정수의 형식으로 출력
    - %f: 부동 소수점(floating-point)의 형식으로 출력
    - %e, %E: 지수(exponent) 표현식의 형식으로 출력
    - %c: 문자(character)로 출력
    - %s: 문자열(string)로 출력

2.4 화면에서 입력받기 - Scanner

Scanner 클래스를 사용하려면 import java.util.*;가 필요하다. 그 다음엔 Scanner 클래스의 객체를 생성한 뒤 nextLine() 메서드를 이용하여 문자열을 입력받는다.

Scanner scanner = new Scanner(System.in); //Scanner 클래스의 객체 생성
String input = scanner.nextLine(); //입력받은 내용을 input에 저장
int num = Integer.parseInt(input); //입력받은 내용을 int타입 값으로 변환

사실 Scanner 클래스에는 nextInt()나 nextFloat()와 같이 따로 변환할 필요없이 숫자로 바로 입력받을 수 있는 메서드들이 있지만, 이 메서드들은 화면에서 연속적으로 값을 입력받아서 사용하기에 까다롭다. 차라리 모든 값을 nextLine()으로 입력받아서 적절히 변환하는 것이 나을 수 있다. (상황에 따라 적절한 메서드 호출하기)

3. 진법

profile
정리하고 다듬기 위한 공간

0개의 댓글