참조형 변수는 객체의 실제 데이터가 저장된 메모리의 위치를 가리키는 주소를 저장한다. 예를 들어, String 타입의 변수는 문자열 데이터가 저장된 위치를 가리키는 참조값을 가진다.
기본형은 값 자체를 변수에 저장하는 반면, 참조형은 메모리에 저장된 객체를 가리키는 주소를 변수에 저장한다. 이러한 차이 때문에, 기본형은 일반적으로 메모리 사용량이 적고 처리 속도가 빠르지만, 복잡한 데이터 구조를 표현하는 데는 한계가 있다. 반면에 참조형은 더 복잡한 데이터 구조와 더 큰 데이터를 다룰 수 있지만, 추가적인 메모리 사용과 처리 시간이 필요하다.
기본형은 간단한 값을 저장하며, 메모리에 직접 값을 가지고 있다. 기본형 데이터 타입에는 다음과 같은 것들이 있다.
byte: 8비트 정수.short: 16비트 정수.int: 32비트 정수. (자바에서 가장 일반적으로 사용되는 정수형 타입)long: 64비트 정수.float: 32비트 부동소수점. (정밀도가 낮은 실수)double: 64비트 부동소수점. (정밀도가 높은 실수)char: 16비트 유니코드 문자. (문자 한 개)boolean: true 또는 false 값을 가지는 타입.정수형 타입에서 범위를 넘어선 값을 저장하려고 하면, 일반적으로 '오버플로우'나 '언더플로우'가 발생한다.
부동소수점 타입에서는 오버플로우와 언더플로우가 다르게 동작한다.
부동소수점 타입에서는 정확도 손실도 문제가 될 수 있다. 특히, 매우 큰 값이나 매우 작은 값을 저장하려고 할 때 정확도가 떨어질 수 있다.
boolean 타입은 오직 true 또는 false 값만을 가질 수 있다. 이 타입은 오버플로우나 언더플로우의 개념이 적용될 수 없다.
public class Ex02_char {
public static void main(String[] args) {
//문자형(char): 2byte사용, 문자 1글자 저장(0~65525)
// 자바 문자처리 방식은 유니코드(Unicode)형태]
char char1 = 'A'; //문자는 작은 따음표를 써야 한다. 큰 따옴표는 안된다. "A"는 문자열(String), 'A'는 문자(char)이다
System.out.println("char1: " + char1);
System.out.println("char1 + 1: " + (char1 + 1)); //,숫자가 나온다
System.out.println("char1 + 1: " + (char)(char1 + 1)); // char타입으로 형변환
char char2 = '한';
System.out.println("char2: " + char2);
char char3 = '\uAC00'; //유니코드 값으로 설정
System.out.println("char3: " + char3);
char char4 = (char)(char1 + 1); // 데이터 형이 다르면 데이터가 큰 것 기준으로 저장된다. char <-- int로 강제형변환 시킨다.
System.out.println("char1 다음값: " + char4);
}
}
이 코드에서 형변환이 일어나는 이유를 설명하기 위해, 먼저 자바에서 기본형 데이터 타입들이 어떻게 연산되는지 이해해야 된다. 코드의 핵심 부분은 char1 + 1이다. 여기서 char1은 char 타입이고, 1은 int 타입이다.
자바에서는 다른 타입의 데이터를 연산할 때, 보다 큰 범위를 가진 타입으로 자동 형변환을 한다. 이를 "확대 변환"(Widening Conversion)이라고 한다. 이 경우, char 타입은 int 타입보다 작기 때문에, char 타입의 char1이 int 타입으로 자동 형변환된다. 따라서 char1 + 1 연산은 실제로 int + int 연산이 되어, 결과도 int 타입이 된다.
System.out.println("char1 + 1: " + (char1 + 1));System.out.println("char1 + 1: " + (char)(char1 + 1));이렇게 자바에서는 타입에 따라 자동 형변환과 명시적 형변환을 통해 다양한 타입 간 연산을 수행할 수 있다. 연산 중에 발생하는 타입 변환을 이해하는 것은 프로그래밍에서 매우 중요한 부분이다.
참조형은 객체의 참조(메모리 주소)를 저장한다. 참조형 데이터 타입의 예로는 다음과 같은 것들이 있다.
참조형 데이터 타입은 주로 객체를 참조하기 위해 사용되며, 여러 가지 형태가 있다.
int[], String[], Object[]int[]는 정수 배열이고, String[]은 문자열 배열이다.List, Map, SetList, Map, Set은 모두 인터페이스로, 이들은 각각 순서가 있는 데이터의 목록, 키-값 쌍의 집합, 그리고 중복되지 않는 값의 집합을 나타낸다.
public class Ex03_byte {
public static void main(String[] args) {
// 정수형 byte: 정수 숫자 저장 256개(-128~127)
byte byte1 = 100;
byte byte2 = 27;
System.out.println("byte1: " + byte1);
System.out.println("byte2: " + byte2);
byte byte3 = (byte)(byte1 + byte2);
System.out.println("byte3에 1을 더하고 byte로 형변환: " + (byte)(byte3 + 1));
//--------------
System.out.println("---byte 최소, 최댓값 ---");
System.out.println("byte 최소값 : " + Byte.MIN_VALUE); // 참조형 데이터
System.out.println("byte 최대값 : " + Byte.MAX_VALUE); // 참조형 데이터
}
}
이 프로그램에서 중요한 점은 byte 타입의 변수들을 연산할 때 자동으로 int 타입으로 형변환되며, 그 결과를 다시 byte 타입으로 명시적으로 형변환해야 한다는 것이다. 이 과정에서 오버플로우가 발생할 수 있으므로 주의해야 한다. 오버플로우는 계산된 결과가 해당 데이터 타입이 저장할 수 있는 범위를 넘어설 때 발생하며, 예상치 못한 값으로 변할 수 있다.
public class Ex04_short {
public static void main(String[] args) {
// 정수형 short: 2byte(갯수 65536, 범위: -32768 ~ 32767)
short short1 = 20000;
short short2 = 30000;
System.out.println("short1 : " + short1);
System.out.println("short2 : " + short2);
//표현범위를 벗어나면 원치않는 결과값을 가진다.
short sum = (short)(short1 + short2); // 결과값이 -15536이 나온다.
System.out.println("short sum : " + sum);
int intSum = short1 + short2;
System.out.println("int intSum : " + intSum);
System.out.println("---short 최소/최대값---");
System.out.println("short 최소값 : " + Short.MIN_VALUE);
System.out.println("short 최대값 : " + Short.MAX_VALUE);
}
}
이 예제에서는 같은 연산이지만 데이터 타입에 따라 결과가 달라지는 것을 보여준다. short 타입으로 계산할 때는 오버플로우가 발생하지만, int 타입으로 계산할 때는 정상적인 결과가 나온다. 이는 자바에서 기본형 데이터 타입의 범위와 연산의 중요성을 이해하는 데 도움이 된다.
public class Ex05_int {
public static void main(String[] args) {
// 정수형 int: 4byte, 범위(-2147483648 ~ 2147483647 : 대략 21억)
int num1 = 70000;
int num2 = 30000;
int sum = num1 + num2; // sum <--- num1 + num2
System.out.println("num1 : " + num1);
System.out.println("num2 : " + num2);
System.out.println("sum : " + sum);
System.out.println(num1 + " + " + num2 + " = " + sum); // 70000 + 30000 = 100000
System.out.println(num1 + " - " + num2 + " = " + (num1 - num2)); // 70000 - 30000 = 40000
System.out.println(num1 + " * " + num2 + " = " + (num1 * num2)); // 70000 * 30000 = 2100000000
System.out.println(num1 + " / " + num2 + " = " + (num1 / num2)); // 70000 / 30000 = 2
// % 연산자 : 나누기 연산 후 남은 나머지 값을 구함
System.out.println(num1 + " % " + num2 + " = " + (num1 % num2)); // 70000 % 30000 = 10000
System.out.println("--- int 최소/최대값 ---");
System.out.println("int 최소값 : " + Integer.MIN_VALUE);
System.out.println("int 최소값 : " + Integer.MAX_VALUE);
}
}
여기서 num1, num2, 그리고 sum이 문자열로 처리되는 것처럼 보이는 이유는 자바의 문자열 연결 연산자 + 때문이다. System.out.println 문에서 + 연산자는 숫자와 문자열을 결합하는 데 사용됩니다. 숫자를 문자열과 결합할 때, 자바는 숫자를 문자열로 자동 변환한다. 이 과정에서 숫자가 문자열의 일부로 취급되어 출력된다.
예를 들어, System.out.println(num1 + " + " + num2 + " = " + sum);의 경우:
이 방식은 다른 연산에도 적용된다. 예를 들어, num1 + " - " + num2 + " = " + (num1 - num2)에서는 먼저 num1과 num2의 차이를 계산한 다음, 그 결과를 문자열과 결합하여 출력한다.
이러한 특성 때문에 자바에서는 문자열과 숫자의 결합을 매우 쉽게 할 수 있다. 하지만 이를 통해 이루어지는 것은 단지 출력 형식을 위한 변환일 뿐, 실제 num1, num2, sum 변수의 데이터 타입은 int로 숫자이다.
public class Ex06_long {
public static void main(String[] args) {
// 정수형 long : 8개 바이트 사용
// 범위 : -9223372036854775808 ~ 9223372036854775807
// long 타입값 명시적 표현 : 숫자 + L 또는 l(영문대소문자 엘)
long num1 = 20000000000L; // int를 넘었을 때, Long타입임을 명시하기 위해 뒤에 L을 붙임
long num2 = 30000000000l;
long sum = num1 + num2;
System.out.println("num1 + num2 = " + sum); // num1 + num2 = 50000000000
System.out.println("=======================");
System.out.println("---- long 최소/최대값 ----");
System.out.println("long 최대값 : " + Long.MAX_VALUE);
System.out.println("long 최솟값 : " + Long.MIN_VALUE);
}
}
public class Ex06_long {
public static void main(String[] args) {
byte numByte = 10;
short numShort = 3000;
int numInt = 3000000;
long numLong = 500000000000000L;
numByte = (byte) numShort; // 강제형변환 : 손실 발생 가능성 있음 -> 쓰레기값 발생 가능성 있다.
System.out.println("numByte : " + numByte); // numByte : -72
numLong = numInt; // long타입 <--- int타입 : 자동형변환
}
}
numByte = (byte) numShort; 은 numShort는 short, numByte는 byte 유형에서 short 유형을 byte 유형으로 강제 형변환하고 있다.이 경우에 numInt의 값을 numLong에 할당하면, numInt의 값이 long 유형으로 자동 변환되어 numLong에 저장된다. 이 변환 과정에서 값의 손실이나 변경은 발생하지 않으며, numLong은 numInt와 같은 값을 가지게 된다.
따라서 numLong = numInt; 라인에서는 numInt의 값을 long 유형인 numLong에 할당하고 있으며, 이 과정은 자동 형변환으로 진행된다. 이러한 자동 형변환은 프로그램의 데이터 처리에 있어서 안전하고 효율적인 방법을 제공한다.
public class Ex07_float {
public static void main(String[] args) {
// 실수형 float: 4byte (1.4E-45 ~ 3.4028235E38)
// 소수점 이하 데이터 저장 가능
// 표시형식: 숫자.숫자 + f 또는 F
// 단, 소수점 이하 6자리까지만 정확도 보장
float f1 = 3.4f;
float f2 = 3.2F;
System.out.println("float 3.4f: " + f1); // float 3.4f: 3.4
System.out.println("float 3.2f: " + f2); // float 3.2f: 3.2
System.out.println("3.4f + 3.2f : " + (3.4f + 3.2f)); // 3.4f + 3.2f : 6.6000004
System.out.println("--- float 최소값 / 최대값 ---");
System.out.println("float 최소값 : " + Float.MIN_VALUE);
System.out.println("float 최대값 : " + Float.MAX_VALUE);
}
}
float 데이터 유형: float는 4바이트(32비트) 크기의 실수를 저장하는 데 사용된다. float 유형의 값은 대략 1.4E-45에서 3.4028235E38 사이의 범위를 가지며, 소수점 이하의 데이터를 저장할 수 있다.
float 리터럴 표기법: Java에서 float 유형의 리터럴은 숫자 뒤에 f 또는 F를 붙여서 표현한다. 예를 들어, 3.4f 또는 3.2F와 같이 작성한다. 이렇게 표기하는 이유는 Java에서 실수 리터럴이 기본적으로 double 유형으로 간주되기 때문이다. f 또는 F를 붙이면 이를 float 유형으로 명시한다.
정확도: float 유형은 소수점 이하 약 6자리까지의 정확도를 보장한다. 이는 더 정밀한 계산이 필요한 경우에는 double 유형을 사용하는 것이 좋다는 것을 의미한다.
float는 실수를 표현하는 데 사용되며, 메모리를 적게 사용하지만 double보다 낮은 정밀도를 가진다.
public class Ex08_double {
public static void main(String[] args) {
// 실수형 double : 8 byte
// 범위 (4.9E-324 ~ 1.7976931348623157E308)
// 표시형식: 숫자.숫자 또는 숫자.숫자 + D 또는 d (자바에선 실수형의 기본형이 더블이라 숫자만 해도 된다.)
// 15자리의 정밀도를 가진다.
double d1 = 1.1;
double d2 = 1.1234214131242111d;
System.out.println("double 1.1 : " + d1);
System.out.println("double double d2 = 1.1234214131242111 : " + d2);
double sum = d1 + d2;
System.out.println("d1 + d2 : " + sum);
System.out.println("3.4d + 3.2d : " + (3.4d + 3.2d));
System.out.println("---double 최소값 / 최대값 ---");
System.out.println("double 최소값 : " + Double.MIN_VALUE);
System.out.println("double 최대값 : " + Double.MAX_VALUE);
}
}
double 데이터 유형: double 유형은 약 4.9E-324에서 1.7976931348623157E308의 범위를 가질 수 있는 8바이트 실수형 데이터 유형이다. 이 큰 범위와 높은 정밀도 때문에 double은 과학적 계산이나 정밀한 실수 계산에 널리 사용된다.
리터럴 표기법: double 유형의 리터럴은 숫자 뒤에 d 또는 D를 붙여서 표현할 수 있다. 하지만, double이 Java에서 실수형 리터럴의 기본 유형이므로, d나 D를 생략해도 double 유형으로 인식된다. 예를 들어, 1.1 또는 1.1234214131242111d와 같이 작성할 수 있다.
Java에서 double 데이터 유형의 정확도는 대략 소수점 이하 15-16자리까지이다. double은 64비트(8바이트) 실수형 데이터 유형으로, 이중 정밀도 부동소수점 수를 나타낸다. 이 정밀도는 대체로 대부분의 계산에 충분하지만, 매우 높은 정밀도가 요구되는 경우에는 주의가 필요하다.

Java에서 논리연산자는 주로 불리언(boolean) 표현식들을 결합하는 데 사용된다. 이 연산자들은 조건문과 루프에서 특히 유용하며, 복잡한 조건을 평가하는 데 사용됩니다. 주요 논리연산자는 다음과 같다.
논리연산자들은 다음과 같은 특성을 가지고 있다.
public class Ex01_plusplus {
public static void main(String[] args) {
// 증감연산자: ++, --
// 사용형태 : ++변수명, 변수명++, --변수명, 변수명--
// ++: 값을 1 증가 시킴
// --: 값을 1 감소 시킴
int num = 100;
System.out.println("num : " + num);
num = num + 1; // 101
System.out.println("num = num + 1 : " + num);
System.out.println("--------------------------");
// ++, -- 연산자 단독 사용시 항상 1증가 또는 감소
num = 100; // 다시 값 초기화
System.out.println("num : " + num);
num++;
System.out.println("num++ : " + num);
System.out.println("===========================");
// ++, -- 연산자가 연산식에 사용되는 경우
// ++변수명 : 변수값이 1증가된 상태에서 연산에 사용됨
// 변수명++: 변수값이 연산에 사용되고 그 후에 변수값이 1 증가됨
int sum = 0;
num = 100;
System.out.println("num : " + num);
sum = num++ + 5;
System.out.println("num++ + 5 : " + sum); // 105
System.out.println("num : " + num);
}
}
public class Ex02_gt_lt {
public static void main(String[] args) {
// 비교연산자 : >, <, >= (크거나 같다), <= (작거나 같다)
// == (같다, 동일하다), != (같지않다, 다르다)
// 비교연산의 결과 값: true, false
int num1 = 30;
int num2 = 20;
// num > num2 : ???
System.out.println(num1 > num2); // true
System.out.println(num1 + " > " + num2 + " : " + (num1 > num2)); // 30 > 20 : true
System.out.println(num1 + " < " + num2 + " : " + (num1 < num2)); // 30 < 20 : false
System.out.println(num1 + " >= " + num2 + " : " + (num1 >= num2)); // 30 >= 20 : true
System.out.println(num1 + " <= " + num2 + " : " + (num1 <= num2)); // 30 <= 20 : false
System.out.println(num1 + " == " + num2 + " : " + (num1 == num2)); // 30 == 20 : false
System.out.println(num1 + " != " + num2 + " : " + (num1 != num2)); // 30 != 20 : true
System.out.println("======================");
// !: 부정처리(Not)
// !true ===> false, !false ===> true
boolean power = true; // 전원이 켜짐
System.out.println("power : " + power); // power : true
power = !power; // 현재 저장된 값이 아닌 값(부정처리)
System.out.println("power : " + power); // power : false
System.out.println("-------------------");
if (power) { //power 가 true일 때 실행
System.out.println("power 값이 true: 전원 ON 상태입니다"); //
}
else if (!power) {
System.out.println("power 값이 false: 전원 OFF 상태입니다"); // power 값이 false: 전원 OFF 상태입니다
}
}
}
public class Ex03_AND_OR_NOT {
public static void main(String[] args) {
// 논리연산자 : && (AND), || (OR), ! (NOT)
// 논리연산자(&&, ||)의 좌, 우에는 true, false값이 와야한다. (숫자나 문자 같은 값은 안된다.)
System.out.println("----- && (AND) -----");
// 양쪽 다 true여야지 true가 출력된다.
System.out.println("true && true : " + (true && true)); // true
System.out.println("true && false : " + (true && false)); // false
System.out.println("true && true : " + (false && true)); // false
System.out.println("true && true : " + (false && false)); // false
System.out.println("---------------------");
int num1 = 10;
int num2 = 20;
boolean bool1 = true;
boolean bool2 = false;
System.out.println(bool1 + "&&" + bool2 + " : " + (bool1 && bool2));
System.out.println("---------------------");
// (num1 > num2) && bool1 : ??
boolean result = (num1 > num2) && bool1;
System.out.println("(num1 > num2) && bool1 : " + result); // (num1 > num2) && bool1 : false
System.out.println("======== || (OR) ========");
System.out.println("false || true : " + (false || true)); // false || true : true
result = (num1 > num2) || bool1;
System.out.println(num1 + " > " + num2 + " || " + bool1 + " : " + result); // 10 > 20 || true : true
System.out.println("======== ! (NOT) ========");
result = !(num1 > num2 || bool1);
System.out.println("!(num1 > num2 || bool1) : " + result); // !(num1 > num2 || bool1) : false
}
}
public class EX04_plusEqual {
public static void main(String[] args) {
// 대입연산자: =, +=, -=, *=, /=, %=
// 예) num += 2; -------> num = num + 2;
int result = 0;
System.out.println("result : " + result); // result : 0
result += 35; // result = result + 15;
System.out.println("---- -=연산 ----");
System.out.println("result: " + result); // result: 15
result -= 10; // result = result - 10;
System.out.println("result -= 10 : " + result); // result -= 10 : 5
System.out.println("");
result *= 10;
System.out.println("result *= 10 : " + result); // result *= 10 : 50
System.out.println("");
result /= 130;
System.out.println("result /= 130 : " + result); // result /= 130 : 1
System.out.println("");
result = 10;
System.out.println("result : " + result); // result : 10
result %= 6; // result = result % 6;
System.out.println("result % 6 : " + result); // result % 6 : 4
System.out.println("");
}
}