변수란?
단 하나의 값을 저장할 수 있는 메모리 공간입니다.
변수 선언 및 초기화 방법
- 변수 타입은 저장하려는 값의 종류를 지정합니다. 자바는 정수, 실수, 문자 등을 포함하여 다양한 기본 데이터 타입을 제공합니다. 아래에서 타입에 대해 자세히 설명하고 있으니, 지금은 넘어가도 됩니다.
- 변수 이름에는 해당 변수를 사용할 이름을 붙여 주는 것입니다. 변수 이름은 단 하나만 존재해야 합니다. 같은 이름이 같은 공간에 있을 경우 어떤 변수를 말하는 건지 프로그램은 모르기 때문입니다. 변수 이름을 작성하는 규칙은 아래에서 확인할 수 있습니다.
- 변수에 저장될 값은 내가 만들어준 변수에 저장해 줄 어떤 값을 넣어주면 됩니다. 단, 타입에 맞게 넣어줘야 합니다. 이렇게 변수에 적절한 값을 할당하는 행위를 변수 초기화라고 합니다.
위 그림은 int형 변수 year을 선언하고, year 변수에 2024 값을 초기화 해준 내용입니다.
변수를 선언하고, 해당 변수를 사용하면 됩니다. 단, 변수 사용하기 전에 꼭 초기화 작업을 해줘야 합니다.
만약 변수 선언 후 초기화 작업을 하지 않고, 해당 변수를 사용하게 되면 Java는 에러를 던져줍니다.
- 유효한 코드 예제 -
public class VariableEx01 {
public static void main(String[] args) {
int year;
year = 2024;
System.out.println(year);
}
}
- 출력 결과 -
2024
- 유효하지 않은 코드 예제 (에러 발생) -
public class VariableEx01 {
public static void main(String[] args) {
int year;
// 변수 선언 후 초기화 없이 사용할 경우 에러 발생
System.out.println(year);
}
}
- 출력 결과 -
java: variable year might not have been initialized //year 변수가 초기화되지 않았다는 에러
위 코드에서 살펴본 것과 같이 변수를 선언 후 초기화 작업 없이, 해당 변수를 출력하려고 하면 에러가 발생됩니다. 이러한 규칙은 출력뿐만 아니라, 변수를 사용하는 모든 연산(덧셈, 뺄셈, 비교 등)에 적용됩니다.
💡 Java에서 화면에 텍스트를 출력하기 위해 System.out.println() 메서드를 자주 사용합니다. 이 메서드는 Java의 표준 출력 스트림인 System.out 객체에 속해 있으며, 주어진 인자(문자열, 숫자, 변수 등 다양한 데이터 타입)를 콘솔에 출력한 후 줄 바꿈을 수행합니다.
이 메서드를 사용하는 것은 Java 프로그래밍을 배우는 초기 단계에서 가장 기본적인 방법 중 하나로, 디버깅이나 간단한 프로그램의 결과를 확인하는 데 매우 유용합니다. System.out.println() 을 사용함으로써, 개발자는 콘솔에 메시지를 쉽게 출력하여 프로그램의 실행 흐름을 모니터링하거나 변수의 값 등을 확인할 수 있습니다.
💡 Java에서 코드에 대해 설명을 작성하는 용도 또는 실행되지 않아야 할 코드를 비활성화하기 위해 주석(Comment)이라는 기능을 사용합니다. 주요 세 가지 유형이 있습니다.
● ' // ' : 한 줄 주석으로 //로 시작하여 해당 줄의 끝까지 주석처리를 합니다.
● ' /* */ ' : 여러 줄 주석으로 /*로 시작하고 */로 끝나며, 이 사이에 있는 모든 내용을 주석으로 처리합니다. 여러 줄 주석은 여러 줄에 걸친 설명을 추가하거나 코드의 큰 부분을 비활성화할 때 유용합니다.
● ' /** */ ' : 문서 주석으로 주로 API 문서를 자동으로 생성하기 위해 사용됩니다. 이 유형의 주석은 /**로 시작하고 */로 끝나며, Javadoc 도구는 이러한 주석을 사용하여 HTML 형식의 문서를 생성합니다.
변수 초기화는 아래와 같이 여러 방법으로 할 수 있습니다. 해당 코드는 모두 같은 기능을 합니다.
위 그림에서 살펴보면 콤마( , ) 로 변수명을 이어서 써줬는데, 타입이 같은 변수끼리는 콤마로 작성해서 변수 선언 및 초기화를 같이 할 수 있습니다.
- 실습 예제 -
public class VariableEx02 {
public static void main(String[] args) {
int a;
int b;
a = 1;
b = 1;
System.out.println(a);
System.out.println(b);
int c, d;
c = 1;
d = 1;
System.out.println(c);
System.out.println(d);
int e = 1;
int f = 1;
System.out.println(e);
System.out.println(f);
int g = 1, h = 1;
System.out.println(g);
System.out.println(h);
}
}
- 출력 결과 -
1
1
1
1
1
1
1
1
변수 명명 규칙
변수의 이름은 사용자가 원하는 이름으로 작성하시면 됩니다. 하지만 여기에 몇 가지 지켜야 할 필수적인 규칙과 권장되는 규칙이 있습니다.
필수적인 규칙
- 대소문자가 구분되며, 길이에 제한이 없습니다.
- 예) woozzing 과 Woozzing은 다른 것으로 인식됩니다.
- Java에서 기본적으로 사용하기 위해 의미가 부여되어 있는 예약어는 사용할 수 없습니다.
- 예) class, public, static, void, if, else, try, catch, finally, import, package 등
- 변수 이름은 문자와 숫자 그리고 특수문자 '_' 와 '$' 로 구성할 수 있습니다. 단, 변수 이름의 시작은 반드시 문자 또는 특수문자로 시작해야 합니다.
- 예) k1 은 허용하지만, 1k 는 허용되지 않습니다.
● '$' 같은 경우는 자동으로 생성되는 이름으로 직접 사용은 피하는 것이 좋습니다.
● '_' 자체는 유효한 변수 이름이 아닙니다. (Java 9 이후 버전에서 '_' 가 예약어로 지정되었습니다)
● 메서드나 클래스도 위와 같은 명명 규칙을 따릅니다.
권장되는 규칙
- 변수 이름은 소문자로 시작해야 하며, 두 번째 단어부터는 첫 글자를 대문자로 표기하는 카멜케이스(CamelCase) 방식을 사용합니다.
- 예) helloWorld, javaProgram 등
- 상수(변경되지 않는 변수)는 모든 글자를 대문자로 하며, 단어 사이는 '_'로 구분합니다.
- 예) MAX_SIZE, PI_VALUE, DEFAULT_NAME 등
권장되는 규칙은 필수적으로 지켜야 하는 사항은 아니지만, 대부분의 자바 프로그래머들이 지키고 있는 관례입니다.
변수 타입
변수의 타입에는 기본형과 참조형이 있습니다. 이 두 가지에는 데이터를 저장하고 처리하는 방식에서 큰 차이가 있습니다.
기본형
- 실제 값(data)을 메모리에 직접 저장합니다.
- 자바에서는 8가지 기본형 타입을 제공합니다.
- 정수형(byte, short, int, long), 실수형(float, double), 문자형(char), 논리형(boolean)
- 기본형 변수는 변수를 생성할 때 지정한 타입에 따라 고정된 메모리 크기를 갖습니다.
- 예) int age = 30; 여기서 age는 기본형 타입의 변수 이름이며, 정수 30을 직접 저장합니다.
- boolean을 제외한 나머지 7가지의 타입은 서로 연산이 가능합니다. char타입은 문자를 내부적으로 정수(유니코드)로 저장하기 때문에 정수형, 실수형과 연산이 가능합니다.
- 예) 문자 A의 유니코드 값은 65 입니다.
기본형의 종류별 특징을 살펴보겠습니다.
논리형
- 논리형 변수는 참(true) 또는 거짓(false) 두 가지 값 중 하나만을 저장할 수 있습니다.
- 주로 조건문과 제어문에서 조건식을 평가하고, 메서드나 클래스의 반환 값으로 사용됩니다.
- 대소문자가 구분되므로 True나 TRUE는 사용할 수 없습니다. (true, false만 가능)
- 기본값은 false 입니다.
문자형
- 문자형 변수는 문자가 저장되는 것이 아닌 문자의 유니코드(Unicode)가 저장됩니다. 유니코드는 전 세계의 모든 문자와 기호를 표현하기 위한 표준 인코딩 방식입니다.
- 예) A는 유니코드로 숫자 65이고, B는 유니코드로 숫자 66입니다.
- 단 하나의 문자만을 저장할 수 있습니다.
- 기본값은 널 문자인 \u0000 입니다. 이 값은 유니코드에서 0번째 위치에 해당하는 문자로, 실제로는 어떠한 문자도 표현하지 않는 특수한 값입니다.
정수형
- 정수형 변수는 부호 있는 정수 값을 저장합니다. 즉, 양수, 음수, 0을 저장할 수 있습니다.
- 정수형은 주로 int가 쓰입니다. int는 대부분의 정수 값을 표현할 수 있는 충분한 범위를 제공합니다.(약 ±21억)
- JVM은 정수타입을 4 byte 단위로 작업을 수행하기 때문에, byte와 short 타입은 연산을 수행할 때 내부적으로 int 타입으로 확장되어 처리됩니다. 따라서 int를 사용하는 것이 더 효율적입니다.
- byte와 short는 저장공간이 중요할 때 사용하고, long은 int의 범위를 넘어서는 수를 다룰 때 사용합니다.
- long 타입인 경우 접미사 l 또는 L을 붙입니다. 붙이지 않을 경우 해당 값은 int 타입으로 에러가 발생합니다.
- 예) 7852354812L;
- 정수형 리터럴 중간에 '_' 구분자를 추가할 수 있습니다(사람이 구분할 때 편합니다).
- 예) 1_000_000_000 은 JVM이 내부적으로 언더바(_)를 제거합니다.
- 기본값은 0 입니다.
실수형
- 실수형 변수는 소수점이 있는 수를 저장하는 데 사용됩니다.
- 실수형은 주로 double이 쓰입니다. double은 대부분의 실수 값을 표현할 수 있는 충분한 정밀도와 범위를 제공합니다.(float 타입은 소수점자리 6~7개를 표현하기 때문에 너무 적습니다.)
- float 타입인 경우 접미사 f 또는 F를 붙입니다. 붙이지 않을 경우 해당 값은 double 타입으로 에러가 발생합니다.
- 예) 3.14F
- 기본값은 0.0 입니다.
💡 float과 double은 부동소수점 타입입니다. 부동소수점은 금융계산에 적합하지 않습니다. 예를 들어 2.0 - 1.1의 결과를 출력하게 되면 0.8999999999999999 값이 출력됩니다. 이렇게 나오는 이유는 부동소수점 수를 2진수 체계로 나타내기 때문입니다. 따라서 이런 절대적인 정밀도가 요구되는 상황에서는 BigDecimal 클래스 사용하는 것이 권장됩니다.
- 실습 예제 -
public class VariableEx03 {
public static void main(String[] args) {
/* 논리형 */
boolean flag = true;
System.out.println("=======논리형=======");
System.out.println(flag);
/* 문자형 */
char a = 'A';
System.out.println("=======문자형=======");
System.out.println(a);
System.out.println((int) a); // A 문자의 유니코드 정수 출력
/* 정수형 */
byte b = 127;
short s = 32_767;
int i = 32_768;
long l = 7_852_354_812L;
System.out.println("=======정수형=======");
System.out.println(b);
System.out.println(s);
System.out.println(i);
System.out.println(l);
/* 실수형 */
float f = 3.141592F;
double d = 3.141592653589793;
System.out.println("=======실수형=======");
System.out.println(f);
System.out.println(d);
}
}
- 출력 결과 -
=======논리형=======
true
=======문자형=======
A
65
=======정수형=======
127
32767
32768
7852354812
=======실수형=======
3.141592
3.141592653589793
💡기본형에 기본값이 주어진다고 했는데, 이 글 맨 위에 변수 선언 및 초기화에서 변수 선언만 진행하고 초기화 없이 해당 변수를 사용할 때는 왜 기본값이 출력된 게 아니라 에러가 발생했을까요?
그 이유는 Java에서 기본형 데이터 타입의 기본값은 클래스의 멤버 변수(필드)에 대해 자동으로 적용되기 때문입니다. 우리는 지금까지 "public static void main" 안에서만 작업을 했습니다. "main"은 메서드로 메서드 내부에서 선언된 변수에 대해서는 이러한 기본값이 자동으로 적용되지 않습니다. 이렇게 메서드 내부에서 선언된 변수를 로컬 변수(지역 변수)라 합니다.
참조형
- 참조형 변수는 메모리에 저장된 객체의 주소(참조)를 저장합니다. 즉, 변수 자체에 데이터가 직접 저장되는 것이 아니라, 데이터가 저장된 객체를 가리키는 메모리 주소가 저장됩니다.
- 참조형 타입은 기본형 타입 8개를 제외한 모든 타입을 말합니다(클래스, 인터페이스, 배열, 문자열 등).
- 참조형 변수의 선언 방법은 변수의 타입으로 클래스 이름을 사용합니다.
- 예) String name = "wooZzing"; 여기서 name은 참조형 타입의 변수 이름이며, 문자열 "wooZzing"이 저장된 String 객체의 주소를 가리킵니다. 예를 들어 "wooZzing"이 저장된 주소가 x0100 이라면 name변수에는 x0100이 저장됩니다. (여기서 x0100은 메모리상 가상의 주소입니다.)
참조형 변수는 객체의 주소를 저장한다고 했는데, 정확히 무슨 말일 까요? 예를 들어, 다음과 같이 자동차의 속성을 담은 클래스가 있다고 가정해 보겠습니다.
public class Car {
String model = "현대";
int year = 2024;
int maxSpeed = 200;
}
이렇게 자동차의 속성을 담은 클래스를 사용하기 위해 참조형 변수 carInfo에 초기화하고, 해당 변수를 출력해 보겠습니다. 결괏값이 어떻게 나올까요?
public class Reference {
public static void main(String[] args) {
// 자동차의 속성을 담은 Car 클래스를 참조형 변수 carInfo에 선언
Car carInfo;
// Car 클래스의 새 인스턴스(객체)를 생성하고, 그 인스턴스의 메모리 주소를 carInfo 변수에 할당합니다
carInfo = new Car();
System.out.println(carInfo);
}
}
이 코드의 출력 결과는 클래스(타입)@주소 처럼 메모리 주소를 나타내는 식별자와 같은 형태의 문자열이 출력됩니다. 예를 들어, Car@3b07d329와 같은 형태로 출력될 수 있습니다. 이는 Car 클래스의 인스턴스에 대한 참조의 메모리 주소(해시코드 기반)를 문자열로 표현하는 방식입니다.
💡 클래스, 인스턴스는 추후에 자세히 배울 내용입니다. 참조형 변수가 정확히 이해가 가지 않더라도 가볍게 읽고 넘어가시면 됩니다!
위에서 제공된 Car 클래스의 인스턴스를 참조 변수를 사용하여 선언하고 초기화하는 과정을 그림으로 설명하겠습니다.
- Car 클래스 타입의 carInfo를 선언하고, new 키워드를 통해 신규 객체를 생성 후, 해당 주소를 참조 변수에 초기화했습니다.
- new 키워드는 새로운 객체를 생성하고, 그 객체의 주소를 반환해 줍니다. 따라서 "new Car"는 새로운 Car 객체를 생성하고, 이 객체의 주소를 "carInfo"라는 변수에 할당하는 과정입니다.
기본형과 참조형의 차이점을 요약하자면 기본형은 실제 값을 직접 저장하는 반면, 참조형은 메모리에 저장된 객체를 가리키는 주소를 저장합니다!
상수란?
Java에서 상수(constant)는 한 번 값을 저장하면 다른 값으로 변경할 수 없는 변수를 의미합니다. 상수는 프로그램 실행 도중에 그 값이 변하지 않아야 하는 데이터에 사용됩니다. 예를 들어, π(파이)의 값이나 한 주의 일수와 같이 변하지 않는 값을 표현할 때 상수를 사용할 수 있습니다.
상수의 선언 및 초기화 방법
상수를 선언하기 위해 final 키워드를 사용합니다. final 키워드는 변수 앞에 위치하며, 이 변수의 값을 변경할 수 없음을 컴파일러에게 알립니다. 상수의 이름은 일반적으로 대문자로 작성하며, 여러 단어로 이루어진 경우에는 단어 사이를 '_' 로 구분합니다. 이는 상수 값을 쉽게 식별하기 위한 권장되는 규칙입니다.
상수를 사용하기 전에 딱 한 번만 초기화한다면 초기화를 나중으로 미룰 수 있습니다(JDK 1.6 이상부터). 하지만, 선언과 동시에 초기화하는 습관이 좋습니다.
- 실습 예제 -
public class VariableEx04 {
public static void main(String[] args) {
final double PI = 3.14159;
final int DAYS_IN_WEEK = 7;
System.out.println(PI);
System.out.println(DAYS_IN_WEEK);
}
}
- 출력 결과 -
3.14159
7
상수는 변경할 수 없는 변수라고 배웠는데, 아래 코드와 같이 변경을 시도하면 어떻게 될까요?
final int MAX_VALUE = 100;
MAX_VALUE = 200;
final 키워드로 MAX_VALUE 값을 100으로 초기화를 한 이후에, MAX_VALUE 값을 200으로 변경하려 했기 때문에 해당 코드는 컴파일러가 에러를 던져줍니다.
The final local variable MAX_VALUE cannot be assigned. It must be blank and not using a compound assignment
상수를 사용하는 이유
굳이 상수를 사용하는 이유는 무엇일까요? 상수 대신 리터럴(값 그 자체) 또는 변수를 사용해도 되지만 상수를 사용하는 이유는 아래와 같은 이유로 사용합니다.
- 불변성(Immutability) : 상수의 가장 중요한 특징은 한 번 초기화되면 그 값을 변경할 수 없다는 것입니다. 시도하면 컴파일 오류가 발생합니다.
- 명확성(Clarity) : 상수를 사용하면 코드의 가독성이 향상됩니다. 리터럴 값(예: 3.14159) 대신 의미 있는 이름(예: PI)을 사용하여 코드 내에서 어떤 값이 사용되고 있는지 쉽게 파악할 수 있습니다.
- 유지보수성(Maintainability) : 프로그램에서 반복적으로 사용되는 값에 대해 상수를 사용하면, 나중에 이 값을 변경해야 할 경우 상수를 선언한 한 곳만 수정하면 되므로 유지보수가 용이해집니다.
- 타입 안정성(Type Safety): 상수에는 선언 시 지정한 타입의 값만 할당할 수 있습니다. 이를 통해 타입 불일치로 인한 오류를 사전에 방지할 수 있습니다.
이러한 이유로 상수는 프로그램의 안정성과 유지보수성을 향상시키며, 코드를 더 명확하고 의미 있는 형태로 유지할 수 있게 도와줍니다. 상수를 적절히 활용함으로써 코드의 가독성과 신뢰성을 높일 수 있습니다.
읽어주셔서 감사합니다 😊
'프로그래밍 언어 > Java' 카테고리의 다른 글
[Java] 04. 조건문 배우기 (if, if-else, else if, switch) (0) | 2024.03.27 |
---|---|
[Java] 03. 연산자란? (우선순위, 결합규칙) (1) | 2024.03.26 |
[Java] 02. 형변환이란? (암시적 형변환, 명시적 형변환) (0) | 2024.03.26 |
Java 17 개발 환경 셋팅 - JDK 17 & 인텔리제이 설치 (With.MacOS M1) (0) | 2024.03.26 |
Java 프로그래밍 언어 소개 (0) | 2024.03.26 |