will come true

[Java] 변수, 상수, 자료형, printf() 본문

Java

[Java] 변수, 상수, 자료형, printf()

haehyun 2023. 4. 28. 18:40

변수 (variable)

단 하나의 값을 저장할 수 있는 메모리 공간
하나의 변수에 단 하나의 값만 저장할 수 있으므로, 새로운 값을 저장하면 기존의 값은 사라진다.

변수가 '값을 저장할 수 있는 메모리 공간'이라는 하드웨어적 의미이면, 변수명은 이 메모리 공간에 이름을 붙여주는 것이다. 변수는 결국 값을 저장하고 그 값을 다시 읽어들여 사용하기 위한 것. 일정 메모리 공간을 할당한 후 다시 이 공간에 접근하기 위해서는 식별자가 필요하다.

 

변수의 초기화

변수의 초기화란, 변수를 사용하기 전에 처음으로 값을 저장하는 것이다.
메모리는 여러 프로그램이 공유하는 자원이므로 전에 다른 프로그램에 의해 저장된 쓰레기값이 남아있을 수 있기 때문에 초기화 과정은 필수이다.

타입의 같은 경우 콤파 ','를 구분자로 여러 변수를 한 줄에 선언할 수도 있다.

int a;
int b;
int x = 0;
int y = 0;
int a, b;
int x = 0, y = 0;
int year = 0;
int age = 0;
        
year = age + 2000;	// age 변수를 이용해 year 변수 값 갱신
age = age + 1;		// age 변수 자기자신을 이용해 값 갱신
        
System.out.printf("year : %d, age : %d", year, age);

지역변수는 사용되지 전에 초기화를 반드시 해야 하지만 클래스변수와 인스턴스변수는 초기화를 생략할 수 있다.
★ 선언 위치에 따른 변수의 종류

 

두 변수의 값 교환하기 (Swap)

int x = 10, y = 20;
int tmp = 0; // x의 값을 임시로 저장할 변수를 선언

tmp = x;
x = y;
y = tmp;

System.out.println("x:" + x + "y:" + y);

덧셈연산자(+)는 두 값을 더하기도 하지만, 문자열과 숫자를 하나의 문자열로 결합하기도 한다.
문자열 결합

 

변수 명명규칙

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

예약어 : 키워드(keyword), 리져브드 워드(reserved word). 프로그래밍 언어의 구문에 사용되는 단어.
예) boolean, byte, case, try, abstract, break, char, class, final, public, true, false 등

권장사항

  1. 클래스 이름의 첫 글자는 항상 대문자로 한다. (MainClass)
  2. 변수와 메서드 이름의 첫 글자는 항상 소문자로 한다. (count, move())
  3. 여러 단어로 이루어진 이름은 단어의 첫글자를 대문자로 한다. (lastIndexOf(), StringBuffer)
  4. 상수의 이름은 모두 대문자로 한다. 여러 단어로 이루어진 경우 '_'로 구분한다. (PI, MAX_NUMBER)
  5. 변수의 이름은 짧을수록 좋디만, 약간 길더라도 용도를 알기 쉽게 '의미있는 이름'으로 하는 것이 바람직하다.
int curPos = 0;		// 현재 위치(current position)
int lastPos = -1;	// 마지막 위치(last position)

 

자료형

값(data)의 종류(type)에 따라 값이 저장될 공간의 크기와 저장형식을 정의한 것.
변수를 선언할 때는 저장하려는 값의 특성을 고려하여 가장 알맞은 자료형을 변수의 타입으로 선택하면 된다.

문자형(char), 정수형(byte, short, int, long), 실수형(float, double)

예) 계산 프로그램에서 결과값을 저장하는 변수를 선언할 경우, 저장(표현) 가능한 값의 범위가 작은 int대신 같은 정수형 타입에 더 큰 범위의 값을 저장할 수 있는 long타입으로 선언한다. 소수점 단위 값까지 저장해야할 경우 double형을 이용한다.

기본형과 참조형

  • 기본형(primitive type) = 기본 자료형
    계산을 위한 실제 값(data)을 저장한다.
    논리형(boolean), 문자형(char), 정수형(byte, short, int, long), 실수형(float, double)
    저장할 값의 종류(data type)에 따라 구분된다.
byte b = 1;
short s = 2;
char c = 'A';

boolean isTrue = true;

int finger = 10;
long big = 100_000_000_000L;		// L : long
long hex = 0xFFFF_FFFF_FFFF_FFFFL;	

int octNum = 010;		// 0 : 8진수 octal
int hexNum = 0x10;		// 0x : 16진수 hexadecimal
int binNum = 0b10;		// 0b : 2진수 binary

 

  • 참조형(reference type) = 사용자 정의 타입
    객체의 주소(memory address)를 저장한다.
    참조형 변수명을 호출하면 객체의 주소, 즉 객체가 저장된 메모리 주소(일련번호)가 읽어들여지기 때문에 참조 타입끼리는 연산이 불가하다. 해당 변수가 참조하고 있는 객체에 접근해 속성 값을 읽어들여야 한다.
    기본형을 제외한 나머지 타입. 선언할 때 변수의 타입으로 클래스명을 사용한다.
    객체의 종류(type)에 의해 구분된다.

    ★ 메모리에는 1byte(8bit) 단위로 일련번호가 붙어있는데, 이 번호를 메모리 주소 또는 주소라고 한다.

    참조형은 null 또는 객체의 주소를 값으로 가지며 new키워드로 객체를 생성함과 동시에 주소를 저장하면서 초기화된다. 연산자 new의 결과는 생성된 객체의 주소이다.
Date date = new Date();

 

기본형

분류 타입
논리형 boolean
false / true, 조건식과 논리적 계산에 사용
문자형 char
문자 1개 저장
정수형 byte, short, int, long
정수 저장. 기본 자료형은 int
실수형 float, double
실수 저장. 기본 자료형은 double
  • char은 내부적으로 정수(유니코드)로 저장하기 때문에 정수형 또는 실수형과 연산이 가능하다.
  • boolean을 제외한 7개 자료형들은 서로 연산과 변환이 가능하다.
  • int는 CPU가 가장 효율적으로 처리할 수 있는 타입이기 때문에 주로 정수형은 주로 int를 사용한다. 효율적인 실해옵다 메모리를 절약하려면 값의 범위에 맞게 byte나 short를 선택할 수 있으나 개인 실습에서는 이렇게까지 메모리를 신경쓸 필요는 없다.

 

데이터의 표현 범위

1bit는 0 또는 1로 표현되는 한자리 값입니다. 즉, 2^1 = 2가지 값을 표현할 수 있다.
마찬가지로 1byte(=8bit)는 2진수로 00000000~11111111 사이의 값을 가지며 최대 2^8=256 가지 값을 표현한다.

종류 \ 크기 1byte 2byte 3byte 4byte
논리형 boolean      
문자형   char    
정수형 byte short int long
실수형     float double
  • boolean은 true / false 두 가지만 표현할 수 있으면 되므로 가장 작은 크기인 1byte.
  • char은 자바에서 유니코드(2byte 문자체계)를 사용.
  • char은 정수도 저장할 수 있지만 문자 하나를 담는 용도의 글자타입 변수로 취급된다.
    문자형 char변수에 같은 크기의 정수형 short변수 값을 대입하려 하면 Error. char타입으로 형변환해서 대입해야 한다.
  • byte는 크기가 1byte라서 byte.
  • int를 기준으로 짧아서 short, 길어서 long.
  • float은 실수값을 부동소수점(floating-point) 방식으로 저장
  • float의 두 배 크기라서 double
  • 정수형이 저장 가능한 값의 번위는 비트 수 n에 따라 '-2^(n-1) ~ 2^(n-1)-1'
    • int형의 경우 32bit(4byte) 이므로 '-2^31 ~ 2^31-1'의 범위를 갖는다.
    • 제곱식 Tip : 2^10 = 1024 ≒ 10^3
      2^31 = 2^10 x 2^10 x 2^10 x 2 = 1024 x 1024 x 1024 x 2 = 2 x 10^3 = 약 6000
    • 따라서 int타입의 변수는 대략 10자리 수 (약 20억 : 2,000,000,000)의 값을 저장할 수 있다.
      연산 중에 저장범위를 넘어서게 되면 값 손실이 일어나기 때문에 10자리 수보다 큰 값을 저장해야한다면 변수를 long타입으로 선언해야 한다. 보통 7~9자리 수를 계산할 때도 넉넉하게 long을 사용한다.
  • 실수형은 정수형과 저장방식이달라서 같은 크기라도 훨씬 큰 값을 표현할 수 있으나 오차가 발생할 수 있다.
    실수형의 정밀도(precision)이 높을수록 오차 범위가 줄어들며 double의 정밀도가 float보다 높다.
    • 실수형은 약 ±10^38 같이 큰 값을 저장할 수 있으나 정밀도는 7로, 10진수 7자리의 수까지만 오차없이 저장할 수 있다. 보다 높은 정밀도가 필요한 경우(은행과 같이 돈을 다루는 기관)에는 정밀도가 15인 double을 쓰는 게 좋다.
      = 실수형 타입 선택 기준 : 저장 가능한 값의 범위, 정밀도

 ★ TODO : 유니코드와 UTF-8

 

상수 (constant)

변수와 마찬가지로 값을 저장할 수 있는 공간이지만, 변수와 달리 한 번 값을 저장하면 다른 값으로 변경할 수 없다.
변수 타입 앞에 'final' 키워드를 붙여서 선언한다.
상수 값을 사용하기 전에만 초기화하면 되지만 되도록 상수 선언과 동시에 초기화해주는 것이 좋다.

final int MAX_VALUE = 10;

 

리터널 (Literal)

상수는 본래 12, 3.14, 'A'와 같이 그 자체로 값을 의미하는 것인데, 프로그래밍에서는 이 '상수'라는 단어를 '값을 한 번 저장하면 변경할 수 없는 저장공간'이라는 용도로 사용하기 때문에 본래의 상수들을 일컫기 위해 '리터널'이라는 용어을 사용한다.

int year = 2014;
final int MAX_VALUE = 100;
// 변수: year
// 상수: MAX_VALUE
// 리터널: 2014, 100

 

상수가 필요한 이유

  • 고정 값의 의도치 않은 값 변경 실수를 방지한다.
  • 리터널에 '의미있는 이름'을 붙여서 코드의 이해를 돕는다.
  • 코드 수정시 상수 초기화 부분의 값만 바꾸면 되기 때문에 수정이 쉽다.

A. 리터널만 사용한 경우

int triangleArea = (20 * 10) / 2;	// 삼각형 면적 구하기
int rectangleArea = 20 * 10;		// 사각형 면적 구하기

갑자기 대체 무슨값과 무슨값을 연산하는건지, 저 값이 의미하는 게 무엇인지 단번에 이해하기 어려움

B. 상수를 사용한 경우

final int WIDTH = 20;	// 폭
final int HEIGHT = 10;	// 높이

int triangleArea = (WIDTH * HEIGHT) / 2;	// 삼각형 면적 구하기
int rectangleArea = WIDTH * HEIGHT;			// 사각형 면적 구하기

상수명으로 하여금 폭X높이를 연산하는 코드라는 걸 단번에 알 수 있다.
혹시 폭을 잘못 설정했다 하더라도 WIDTH 상수 값만 변경해주면 변경된 값이 코드 전체에 반영된다.

 

리터널의 타입과 접미사

변수의 타입은 저장될 '값의 타입(리터널의 타입)'에 의해 결정된다고 했다. 이렇듯 리터널에도 변수처럼 타입이 존재한다.

논리형, 문자형, 문자열 타입은 상관 없으나 정수형, 실수형에는 여러 타입이 존재하므로, 리터널에 접미사를 붙여서 타입을 구분한다. 접미사를 안붙이면 정수형은 int, 실수형은 double로, 기본 자료형으로 인식된다. (기본 자료형은 접미사가 생략 가능하다.)

byte와 short타입의 리터널은 별도로 존재하지 않으며 해당 변수들에 값을 저장할 때는 int타입 리터널을 사용한다.

정수형에서는 10진수 외에도 2, 8, 16진수로 표현된 리터널을 변수에 저장할 수 있다. 코드에서 '077'과 같은 리터널을 보더라도 '왜 77앞에 의미없이 0을 붙여놨지? 오타인가보네' 라며 섣불리 0을 지우지 말자. 8진수 리터널을 표현한 것이니까.

접미사 알파벳의 소/대문자는 상관없다. (l, L 둘 다 OK)

타입 리터널 접미사
정수형 123, 0b101, 077, 0xFF, 100L L
실수형 3.14, 3.0e8, 1.4f, 0x1.0p-1 f, d

 

int octNum = 010;	// int, 8진수
int hexNum = 0x10;	// int, 16진수
int binNum = 0b10;	// int, 2진수

long big = 100_000_000_000L;		// long
long hex = 0xFFFF_FFFF_FFFF_FFFF;	// long, 16진수

float pi = 3.14f;	// float
double rate = 1.618d;	// double

 

  • double타입의 d는 생략 가능하기 때문에, float타입 리터널의 f, long타입 리터널의 L만 신경써서 붙여주면 된다.
    • float은 접미사나 정밀도 등 신경쓸 것이 많다. 메모리가 심각하게 부족한 게 아니라면 왠만해서는 double을 추천
    • 데이터 값의 크기에 상관없이 double타입의 리터널을 float타입의 변수에 저장할 수 없다.
  • 리터널의 타입은 저장될 변수의 타입과 일치하는 것이 보통이지만, 타입이 달라도 저장범위가 넓은 타입에 좁은 타입의 값을 저장하는 것은 허용된다. (= 큰 상자에 작은 물건을 넣는건 OK)
  • 그러나 리터널의 값이 변수타입의 범위를 넘어서거나, 리터널의 타입이 변수의 타입보다 저장범위가 넓어선 안된다. (= 작은 상자에 큰 물건을 넣는건 NG. 물건을 잘라내거나 엉망으로 구겨넣어야만 가능 → 데이터 손실 및 왜곡)
float pi = 3.14;	// 에러. float타입 변수에 double타입 리터널 저장 불가
double rate = 1.1618	// OK. 실수형 리터널에 접미사를 생략하면 double리터널로 간주

int i = 'A';		// OK. 문자 'A'의 유니코드인 65가 변수 i에 저장된다. (char==short : 2byte)
long l = 123;		// OK. long 타입이 int 보다 범위가 넓기 때문에 저장 가능
double d = 3.14f;	// OK. double 타입이 float보다 범위가 넓기 때문에 저장 가능

 

리터널에 소수점이나 10의 제곱을 나타내는 기호 e 또는 E, 그리고 접미사 f, F, d, D를 포함하고 있으면 실수형 리터널로 간주한다.

e1 : 10 제곱 = 곱하기 10 = 소수점자리 오른쪽으로 이동
e-1 : -10제곱 = 나누기 10 = 소점자리 왼쪽으로 이동

자료형 실수형 리터널 다른 형태의 동등한 표현
double 10. 10.0
double .10 0.10
float 10f 10.0f
float 3.14e3f 3140.0f
double 1e1 10.0
double 1e-3 0.001

 

문자, 문자열 리터널

문자열 리터널은 "" 안에 아무것도 없는 빈 문자열(empty string)을 허용하지만,
문자 리터널은 반드시 ''안에 하나의 문자가 있어야 한다.

  • empty string : 빈 문자열 ""
  • blank string : 공백 문자열 " "
String str = "";	// OK. 
char ch = '';		// ERROR
char ch = ' '; 		// OK. 공백 문자(blank)로 변수 초기화

 

원래 String은 클래스이므로 객체를 생성하는 new연산자를 사용해야 하지만 기본 자료형과 같이 선언할 수 있다.
(다른 타입들은 소문자로 작성하는데, String만 클래스 명명타입에 따라 첫글자를 대문자로 쓴다.)

덧셈 연산자를 이용하여 문자열을 결합할 수 있다. 피연산자 중 어느 한쪽이 String이면 나머지 한 쪽을 먼저 String으로 변환한 다음 두 String을 결합한다. (int + String = String)
이때 덧셈 연산자는 왼쪽에서 오른쪽 방향으로 연산을 수행하기 때문에 결합 순서에 따라 결과가 달라질 수 있다.

System.out.println(" " + 7);		//  7
System.out.println(7 + 7 + "");		// 14. 앞의 두개는 int+int
System.out.println("" + 7 + 7);		// 77. 앞에서 이미 String+int

 

printf()

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

  • 정수형 변수에 저장된 값을 10진 진수로 출력할 때는 지시자 '%d'(decimal)를 사용하며, 변수의 값을 지정된 형식으로 변환해서 지시자대신 넣는다.
  • println()과 달리 printf()는 줄바꿈이 자동으로 이뤄지지 않는다. 줄바꿈을 위해서는 문자열 내에 '\n' 또는 '%n'을 추가해야 한다.
  • 출력될 값이 차지할 공간을 숫자로 지정할 수 있다.여러 값을 여러 줄로 간격 맞춰 출력할 때 꼭 필요한 기능.
  • '%x'와 '%o'에 '#'을 사용하면 접두사 '0x'와 '0'이 각각 붙는다.
  • '%f'는 기본적으로 소수점 아래 6자리까지만 출력하기 때문에 소수점 아래 7자리에서 반올림한다.
    • 1.23456789 → 1.234568
    • 전체 자리수와 소수점 아래 자리수, 좌우 정렬을 지정할 수 있다.
    • %전체자리.소수점아래자리f : 전체 자리 중 소수점 아래 자리수만큼만 출력
      소수점도 한자리를 차지, 소수점 아래 빈자리는 0으로, 정수의 빈자리는 공백으로 채워서 전체 자리수를 맞춘다.
  • '%s'도 지시자 앞에 자리수를 추가하면 원하는 만큼의 출력공간을 확보하거나 문자열의 일부만 출력할 수 있다.
    • n : n만큼 출력공간 확보 (우측정렬)
    • -n : n만큼 출력공간 확보 (좌측정렬) 
    • .n : 왼쪽에서 n만큼만 출력
지시자 설명
%b boolean 형식 출력
%d 10진(decimal) 정수 형식 출력
%o 8진(octal) 정수 형식 출력
%x, %X 16진(hexa-decimal) 정수 형식 출력
%f 부동 소수점(floating-point) 형식 출력
%e, %E 지수(exponent) 표현식 형식 출력
%c 문자(char) 출력
%s 문자열(string) 출력

 

Scanner

  • nextLine() 메서드가 호출되면 입력대기 상태에 있다가, 사용자가 입력을 마치고 엔터를 누르는 순간 입력한 내용을 문자열로 반환한다.
    • 여기서 반환된 문자열 데이터를 Integer.parseInt(), Float.parseFloat() 메서드로 형변환 할 수 있다.
    • 만일 숫자가 아니라 문자 또는 기호에 parseInt() 메서드를 사용하면 에러가 발생한다. (공백 입력에 주의!)
  • nextInt(), nextFloat() 메서드를 사용해 바로 정수, 실수 데이터를 입력받을 수도 있으나 이 메서드들은 연속적인 값을 입력받아서 사용하기에 까다롭다. 모든 값을 nextLine()으로 입력 받아 적절히 자르거나 변환하는 것이 편함.
import java.util.*;

public class MainClass {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
        
        String input = scanner.nextLine();
        int num = Integer.parseInt(input);
	}

}

 

기본형(primitive type)

boolean

  • true / false 저장 가능, 디폴트값은 false이다.
  • 두 가지 값만을 표현하면 되므로 1bit(0/1)만으로 충분하지만, 자바에서는 데이터를 다루는 최소단위가 byte(8bit)이기 때문에 boolean의 크기가 1byte이다.
  • 대답(yes/no), 스위치(on/off) 등의 논리구현에 주로 사용된다.
    • 한 가지 예로 스마트폰의 야간모드를 들 수 있다. 낮모드/야간모드 두 가지 전환밖에 없기 때문에 [모드 변경] 버튼을 클릭하면 boolean 타입의 변수 isMode에 부정연산자를 적용해 반대 모드로 전환하도록 프로그래밍할 수 있다.

 

char

  • 문자를 저장하기 위한 변수를 선언할 때 사용되며, 단 하나의 문자만을 저장한다.
  • 변수에 'a'와 같이 문자가 저장되는 것 같지만, 사실은 문자가 아닌 유니코드(정수)가 저장된다.
    컴퓨터는 숫자(이진법)밖에 모르기 때문에 모든 데이터를 숫자로 변환하여 저장하는 것이다.
    • char ch = 'A';    // 실제로 저장되는 값은 65 정수
    • char 타입 변수를 int타입으로 형변환 하면 유니코드 정수가 나온다.
// 문자 'A'의 유니코드 : 65 (16진수로 0x41)
char ch = 'A';	// 문자 'A'를 저장
char ch = 65;	// 문자의 코드를 직접 저장

int code = (int) ch;	// ch에 저장된 유니코드 정수

char hch = 0x41;		// 16진수 저장
char hch = '\u41';		// 16진수 유니코드 저장

 

특수문자 입력

특수 문자 문자 리터널
tab \t
backspace \b
form feed \f
new line \n
carriage reture \r
역슬래쉬 \\ (c:/ 파일경로 작성시 사용)
작은따옴표 \'
큰따옴표 \" (""안에서 "출력 가능)
유니코드(16진수) 문자 \u유니코드 

 

아스키

확장 아스키

유니코드

 

형변환 (Type Casting)

 

 

 

 

Comments