코딩/Java

Java 2 : 변수

americanoallday 2025. 2. 4. 19:01

변수(Variable)

데이터를 저장하는 공간(메모리)

 

변수 생성 규칙

- 대소문자가 구분되며 길이에 제한이 없음

- 숫자로 시작 불가

- 특수문자는 _ 와 $ 만 허용

 

변수 선언

class Variable1_1 {
        boolean flag;
        char grade;
        byte val;
        short sval;
        int num;
        long price;
        float tax;
        double score;
}

 

 

변수의 종류

지역 변수(Local Variable)

- 메서드나 블록 내부에서 선언되는 변수, 반드시 초기화해야 함.

- 메모리 저장 위치 : Stack

- 생명 주기 : 메서드 종료 시 제거

인스턴스 변수(Instance Variable)

- 클래스 내부에서 선언, 객체가 생성될 때 할당됨. 객체마다 별도 존재, 서로 다른 값을 가질 수 있음. 

- 메모리 저장 위치 : Heap

- 생명 주기 : 객체가 제거될 때까지 유지

클래스 변수(Class Variable, Static Variable)

- 모든 객체가 공유하는 변수, 한 번만 메모리에 저장 됨. 

- 메모리 저장 위치 : Method Area

- 생명 주기 : 프로그램 종료 시까지 유지

매개변수(Parameter)

- 메서드가 호출될 때 전달되는 값을 저장하는 변수. 메서드가 실행되는 동안만 사용.

- 메모리 저장 위치 : Stack

- 생명 주기 : 메서드 실행 중에만 존재

class Car {
    // 클래스 변수 (static 변수) - 모든 객체가 공유
    static int totalCars = 0;

    // 인스턴스 변수 - 객체마다 개별적으로 존재
    String brand;
    int speed;

    // 생성자 (매개변수 사용)
    public Car(String brand, int speed) {
        this.brand = brand; // 인스턴스 변수 초기화
        this.speed = speed; // 인스턴스 변수 초기화
        totalCars++; // 클래스 변수 증가 (모든 객체가 공유)
    }

    // 메서드 (매개변수 사용)
    public void accelerate(int increase) {
        // 지역 변수 - 메서드 내부에서만 사용
        int newSpeed = speed + increase;
        speed = newSpeed; // 인스턴스 변수 업데이트
        System.out.println(brand + " 속도 증가: " + speed + "km/h");
    }

    // 클래스 변수 사용 예제
    public static void showTotalCars() {
        System.out.println("총 차량 수: " + totalCars);
    }
}

public class VariableExample {
    public static void main(String[] args) {
        // 지역 변수 - main 메서드 내부에서만 사용됨
        int initialSpeed = 50;

        // 객체 생성 (매개변수 전달)
        Car car1 = new Car("Tesla", initialSpeed);
        Car car2 = new Car("BMW", 60);

        // 메서드 호출 (매개변수 전달)
        car1.accelerate(20);
        car2.accelerate(30);

        // 클래스 변수 출력 (객체 없이 사용 가능)
        Car.showTotalCars();
    }
}

지역 변수: initialSpeed, newSpeed

인스턴스 변수: brand, speed

클래스 변수: totalCars

매개변수: brand, speed, increase

 

상수(Constant)

한 번 값을 저장하면 변경할 수 없는 변수.

프로그램 실핼 중 값이 변하지 않아야 할 경우 사용 됨.

final 키워드를 사용해서 선언

public class ConstantExample {
    public static void main(String[] args) {
        final double PI = 3.14159; // 상수 선언
        System.out.println("원주율: " + PI);

        // PI = 3.14;  // ❌ 오류 발생! (상수는 값 변경 불가능)
    }
}

 

리터럴(Literal)

상수나 변수에 들어가는 값 자체를 의미.

- 정수 리터럴 : int, long

- 실수 리터럴 : double, float

- 문자 리터럴 : char, ''(작은 따옴표)

- 문자열 리터럴 : String, ""(큰 따옴표)

- 논리 리터럴 : boolean

- null 리터럴 : 객체가 아무것도 가리키지 않을 때 사용

public class LiteralExample {
    public static void main(String[] args) {
        int number = 10;      // 정수 리터럴 (10)
        double pi = 3.14;     // 실수 리터럴 (3.14)
        char letter = 'A';    // 문자 리터럴 ('A')
        String word = "Java"; // 문자열 리터럴 ("Java")
        boolean isJavaFun = true; // 논리 리터럴 (true)

        System.out.println(number);
        System.out.println(pi);
        System.out.println(letter);
        System.out.println(word);
        System.out.println(isJavaFun);
    }
}

✔ "Java"는 문자열 리터럴

✔ 'A'는 문자 리터럴

✔ 10, 3.14, true 같은 값들은 모두 리터럴!

 

기본형 데이터 타입

논리형

- boolean(1 byte), range(true, false), default value(false)

문자형

- char(2 byte), range(0 ~ 65,535), default value('\u0000')

정수형

- byte(1 byte), range(-128 ~ 127), default value(0)

- short(2 byte), range(-32,768 ~ 32,767), default value(0)

- int(4 byte), range(-2,147,483,648 ~ 2,147,483,647), default value(0)

- long(8 byte), range(-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807), default value(0L)

실수형

- float(4 byte), range(-3.4 × 10^38 ~ 3.4 × 10^38), default value(0.0F)

- double(8 byte), range(-1.8 x 10^308 ~ 1.8 x 10^308), default value(0.0)

더보기

1bit = 0, 1 -> 2개

2bit = 00, 10, 01, 11 -> 4개

8bit = 2^8 : 256개

 

1byte = 8bit

 

부호없는 정수의 범위 : 0 ~ 2^n - 1

부호있는 정수의 범위 : -2^(n-1) ~ 2^(n-1) - 1

✔ 첫 번째 비트(최상위 비트, Most Significant Bit)를 부호(Sign)로 사용.

✔ 0이면 양수, 1이면 음수를 나타냄.

✔ 나머지 (n-1)개의 비트로 숫자를 표현.

📌 즉, 전체 n비트 중에서 1비트는 부호를 저장하므로, 숫자를 저장하는 공간이 n-1비트로 줄어듦.

 

실수형 표현 범위

float(4byte) = 32bit

S : 부호(양수, 음수), 1bit

E : 지수, 8bit

M : 가수(소수점 이하), 23bit

 

정규화 (Normalization)

✔ 부동소수점 표현에서, 가수를 항상 특정한 형태로 유지하는 것

✔ 컴퓨터가 소수를 저장하는 방식을 표준화해서, 저장 공간을 최적화하는 과정

✔ IEEE 754 표준에 따라 가수(M)는 항상 1.xxx... 형태로 저장됨.

✔ 즉, 소수점 왼쪽이 항상 1이 되도록 변환하는 것

 

🔹 예제: 10진수를 2진수 부동소수점으로 변환

(1) 10진수 10.625를 2진수로 변환

1. 정수 부분 변환: 101010₂

2. 소수 부분 변환: 0.6250.101₂

3. 전체 2진수 표현: 1010.101₂

(2) 정규화 (Normalization)

✔ 정규화하면 소수점 왼쪽을 1로 맞춰야 함.

1010.101₂1.010101 × 2³

✔ 즉, M = 1.010101, E = 3

 

📌 똑같은 4byte여도 float가 int보다 더 큰 범위가 저장 가능한 이유

int는 1비트는 부호, 31비트는 숫자만 저장 가능함

float는 1비트는 부호, 8비트는 지수, 23비트는 가수로 구성되어 있는데, 위의 부동소수점 표현으로 더 큰 범위가 저장 가능하기 때문

✔ 지수를 사용해서 값의 크기를 조절할 수 있음.

✔ 즉, 10진수에서 1.5 × 10³, 1.5 × 10⁶처럼, float도 M × 2^E 형태로 수를 표현 가능

 

메모리에는 값이 2진수로 변환하여 저장 됨. 

문자를 표현하기 위해서 문자와 숫자를 매칭하는 아스키 코드를 만들었음. (ex : A -> 65 -> 1000001(2))
*문자코드는 음수 표현이 필요없기 때문에 char범위에는 부호가 없음.

아스키코드(ASCII)

✔ 영어 알파벳, 숫자, 특수문자를 표현하는 문자 인코딩 표준

✔ 7비트(0~127)의 숫자로 문자 표현 (총 128개 문자 가능)

✔ 주로 영어 및 기본적인 기호만 포함됨.

유니코드(Unicode)

✔ 전 세계 모든 문자를 표현하기 위한 국제 표준 문자 인코딩

✔ ASCII로는 영어만 표현 가능하지만, 한글, 일본어, 중국어 등 모든 언어를 포함함.

✔ 각 문자를 고유한 코드(숫자)로 매핑하여 저장함.

✔ 유니코드 문자 표현 방식에는 여러 가지가 있지만, 가장 많이 사용하는 방식이 UTF-8

UTF-8

✔ 유니코드를 효율적으로 저장하기 위한 가변 길이 인코딩 방식

✔ 1~4바이트로 문자 표현 (가변 길이)

✔ 영어(ASCII 문자)는 1바이트, 한글/중국어/일본어는 3바이트 이상 사용

✔ 웹, 운영체제, 데이터베이스 등에서 가장 많이 사용하는 인코딩 방식

 

 

정수형 오버플로우(Integer Overflow)

✔ 변수가 저장할 수 있는 최대값을 초과할 때 발생하는 오류

✔ 컴퓨터는 메모리 크기가 제한되어 있기 때문에, 특정 자료형이 표현할 수 있는 숫자 범위를 넘으면 값이 예상과 다르게 변함.

✔ 최대값을 초과하면 최소값으로, 최소값을 초과하면 최대값으로 순환됨 (순환 구조, Wrap Around).

public class OverflowExample {
    public static void main(String[] args) {
        int maxInt = Integer.MAX_VALUE; // 2,147,483,647 (int의 최대값)
        System.out.println("최대값: " + maxInt);

        int overflow = maxInt + 1; // 최대값 + 1
        System.out.println("오버플로우 발생: " + overflow); // -2,147,483,648 (int 최소값)
    }
}

 

실행 결과

최대값: 2147483647
오버플로우 발생: -2147483648

int의 최대값(2,147,483,647)에서 1을 더하면 최소값(-2,147,483,648)으로 변함!

✔ 이런 현상을 정수형 오버플로우(Integer Overflow)라고 함

 

해설

✔ 컴퓨터는 숫자를 이진수(0과 1)로 저장

int는 4바이트(32비트)이며, 범위는 -2^31 ~ 2^31 - 1

✔ 최대값(0111...1111)에서 +1을 하면 부호 비트가 반전되면서 최소값(1000...0000)이 됨.

 

BigInteger

✔ Java에서 매우 큰 정수를 저장하고 연산할 수 있도록 제공하는 클래스

✔ 기본 정수형(int, long)은 크기 제한이 있지만, BigInteger는 이론적으로 무한한 크기의 정수를 저장 가능

✔ 메모리가 허용하는 한 크기 제한 없이 사용할 수 있음.

java.math.BigInteger 패키지에 포함되어 있음.

public class BigIntegerExample {
    public static void main(String[] args) {
        long maxLong = Long.MAX_VALUE; // 9,223,372,036,854,775,807
        System.out.println("long 최대값: " + maxLong);

        // long 범위를 초과하는 값 (에러 발생)
        // long bigNumber = 9223372036854775808L; // ❌ 오류 발생

        // BigInteger 사용
        BigInteger bigNumber = new BigInteger("9223372036854775808");
        System.out.println("BigInteger 값: " + bigNumber);
    }
}

 

 

BigInteger의 주요 특징

✔ 정수 크기 제한이 없음.

+, -, *, / 같은 연산자를 직접 사용할 수 없고, 메서드를 사용해야 함.

✔ 값을 직접 대입(=)할 수 없고, new BigInteger("값")으로 생성해야 함.

 

타입간 변환방법

숫자 → 문자 (int → char)

public class ConvertExample {
    public static void main(String[] args) {
        int num = 65; // ASCII에서 65는 'A'
        char ch = (char) num;
        System.out.println("숫자 → 문자: " + ch); // 'A'
    }
}
숫자 → 문자: A

 

문자 → 숫자 (char → int)

public class ConvertExample {
    public static void main(String[] args) {
        char ch = 'A';
        int num = (int) ch;
        System.out.println("문자 → 숫자: " + num); // 65
    }
}
문자 → 숫자: 65

 

유니코드(ASCII) 이용한 변환

- 숫자 + '0' = 문자

- 문자 - '0' = 숫자

class Variable3_2  {
    public static void main(String[] args) {
        int num = 5;
        char ch = '5';

        // 숫자 -> 문자
        System.out.println("num = " + num);
        // '0' 이 48이기 때문에 결과값을 char 타입으로 변환 필요
        System.out.println("num + '0' = " + (char)(num + '0'));

        // 문자 -> 숫자
        System.out.println("ch = " + ch);
        System.out.print("ch - '0' = ");
        System.out.println(ch - '0');

        // '5' 에서 숫자 5로 변환되었기 때문에 결과값 6
        System.out.print("ch - '0' + 1 = ");
        System.out.println(ch - '0' + 1);
    }
}

 

숫자 → 문자열 (int → String)

public class ConvertExample {
    public static void main(String[] args) {
        int num = 123;
        String str1 = String.valueOf(num);
        String str2 = Integer.toString(num);
        
        System.out.println("숫자 → 문자열: " + str1); // "123"
        System.out.println("숫자 → 문자열: " + str2); // "123"
    }
}
숫자 → 문자열: 123
숫자 → 문자열: 123

 

문자 → 문자열 (char → String)

public class ConvertExample {
    public static void main(String[] args) {
        char ch = 'A';
        String str1 = Character.toString(ch);
        String str2 = String.valueOf(ch);
        
        System.out.println("문자 → 문자열: " + str1); // "A"
        System.out.println("문자 → 문자열: " + str2); // "A"
    }
}
문자 → 문자열: A
문자 → 문자열: A

 

문자열 연결(Concatenation) 연산을 이용한 변환

- 숫자 + "" = 문자열

- 문자 + "" = 문자열

class Variable3_3  {
    public static void main(String[] args) {
        int num = 5;
        char ch = '5';

        // 숫자 -> 문자열
        System.out.println("num + \"\" = " + num + "");
        // num 이 "5" 로 변환되었기 때문에 "5" + "5" 로  결과값은 "55"
        System.out.println("num + \"\" + \"5\" = " + num + "" + "5");
        
        // 문자 -> 문자열
        System.out.println("ch + \"\" = " + ch + "");
        // ch 이 '5' 에서 "5" 로 변환되었기 때문에 "5" + "8" 로  결과값은 "58"
        System.out.println("ch + \"\" + \"8\" = " + ch + "" + "8");
        
    }
}

 

 

 

문자열 → 숫자 (String → int, double 등)

public class ConvertExample {
    public static void main(String[] args) {
        String str = "123";
        int num = Integer.parseInt(str);
        double dnum = Double.parseDouble("3.14");

        System.out.println("문자열 → 정수: " + num); // 123
        System.out.println("문자열 → 실수: " + dnum); // 3.14
    }
}
문자열 → 정수: 123
문자열 → 실수: 3.14

 

문자열 → 문자 (String → char)

public class ConvertExample {
    public static void main(String[] args) {
        String str = "Hello";
        char ch = str.charAt(0); // 첫 번째 문자 가져오기
        
        System.out.println("문자열 → 문자: " + ch); // 'H'
    }
}
문자열 → 문자: H

 

참조형 타입(Reference Type)

 

기본 데이터타입을 제외한 나머지 타입 (ex : String, System).

참조형 변수는 null 또는 메모리 주소를 저장

타입에 관계없이 변수의 크기는 항상 4byte(JVM이 64bit일 경우 8byte)

- 4바이트(32비트)는 총 2^32 = 4,294,967,296 개의 서로 다른 값을 표현 가능

- 즉, 40억 개(약 2^32)의 메모리 주소를 표현할 수 있음

✔ 각 메모리 주소는 1바이트를 가리킴.

✔ 1개의 메모리 주소가 1바이트(8비트) 크기의 데이터에 해당

✔ 즉, 40억 개의 주소를 저장할 수 있다는 것은 40억 바이트(4GB)의 메모리를 다룰 수 있다는 것을 의미

더보기

64비트 JVM

 2^64 바이트 = 16엑사바이트(EB)

 이론적으로 16EB(엑사바이트)까지 메모리 접근 가능

예제

class Variable3_5 {
    public static void main(String[] args) {
        // Date import 필요!
        Date date; // 참조형 변수 date 를 선언
        date = new Date(); // date 에 객체의 주소를 저장 , new 는 객체를 생성하는 명령어

        System.out.println(date); // Wed Jan 11 20:54:45 KST 2023
    }
}

* Date는 날짜와 시간을 저장하고 조작하는 참조형 클래스

* 기본형(int, double 등)과 다르게, 객체를 생성해야 사용할 수 있음.

* java.util.Date 클래스는 날짜와 시간을 다루는 클래스로, java.util 패키지에 포함되어 있음.