
Java는 전 세계적으로 널리 사용되는 객체지향 프로그래밍 언어로, 강력한 플랫폼 독립성과 안정성을 갖추고 있습니다. 다양한 애플리케이션 개발에 활용될 수 있으며, 특히 대규모 웹 애플리케이션, 엔터프라이즈 시스템, 모바일 애플리케이션 등에 강점을 보입니다. 아래는 Java 언어의 주요 특징과 장점에 대한 설명입니다.
Java는 1995년 Sun Microsystems에서 처음 출시되었으며, 현재는 Oracle에서 관리하고 있습니다. Java는 최초 개발 당시 가전제품 및 소형 디바이스를 위한 언어로 설계되었으나, 시간이 흐르면서 다양한 환경에서 널리 사용되는 범용 언어로 발전했습니다.
Java는 강력한 객체지향 프로그래밍 언어로, 안정성과 플랫폼 독립성을 제공하며 다양한 분야에서 널리 사용되고 있습니다. Java를 통해 프로그래밍의 기본 원칙을 배우고, 복잡한 시스템을 개발할 수 있는 능력을 갖출 수 있습니다.
Java 학습을 통해 탄탄한 프로그래밍 기초와 더불어, 다양한 환경에서의 개발 경험을 쌓을 수 있습니다.
Java에서 가장 기본적인 프로그램인 "Hello World"를 작성해 보겠습니다. 이 예제를 통해 Java의 기본 구조와 실행 방법을 이해할 수 있습니다.
아래는 Java로 작성한 "Hello World" 프로그램 코드입니다. HelloWorld.java 파일로 저장합니다.
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
public class HelloWorld: 모든 Java 프로그램은 클래스부터 시작합니다. 여기서 클래스 이름은 HelloWorld이며, 파일 이름도 HelloWorld.java로 저장해야 합니다.public static void main(String[] args): Java 애플리케이션이 실행되는 메인 메서드입니다. 프로그램의 시작점으로, main 메서드가 없으면 Java 프로그램은 실행되지 않습니다.System.out.println("Hello, World!");: System.out.println 메서드를 사용하여 콘솔에 "Hello, World!" 문자열을 출력합니다.컴파일:
javac HelloWorld.javaHelloWorld.class 파일이 생성됩니다.실행:
java HelloWorldHello, World!가 출력되면 성공적으로 프로그램이 실행된 것입니다.Hello, World!
이 "Hello World" 예제는 Java의 기본적인 프로그램 구조와 콘솔 출력 방법을 이해하는 데 도움이 됩니다. Java 개발의 첫걸음으로, 이 프로그램을 직접 작성하고 실행해 보세요.
Java에는 총 8개의 기본 데이터 타입(Primitive Types)이 있습니다. 이 기본 타입들은 메모리에 직접 값을 저장하는 단순한 데이터 값입니다. 각 데이터 타입은 고정된 메모리 크기를 가지며, 특정 범위 내의 값만 저장할 수 있습니다.
byte b = 100;
byte보다 넓은 범위가 필요하지만 int까지는 필요 없는 경우에 사용됩니다.short s = 10000;
int i = 100000;
int 범위를 초과하는 큰 정수 값을 저장할 때 사용합니다. 값 뒤에 L을 붙여 구분합니다.long l = 10000000000L;
f를 붙여 표시합니다.float f = 3.14f;
d를 붙이거나 생략할 수 있습니다.double d = 3.141592653589793;
\u0000 (0) ~ \uffff (65,535)\u0000char c = 'A';
true 또는 falsefalseboolean isJavaFun = true;
| 타입 | 크기 | 기본 값 | 범위 또는 정확도 |
|---|---|---|---|
| byte | 8비트 | 0 | -128 ~ 127 |
| short | 16비트 | 0 | -32,768 ~ 32,767 |
| int | 32비트 | 0 | -2,147,483,648 ~ 2,147,483,647 |
| long | 64비트 | 0L | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
| float | 32비트 | 0.0f | 약 ±3.4 * 10^38 (7자리) |
| double | 64비트 | 0.0d | 약 ±1.7 * 10^308 (15자리) |
| char | 16비트 | \u0000 | \u0000 (0) ~ \uffff (65,535) |
| boolean | 1비트 | false | true 또는 false |
Java의 기본 데이터 타입들은 프로그램이 필요한 자료를 효율적으로 저장하고 처리할 수 있도록 설계되어 있습니다.
Java에서 변수와 상수는 데이터를 저장하고 관리하는 중요한 요소입니다. 변수는 프로그램 실행 중에 값을 변경할 수 있는 반면, 상수는 선언 후 값이 변경되지 않는 특성을 가집니다. 아래는 Java에서 변수와 상수를 정의하고 사용하는 방법입니다.
변수는 데이터를 저장하기 위한 메모리 공간을 의미하며, 변수의 값은 프로그램 실행 중에 변경될 수 있습니다. 변수는 타입, 변수 이름, 값으로 구성됩니다.
변수는 먼저 선언하고, 필요할 때 초기화하여 사용할 수 있습니다.
// 변수를 선언만 하고 값을 넣지 않는다
int number;
// 변수에 값 대입
number = 10;
// 선언과 동시에 초기화
int age = 25;
_(언더스코어) 또는 $ 기호로만 구성할 수 있습니다.static 키워드를 사용하여 선언되며, 클래스에 속하고 모든 객체가 공유합니다.상수는 한번 초기화된 후에는 값을 변경할 수 없는 변수입니다. Java에서 상수는 final 키워드를 사용하여 선언하며, 대문자와 언더스코어를 사용하는 UPPER_CASE 형식으로 이름을 짓는 것이 관례입니다.
final int MAX_VALUE = 100;
final 키워드를 통해 값을 고정시킵니다.static 키워드를 함께 사용하여 모든 객체에서 공유할 수 있도록 설정할 수 있습니다.public class MyClass {
public static final double PI = 3.14159;
}
| 항목 | 변수 | 상수 |
|---|---|---|
| 변경 가능 여부 | 변경 가능 | 변경 불가능 (final로 선언) |
| 키워드 | 없음 | final |
| 사용 예 | int age = 25; | final double PI = 3.14159; |
| 네이밍 규칙 | camelCase | UPPER_CASE |
public class Example {
public static final int MAX_SCORE = 100; // 상수 선언
public static void main(String[] args) {
int score = 90; // 변수 선언 및 초기화
System.out.println("Score: " + score);
System.out.println("Max Score: " + MAX_SCORE);
}
}
위 코드에서 score는 변수로, 프로그램 실행 중 값이 변경될 수 있습니다. 반면 MAX_SCORE는 상수로 final 키워드를 사용하여 선언되었기 때문에 값이 변경되지 않습니다.
Java에서 변수와 상수를 적절히 사용하면 코드의 가독성과 유지보수성이 향상됩니다.
Java에서는 다양한 연산자를 제공하여 변수와 상수에 대해 여러 연산을 수행할 수 있습니다. 주로 사용하는 연산자에는 산술 연산자, 비교 연산자, 논리 연산자, 대입 연산자가 있습니다.
산술 연산자는 수학적 계산을 수행할 때 사용합니다.
| 연산자 | 설명 | 예제 코드 | 결과 |
|---|---|---|---|
+ | 덧셈 | a + b | a와 b의 합 |
- | 뺄셈 | a - b | a에서 b를 뺌 |
* | 곱셈 | a * b | a와 b의 곱 |
/ | 나눗셈 | a / b | a를 b로 나눔 |
% | 나머지 | a % b | a를 b로 나눈 나머지 |
int a = 10;
int b = 3;
System.out.println(a + b); // 13
System.out.println(a - b); // 7
System.out.println(a * b); // 30
System.out.println(a / b); // 3
System.out.println(a % b); // 1
비교 연산자는 두 값을 비교하여 참(true) 또는 거짓(false)을 반환합니다.
| 연산자 | 설명 | 예제 코드 | 결과 |
|---|---|---|---|
== | 같다 | a == b | a와 b가 같으면 true |
!= | 같지 않다 | a != b | a와 b가 다르면 true |
> | 크다 | a > b | a가 b보다 크면 true |
< | 작다 | a < b | a가 b보다 작으면 true |
>= | 크거나 같다 | a >= b | a가 b보다 크거나 같으면 true |
<= | 작거나 같다 | a <= b | a가 b보다 작거나 같으면 true |
int a = 5;
int b = 10;
System.out.println(a == b); // false
System.out.println(a != b); // true
System.out.println(a > b); // false
System.out.println(a < b); // true
System.out.println(a >= b); // false
System.out.println(a <= b); // true
논리 연산자는 주로 조건문에서 사용되며, 여러 조건을 결합할 때 유용합니다.
| 연산자 | 설명 | 예제 코드 | 결과 |
|---|---|---|---|
&& |
논리 AND | (a > b) && (a > c) |
두 조건 모두 참이면 true |
|| |
논리 OR | (a > b) || (a > c) |
둘 중 하나라도 참이면 true |
! |
논리 NOT (부정) | !(a > b) |
조건이 참이면 false, 거짓이면 true |
boolean a = true;
boolean b = false;
System.out.println(a && b); // false
System.out.println(a || b); // true
System.out.println(!a); // false
대입 연산자는 변수에 값을 할당할 때 사용합니다.
| 연산자 | 설명 | 예제 코드 | 결과 |
|---|---|---|---|
= | 대입 | a = 5 | a에 5를 대입 |
+= | 더한 후 대입 | a += 3 | a에 3을 더하고 대입 |
-= | 뺀 후 대입 | a -= 2 | a에서 2를 빼고 대입 |
*= | 곱한 후 대입 | a *= 4 | a에 4를 곱하고 대입 |
/= | 나눈 후 대입 | a /= 2 | a를 2로 나누고 대입 |
%= | 나머지 후 대입 | a %= 3 | a를 3으로 나눈 나머지를 대입 |
int a = 10;
a += 5; // a = a + 5; 결과: 15
a -= 3; // a = a - 3; 결과: 12
a *= 2; // a = a * 2; 결과: 24
a /= 4; // a = a / 4; 결과: 6
a %= 5; // a = a % 5; 결과: 1
증감 연산자는 변수의 값을 1씩 증가시키거나 감소시킬 때 사용합니다.
| 연산자 | 설명 | 예제 코드 | 결과 |
|---|---|---|---|
++ | 1 증가 | a++ | a를 1 증가 |
-- | 1 감소 | a-- | a를 1 감소 |
int a = 10;
System.out.println(a++); // 10 (출력 후 1 증가, a는 11)
System.out.println(++a); // 12 (1 증가 후 출력)
System.out.println(a--); // 12 (출력 후 1 감소, a는 11)
System.out.println(--a); // 10 (1 감소 후 출력)
3항 연산자(ternary operator)는 조건에 따라 다른 값을 선택하는 간단한 방법을 제공합니다. if-else 구문의 축약형으로, 코드가 더 간결해집니다. Java에서 3항 연산자는 다음과 같은 형식을 가집니다.
조건식 ? 참일 때의 값 : 거짓일 때의 값;
true 또는 false로 평가되는 조건식입니다.true일 때 반환되는 값입니다.false일 때 반환되는 값입니다.int a = 10;
int b = 20;
// a가 b보다 크면 "a가 더 큽니다"를, 그렇지 않으면 "b가 더 큽니다"를 출력
String result = (a > b) ? "a가 더 큽니다" : "b가 더 큽니다";
System.out.println(result); // 출력: b가 더 큽니다
3항 연산자를 사용하여 짝수와 홀수를 판별할 수 있습니다.
int number = 7;
String type = (number % 2 == 0) ? "짝수" : "홀수";
System.out.println(type); // 출력: 홀수
3항 연산자는 간단한 조건 분기에서 유용하지만, 조건이 복잡하거나 여러 줄의 코드가 필요할 경우 if-else 구문이 더 적합합니다.
3항 연산자는 코드의 간결함과 효율성을 높여주지만, 가독성을 유지하면서 사용할 수 있는 경우에만 사용하는 것이 좋습니다.
Java의 다양한 연산자를 활용하여 여러 가지 계산 및 조건 처리를 할 수 있습니다. 이러한 연산자들을 잘 이해하고 사용하면 더욱 효과적인 Java 프로그래밍을 할 수 있습니다.
Java에서 조건문은 프로그램의 흐름을 제어하기 위해 사용됩니다. 특정 조건을 평가하고 그 결과에 따라 다른 코드 블록을 실행할 수 있습니다.
if 문은 조건이 true일 때만 특정 코드 블록을 실행합니다.
if (조건식) {
// 조건이 true일 때 실행될 코드
}
예제
int number = 10;
if (number > 5) {
System.out.println("number는 5보다 큽니다.");
}
if-else 문은 조건이 true일 때와 false일 때 각각 다른 코드를 실행합니다.
if (조건식) {
// 조건이 true일 때 실행될 코드
} else {
// 조건이 false일 때 실행될 코드
}
예제
int number = 3;
if (number > 5) {
System.out.println("number는 5보다 큽니다.");
} else {
System.out.println("number는 5보다 작거나 같습니다.");
}
여러 조건을 순차적으로 평가하고, 해당 조건이 true인 블록을 실행합니다.
if (조건식1) {
// 조건식1이 true일 때 실행될 코드
} else if (조건식2) {
// 조건식2가 true일 때 실행될 코드
} else {
// 위 조건이 모두 false일 때 실행될 코드
}
예제
int score = 85;
if (score >= 90) {
System.out.println("A 학점");
} else if (score >= 80) {
System.out.println("B 학점");
} else if (score >= 70) {
System.out.println("C 학점");
} else {
System.out.println("F 학점");
}
switch 문은 하나의 변수 값을 기준으로 여러 경우(case)를 처리합니다. 각 case 블록은 해당 값과 일치할 때 실행됩니다.
switch (표현식) {
case 값1:
// 값1일 때 실행될 코드
break;
case 값2:
// 값2일 때 실행될 코드
break;
default:
// 모든 case에 해당하지 않을 때 실행될 코드
}
예제
int day = 3;
switch (day) {
case 1:
System.out.println("월요일");
break;
case 2:
System.out.println("화요일");
break;
case 3:
System.out.println("수요일");
break;
default:
System.out.println("주말");
}
주의사항
break 키워드는 실행을 종료하고 switch 문 밖으로 빠져나오게 합니다. 생략하면 다음 case까지 실행됩니다.default는 모든 조건에 해당하지 않을 때 실행됩니다.삼항 연산자는 간단한 조건문을 한 줄로 표현할 수 있는 방법입니다.
변수 = (조건식) ? 값1 : 값2;
예제
int number = 10;
String result = (number > 5) ? "크다" : "작다";
System.out.println(result); // 출력: 크다
조건문 안에 또 다른 조건문을 사용하는 방식입니다.
if (조건식1) {
if (조건식2) {
// 조건식1과 조건식2가 모두 true일 때 실행될 코드
}
}
예제
int number = 15;
if (number > 10) {
if (number % 2 == 0) {
System.out.println("10보다 큰 짝수입니다.");
} else {
System.out.println("10보다 큰 홀수입니다.");
}
}
&& (AND), || (OR) 연산자를 적절히 활용합니다.if (age >= 18 && age <= 65) {
System.out.println("성인입니다.");
}
이와 같이 Java 조건문은 다양한 방식으로 활용 가능하며, 코드의 흐름을 유연하게 제어할 수 있습니다.
Java에서 반복문은 특정 조건이 충족될 때까지 코드 블록을 반복 실행하는 구조를 제공합니다. 반복문을 사용하여 동일한 작업을 여러 번 수행할 수 있습니다.
for 문은 반복 횟수가 명확할 때 사용됩니다. 초기화, 조건식, 증감식을 통해 반복을 제어합니다.
for (초기화; 조건식; 증감식) {
// 반복할 코드
}
예제
for (int i = 0; i < 5; i++) {
System.out.println("i의 값: " + i);
}
확장 for 문은 배열이나 컬렉션 같은 데이터 구조를 순차적으로 탐색할 때 사용합니다.
for (자료형 변수 : 배열이나 컬렉션) {
// 배열 요소에 대해 반복할 코드
}
예제
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
System.out.println(number);
}
while 문은 조건이 true인 동안 반복을 수행합니다. 조건을 먼저 평가하고, 조건이 참이면 블록을 실행합니다.
while (조건식) {
// 조건이 true일 때 반복할 코드
}
예제
int i = 0;
while (i < 5) {
System.out.println("i의 값: " + i);
i++;
}
do-while 문은 while과 유사하지만, 먼저 블록을 실행한 후 조건을 평가합니다. 따라서 조건이 false라도 최소한 한 번은 실행됩니다.
do {
// 최소 한 번 실행할 코드
} while (조건식);
예제
int i = 0;
do {
System.out.println("i의 값: " + i);
i++;
} while (i < 5);
중첩 반복문이란, 하나의 반복문 안에 또 다른 반복문이 포함된 구조를 말합니다. 이는 주로 2차원 데이터(예: 2D 배열) 처리나 특정 규칙에 따라 반복 작업을 수행할 때 사용됩니다.
중첩 반복문은 외부 루프(Outer Loop)와 내부 루프(Inner Loop)로 구성됩니다. 외부 루프가 한 번 실행될 때마다 내부 루프가 처음부터 끝까지 실행됩니다.
public class NestedLoopExample {
public static void main(String[] args) {
for (int i = 1; i <= 3; i++) { // 외부 루프
System.out.println("외부 루프 i: " + i);
for (int j = 1; j <= 2; j++) { // 내부 루프
System.out.println(" 내부 루프 j: " + j);
}
}
}
}
실행 결과
외부 루프 i: 1
내부 루프 j: 1
내부 루프 j: 2
외부 루프 i: 2
내부 루프 j: 1
내부 루프 j: 2
외부 루프 i: 3
내부 루프 j: 1
내부 루프 j: 2
설명
3 × 2 = 6번 실행됩니다.Java에서는 반복문의 흐름을 제어하기 위한 몇 가지 키워드를 제공합니다.
break 문은 반복문을 즉시 종료합니다.
for (int i = 0; i < 10; i++) {
if (i == 5) {
break; // i가 5일 때 반복 종료
}
System.out.println(i);
}
continue 문은 반복문의 현재 반복을 건너뛰고 다음 반복으로 진행합니다.
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue; // 짝수일 때는 건너뜀
}
System.out.println(i);
}
return 문은 반복문을 포함한 메서드를 종료하고, 해당 메서드의 결과를 반환합니다. 일반적으로 메서드 내에서 사용되며, 반복문을 포함한 코드의 실행을 중단하고 메서드 자체를 종료합니다.
for (int i = 0; i < 10; i++) {
if (i == 5) {
return; // 메서드를 종료하고 반환
}
System.out.println(i);
}
Java에서 무한 루프란, 특정 조건 없이 반복문이 끝없이 실행되는 구조를 말합니다. 이는 의도적으로 작성하거나, 종료 조건을 잘못 설정했을 때 발생할 수 있습니다.
while 문을 사용한 무한 루프public class InfiniteLoop {
public static void main(String[] args) {
while (true) { // 항상 true
System.out.println("무한 루프 실행 중...");
}
}
}
for 문을 사용한 무한 루프public class InfiniteLoop {
public static void main(String[] args) {
for (;;) { // 조건이 없음
System.out.println("무한 루프 실행 중...");
}
}
}
for 문에서 조건식을 생략하면 기본적으로 항상 참으로 간주됩니다.무한 루프는 break 문을 사용하여 제어할 수 있습니다. 특정 조건에서 반복문을 종료하도록 설정할 수 있습니다.
public class InfiniteLoopWithBreak {
public static void main(String[] args) {
int i = 0;
while (true) { // 무한 루프
System.out.println("i 값: " + i);
i++;
if (i >= 5) { // 특정 조건에서 탈출
System.out.println("반복문 종료");
break;
}
}
}
}
실행 결과
i 값: 0
i 값: 1
i 값: 2
i 값: 3
i 값: 4
반복문 종료
이와 같이 Java의 반복문은 다양한 방식으로 사용 가능하며, 반복 작업을 효율적으로 수행할 수 있도록 합니다.
Java에서 배열은 동일한 데이터 타입의 여러 값을 저장할 수 있는 자료 구조입니다. 배열은 고정된 크기를 가지며, 인덱스를 통해 각 요소에 접근할 수 있습니다.
배열의 길이 - 1 인덱스를 가집니다.Java에서는 배열을 선언하고 생성하여 사용할 수 있습니다.
// 1. 배열 선언
데이터타입[] 식별자;
데이터타입 식별자[]; // 이 형식도 가능
// 2. 배열 생성
new 데이터타입[크기];
// 선언과 생성을 동시에
데이터타입[] 식별자 = new 데이터타입[크기];
예제
// size 가 5인 정수형 배열 선언 및 생성
int[] numbers = new int[5];
int numbers2[] = new int[5];
// size 가 5인 문자열 배열 선언 및 생성
String[] names = new String[5];
String names2[] = new String[5];
배열을 생성할 때 각 요소의 값을 초기화할 수 있습니다.
// 배열 생성과 동시에 초기화
int[] numbers = {1, 2, 3, 4, 5};
배열을 생성하고 나서 요소에 값을 할당할 수도 있습니다.
// 0 으로 초기화된 size 가 3인 정수형 배열객체 생성
int[] numbers = new int[3];
// 0 번, 1 번, 2 번 요소에 값을 각각 할당하기
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
배열 요소는 인덱스를 사용하여 접근할 수 있습니다.
int[] numbers = {10, 20, 30, 40, 50};
// 첫 번째 요소에 접근
System.out.println(numbers[0]); // 출력: 10
// 세 번째 요소 변경
numbers[2] = 25;
System.out.println(numbers[2]); // 출력: 25
배열의 길이는 .length 속성을 사용하여 확인할 수 있습니다.
int[] numbers = {10, 20, 30, 40, 50};
System.out.println("배열의 길이: " + numbers.length); // 출력: 5
배열은 반복문을 사용하여 쉽게 순회할 수 있습니다.
for 문을 이용한 배열 순회int[] numbers = {10, 20, 30, 40, 50};
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}
/*
-실행결과
10
20
30
40
50
*/
for 문을 이용한 배열 순회int[] numbers = {10, 20, 30, 40, 50};
for (int number : numbers) {
System.out.println(number);
}
/*
-실행결과
10
20
30
40
50
*/
Java에서는 2차원 이상의 다차원 배열을 생성할 수 있습니다. 2차원 배열은 행과 열로 이루어진 배열이며, 주로 테이블 형식의 데이터를 표현할 때 사용됩니다.
// 2차원 배열 선언 및 생성
int[][] matrix = new int[3][3];
// 2차원 배열 초기화
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 2차원 배열 요소 접근
System.out.println(matrix[0][1]); // 출력: 2
중첩된 반복문을 사용하여 다차원 배열을 순회할 수 있습니다.
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
Java에서는 java.util.Arrays 클래스를 사용하여 배열 관련 다양한 기능을 제공받을 수 있습니다.
배열 정렬
import java.util.Arrays;
int[] numbers = {5, 3, 1, 4, 2};
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers)); // 출력: [1, 2, 3, 4, 5]
배열을 문자열로 변환
int[] numbers = {1, 2, 3, 4, 5};
System.out.println(Arrays.toString(numbers)); // 출력: [1, 2, 3, 4, 5]
배열의 특정 값 검색
int[] numbers = {1, 2, 3, 4, 5};
int index = Arrays.binarySearch(numbers, 3);
System.out.println("3의 인덱스: " + index); // 정렬된 배열에서 3의 인덱스 출력
0부터 시작하므로 배열의 길이 - 1까지 접근 가능합니다. 범위를 초과하는 인덱스에 접근하면 ArrayIndexOutOfBoundsException이 발생합니다.0, 논리형 배열은 false, 객체형 배열은 null로 초기화됩니다.Java 배열은 고정 크기와 단일 데이터 타입으로 제한되지만, 효율적인 데이터 관리와 처리에 유용하게 사용됩니다. 배열을 활용하여 다양한 데이터 구조와 알고리즘을 구현할 수 있습니다.
Java에서 메소드는 특정 작업을 수행하는 코드 블록입니다. 메소드를 사용하면 코드의 재사용성을 높이고, 프로그램의 구조를 더욱 체계적으로 구성할 수 있습니다. 메소드는 입력값(매개변수)을 받아 처리하고, 결과를 반환할 수도 있습니다.
Java에서 메소드는 다음과 같은 구조로 정의됩니다.
접근지정자 반환타입 메소드이름(매개변수 목록) {
// 메소드의 실행 코드
}
public, private, protected)void로 지정합니다.(int x, int y)){}로 둘러싸인 부분으로, 메소드가 실행할 실제 코드입니다.public int add(int a, int b) {
int result = a + b;
return result;
}
위 예제는 두 개의
int매개변수를 받아 그 합을 반환하는add메소드를 정의합니다.
정의된 메소드는 메소드 이름을 통해 호출할 수 있습니다. 호출 시에는 메소드에 정의된 매개변수의 타입과 순서에 맞게 값을 전달해야 합니다.
메소드이름(인수);
public class Calculator {
// 메소드 정의
public int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
Calculator calc = new Calculator();
// 메소드 호출
int result = calc.add(5, 3);
System.out.println("결과: " + result); // 출력: 결과: 8
}
}
메소드는 return 키워드를 사용하여 결과를 호출한 위치로 반환할 수 있습니다. 반환값의 타입은 메소드의 반환타입과 일치해야 합니다.
public int multiply(int a, int b) {
return a * b;
}
void)public void printMessage() {
System.out.println("Hello, World!");
}
메소드에 전달되는 값을 매개변수(parameter)라고 합니다. 메소드를 호출할 때 전달하는 실제 값을 인수(argument)라고 합니다.
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
public static void main(String[] args) {
greet("Alice"); // 출력: Hello, Alice!
}
위 예제에서 greet 메소드는 name이라는 문자열 매개변수를 받아, 인사 메시지를 출력합니다.
Java에서는 같은 이름의 메소드를 여러 개 정의할 수 있습니다. 이를 메소드 오버로딩이라 하며, 매개변수의 타입이나 개수가 다를 때 유효합니다.
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
위 예제에서는 add 메소드를 두 개 정의하였고, 하나는 int 타입, 다른 하나는 double 타입 매개변수를 받습니다. 호출 시 전달되는 인수의 타입에 따라 알맞은 메소드가 실행됩니다.
Java에서 메소드는 접근제어자를 통해 외부 접근을 제한할 수 있습니다.
public class MyClass {
public void publicMethod() {
System.out.println("Public Method");
}
private void privateMethod() {
System.out.println("Private Method");
}
protected void protectedMethod() {
System.out.println("Protected Method");
}
void defaultMethod() {
System.out.println("Default Method");
}
}
Java에서는 메소드를
static으로 선언할 수 있습니다.static메소드와 일반 메소드는 몇 가지 차이점이 있으며, 사용되는 목적과 방식이 다릅니다.
static 메소드는 클래스 레벨에서 호출할 수 있는 메소드입니다. 객체를 생성하지 않고도 클래스 이름으로 직접 호출할 수 있습니다. static 메소드는 일반적으로 유틸리티 메소드나 특정 작업을 수행하기 위한 메소드로 사용됩니다.
static 메소드에서는 클래스의 인스턴스 변수에 접근할 수 없습니다. static 변수나 static 메소드에만 접근할 수 있습니다.static 메소드 내에서는 this 키워드를 사용할 수 없습니다. this는 인스턴스를 가리키는데, static 메소드는 클래스 레벨에서 존재하기 때문에 인스턴스가 없습니다.public class MathUtils {
// static 메소드
public static int add(int a, int b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
// 객체 생성 없이 클래스 이름으로 호출
int result = MathUtils.add(5, 3);
System.out.println("결과: " + result); // 출력: 결과: 8
}
}
일반 메소드는 객체 인스턴스에서 호출되는 메소드입니다. 일반 메소드는 static 키워드가 없으며, 클래스의 인스턴스를 생성한 후 인스턴스 변수와 인스턴스 메소드에 접근할 수 있습니다.
this 키워드를 사용하여 현재 객체를 참조할 수 있습니다.public class Calculator {
// 인스턴스 변수
private int value;
// 생성자
public Calculator(int value) {
this.value = value;
}
// 일반 메소드
public int multiply(int factor) {
return this.value * factor;
}
}
public class Main {
public static void main(String[] args) {
// 객체 생성 후 메소드 호출
Calculator calc = new Calculator(10);
int result = calc.multiply(5);
System.out.println("결과: " + result); // 출력: 결과: 50
}
}
| 비교 항목 | Static 메소드 | 일반 메소드 |
|---|---|---|
| 호출 방식 | 클래스 이름으로 호출 (ClassName.method()) | 객체 인스턴스에서 호출 (instance.method()) |
| 인스턴스 변수 접근 | 불가능 (static 변수만 접근 가능) | 가능 |
| this 키워드 사용 | 불가능 (this는 인스턴스에 대한 참조이므로) | 가능 (현재 인스턴스에 대한 참조) |
| 주요 용도 | 유틸리티 메소드, 객체와 무관한 작업 수행 | 인스턴스 변수나 인스턴스 메소드와 관련된 작업 수행 |
| 객체 생성 여부 | 필요 없음 | 객체 생성 필요 |
Static 메소드에서는 인스턴스 변수나 일반 메소드에 접근할 수 없기 때문에, 인스턴스와 독립적인 작업을 수행해야 합니다.
일반 메소드는 인스턴스가 필요하므로, 인스턴스 변수와 인스턴스 메소드에 자유롭게 접근할 수 있습니다.
과도한static메소드 사용은 객체 지향 설계 원칙을 해칠 수 있으므로, 객체의 상태나 행동과 관련된 작업은 일반 메소드로 정의하는 것이 좋습니다.
void가 아닌 경우 반드시 return 문을 사용해야 합니다.Java에서 메소드는 프로그램의 가독성을 높이고 유지보수를 쉽게 해주는 중요한 요소입니다. 메소드의 정의와 호출을 이해함으로써 보다 효율적이고 체계적인 코드를 작성할 수 있습니다.
Java에서 클래스와 객체는 객체 지향 프로그래밍(Object-Oriented Programming, OOP)의 핵심 요소입니다. 클래스를 통해 객체를 생성하고, 객체는 프로그램 내에서 데이터를 저장하고 행동을 정의하는 역할을 합니다.
클래스는 객체를 생성하기 위한 청사진(설계도)입니다. 클래스는 속성(필드)과 동작(메소드)을 포함할 수 있습니다. 하나의 클래스는 여러 객체를 생성하는 데 사용될 수 있으며, 각 객체는 고유한 상태를 가질 수 있습니다.
Java에서 클래스는 class 키워드를 사용하여 정의합니다.
public class 클래스이름 {
// 필드 (속성)
데이터타입 변수이름;
// 생성자
public 클래스이름() {
// 생성자 코드
}
// 메소드 (동작)
반환타입 메소드이름() {
// 메소드 코드
}
}
가상의 Car 클래스 정의해 보기
public class Car {
// 필드 (속성)
String color;
int speed;
// 생성자
public Car(String color, int speed) {
this.color = color;
this.speed = speed;
}
// 메소드 (동작)
public void accelerate() {
speed += 10;
System.out.println("현재 속도: " + speed);
}
}
위 예제에서 Car 클래스는 color와 speed라는 두 개의 속성을 가지고 있으며, accelerate() 메소드를 통해 속도를 증가시킵니다.
객체는 클래스로부터 생성된 인스턴스(instance)입니다. 클래스가 설계도라면, 객체는 그 설계도로 만들어진 실제 사물에 해당합니다. 객체는 클래스의 속성과 동작을 가지며, 실제 데이터를 저장하고 메소드를 통해 행동을 수행합니다.
Java에서 객체는 new 키워드를 사용하여 아래와 같은 형식으로 생성합니다.
new 클래스명(생성자에 전달할 값);
public class Main {
public static void main(String[] args) {
// Car 클래스의 객체 생성
Car myCar = new Car("빨간색", 0);
// 객체의 속성과 메소드 사용
System.out.println("색상: " + myCar.color);
myCar.accelerate();
}
}
위 예제에서는 Car 클래스의 객체 myCar를 생성하여, color 속성을 출력하고 accelerate() 메소드를 호출하여 속도를 증가시킵니다.
필드는 클래스의 속성을 나타내는 변수입니다. 필드는 클래스 내에서 선언되며, 객체의 상태를 저장하는 역할을 합니다.
public class Car {
String color; // 필드
int speed; // 필드
}
생성자는 클래스의 인스턴스를 생성할 때 호출되는 특별한 메소드입니다. 생성자는 클래스 이름과 동일해야 하며, 반환 타입이 없습니다. 생성자를 통해 객체의 초기 상태를 설정할 수 있습니다.
public class Car {
String color;
int speed;
// 생성자
public Car(String color, int speed) {
this.color = color;
this.speed = speed;
}
}
메소드는 객체의 동작을 정의합니다. 메소드는 객체의 상태를 변경하거나 특정 작업을 수행할 수 있습니다.
public class Car {
int speed;
// 메소드
public void accelerate() {
speed += 10;
}
}
// Dog 클래스를 정의하고
public class Dog {
// 필드
String name;
int age;
// 생성자
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
// 메소드
public void bark() {
System.out.println(name + "가 멍멍 짖습니다.");
}
}
public class Main {
public static void main(String[] args) {
// 정의된 Dog 클래스로 객체 생성
Dog myDog = new Dog("바둑이", 3);
// 객체의 속성 사용
System.out.println("이름: " + myDog.name);
System.out.println("나이: " + myDog.age);
// 객체의 메소드 호출
myDog.bark(); // 출력: 바둑이가 멍멍 짖습니다.
}
}
위 예제에서는 Dog 클래스를 정의하고, name과 age라는 필드를 가집니다. bark() 메소드를 통해 개가 짖는 동작을 정의하고 있습니다.
Java에서 생성자와
this키워드는 객체 지향 프로그래밍의 중요한 개념입니다. 생성자는 객체가 생성될 때 호출되며,this키워드는 객체 자기 자신을 참조하는 데 사용됩니다. 이 두 가지를 이해하면 클래스의 객체를 더 효율적으로 생성하고 관리할 수 있습니다.
생성자는 객체가 생성될 때 호출되는 특별한 메소드입니다. 생성자는 객체의 초기 상태를 설정하는 데 사용되며, 클래스 이름과 동일한 이름을 가지고 반환 타입이 없습니다.
new 키워드를 통해 객체가 생성될 때 자동으로 호출됩니다.public class 클래스이름 {
// 생성자
public 클래스이름() {
// 초기화 코드
}
}
예제
public class Car {
String color;
int speed;
// 생성자
public Car(String color, int speed) {
this.color = color;
this.speed = speed;
}
}
위 예제에서는 Car 클래스의 생성자가 color와 speed를 초기화하는 역할을 합니다.
Default 생성자는 매개변수가 없는 생성자입니다. 클래스를 정의할 때 생성자를 따로 정의하지 않으면 컴파일러가 자동으로 기본 생성자를 추가합니다.
public class Car {
String color;
int speed;
// 기본 생성자
public Car() {
color = "검정색";
speed = 0;
}
}
위 예제에서는 Car 클래스에 매개변수가 없는 기본 생성자를 정의하여, color와 speed 필드의 초기값을 설정합니다.
this키워드는 현재 객체 자신을 참조하는 키워드입니다. 객체의 필드와 메소드에 접근할 때 주로 사용되며, 특히 생성자나 메소드에서 매개변수와 필드 이름이 동일할 때 유용합니다.
this 키워드를 사용하여 인스턴스 변수를 참조할 수 있습니다.this() 구문을 사용합니다. 이를 생성자 오버로딩이라고 합니다.this 키워드를 사용하여 인스턴스 변수와 매개변수 구분하기
public class Car {
String color;
int speed;
// 생성자
public Car(String color, int speed) {
this.color = color; // this.color는 인스턴스 변수, color는 매개변수
this.speed = speed; // this.speed는 인스턴스 변수, speed는 매개변수
}
}
위 예제에서 this.color와 this.speed는 인스턴스 변수를 참조하며, color와 speed는 생성자의 매개변수를 나타냅니다.
this()를 사용한 생성자 오버로딩
this()를 사용하여 하나의 생성자에서 다른 생성자를 호출할 수 있습니다.public class Car {
String color;
int speed;
// 기본 생성자
public Car() {
this("검정색", 0); // 다른 생성자를 호출
}
// 매개변수가 있는 생성자
public Car(String color, int speed) {
this.color = color;
this.speed = speed;
}
}
위 예제에서 Car() 생성자는 this("검정색", 0); 구문을 통해 Car(String color, int speed) 생성자를 호출합니다. 이렇게 하면 코드 중복을 줄일 수 있습니다.
this 키워드를 사용하여 현재 객체 반환
this를 반환하여 메소드 체이닝(method chaining)을 구현할 수 있습니다.public class Car {
String color;
int speed;
public Car setColor(String color) {
this.color = color;
return this; // 현재 객체 반환
}
public Car setSpeed(int speed) {
this.speed = speed;
return this; // 현재 객체 반환
}
}
public class Main {
public static void main(String[] args) {
Car myCar = new Car();
// 메소드 체이닝
myCar.setColor("빨간색").setSpeed(100);
}
}
위 예제에서 setColor()와 setSpeed() 메소드는 this를 반환하여 메소드 체이닝을 가능하게 합니다.
Java의 생성자와
this키워드는 객체 초기화와 클래스 내에서의 코드 재사용성을 높이는 데 중요한 역할을 합니다. 이 개념을 잘 활용하면 보다 효율적이고 유지보수하기 쉬운 코드를 작성할 수 있습니다.
Java에서 접근 지정자는 클래스, 메소드, 변수 등에 대한 접근 범위를 설정하는 키워드입니다. 접근 지정자를 사용하면 클래스 외부에서 접근할 수 있는 범위를 제어할 수 있으며, 캡슐화와 데이터 보호에 중요한 역할을 합니다.
Java에는 네 가지 주요 접근 지정자가 있습니다: public, protected, default (아무것도 지정하지 않을 때), private. 각각의 접근 지정자는 접근 가능한 범위가 다릅니다.
| 접근 지정자 | 같은 클래스 | 같은 패키지 | 하위 클래스 | 모든 클래스 |
|---|---|---|---|---|
public | 가능 | 가능 | 가능 | 가능 |
protected | 가능 | 가능 | 가능 | 불가능 |
default | 가능 | 가능 | 불가능 | 불가능 |
private | 가능 | 불가능 | 불가능 | 불가능 |
public 접근 지정자는 모든 클래스에서 접근할 수 있도록 허용합니다. 클래스, 메소드, 필드에 public 접근 지정자를 사용할 수 있으며, 이를 사용하면 어느 패키지에서나 접근이 가능합니다.
예제
public class Car {
public String color;
public void drive() {
System.out.println("Driving...");
}
}
위 예제에서 color 필드와 drive() 메소드는 public 접근 지정자가 있어 모든 클래스에서 접근 가능합니다.
protected 접근 지정자는 같은 패키지 내의 클래스와 다른 패키지의 하위 클래스에서 접근할 수 있도록 허용합니다. 주로 상속 관계에서 사용됩니다.
예제
public class Animal {
protected String name;
protected void makeSound() {
System.out.println("Some sound...");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println(name + "가 멍멍 짖습니다.");
}
}
위 예제에서 name 필드와 makeSound() 메소드는 protected 접근 지정자로 선언되어, Animal 클래스와 같은 패키지 내의 클래스 또는 Animal의 하위 클래스인 Dog에서 접근할 수 있습니다.
default 접근 지정자는 접근 지정자를 명시하지 않은 경우를 의미합니다. default 접근 지정자는 같은 패키지 내에서만 접근이 가능하며, 다른 패키지에서는 접근할 수 없습니다.
class Car {
String color;
void drive() {
System.out.println("Driving...");
}
}
위 예제에서 color 필드와 drive() 메소드는 default 접근 지정자로 선언되어, 같은 패키지 내에서만 접근 가능합니다. 다른 패키지에서는 접근할 수 없습니다.
private 접근 지정자는 같은 클래스 내에서만 접근이 가능하도록 제한합니다. 다른 클래스에서는 접근할 수 없으며, 클래스 내부에서만 사용할 수 있습니다. 주로 데이터 캡슐화와 보안을 위해 사용됩니다.
예제
public class Car {
private String color;
private void startEngine() {
System.out.println("Engine started");
}
public void drive() {
startEngine(); // 같은 클래스 내에서 private 메소드 호출
System.out.println("Driving...");
}
}
위 예제에서 color 필드와 startEngine() 메소드는 private 접근 지정자로 선언되어, Car 클래스 외부에서는 접근할 수 없습니다. drive() 메소드는 Car 클래스 외부에서 접근할 수 있으며, 클래스 내부에서 startEngine() 메소드를 호출합니다.
다양한 접근 지정자 예제
public class Person {
public String name; // 모든 클래스에서 접근 가능
protected int age; // 같은 패키지와 하위 클래스에서 접근 가능
String address; // 같은 패키지 내에서만 접근 가능 (default)
private String password; // 같은 클래스 내에서만 접근 가능
public Person(String name, int age, String address, String password) {
this.name = name;
this.age = age;
this.address = address;
this.password = password;
}
// password에 대한 getter 메소드
public String getPassword() {
return this.password;
}
}
위 예제에서 name은 public 접근 지정자로 설정되어 모든 클래스에서 접근 가능합니다. age는 protected로 설정되어, 같은 패키지나 하위 클래스에서 접근할 수 있습니다. address는 default 접근 지정자로 설정되어 같은 패키지 내에서만 접근할 수 있습니다. password는 private 접근 지정자로 설정되어, 같은 클래스 내에서만 접근 가능합니다.
private을 사용하여 캡슐화를 강화합니다.public을 사용하지만, 그렇지 않을 경우 protected나 default 접근 지정자를 고려합니다.public으로 설정하면 보안 문제가 발생할 수 있습니다. 가능한 필요한 경우에만 public을 사용하고, 최대한 접근을 제한합니다.Java 접근 지정자는 클래스, 메소드, 필드에 대한 접근 범위를 제어하여 보안을 강화하고 코드를 더 구조화하고 관리하기 쉽게 만듭니다. 적절한 접근 지정자를 사용하여 프로그램의 안전성과 캡슐화를 높이는 것이 중요합니다.
개념
- 상속은 기존 클래스(부모 클래스 또는 슈퍼 클래스)의 속성과 메소드를 새로운 클래스(자식 클래스 또는 서브 클래스)에서 재사용하고 확장하는 개념입니다.
- 코드의 재사용성을 높이고 객체 간 계층 구조를 형성할 때 사용됩니다.
extends 키워드를 사용하여 상속을 선언합니다.class Parent {
String name;
public void display() {
System.out.println("This is the parent class.");
}
}
class Child extends Parent {
public void showName() {
System.out.println("Name: " + name);
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.name = "John"; // 부모 클래스의 멤버 사용
child.display(); // 부모 클래스의 메소드 호출
child.showName();
}
}
개념
- 오버라이딩은 자식 클래스에서 부모 클래스의 메소드를 재정의하여 새로운 동작을 제공하는 기능입니다.
- 메소드 이름, 매개변수, 반환 타입이 부모 클래스의 메소드와 동일해야 합니다.
@Override 어노테이션을 사용하여 재정의합니다.class Parent {
public void display() {
System.out.println("This is the parent class.");
}
}
class Child extends Parent {
@Override
public void display() {
System.out.println("This is the child class.");
}
}
public class Main {
public static void main(String[] args) {
Parent parent = new Child();
parent.display(); // "This is the child class." 출력
}
}
개념
- 다형성은 같은 타입의 참조 변수로 여러 다른 객체를 참조할 수 있는 능력을 의미합니다.
- 런타임 시점에서 실행되는 메소드가 결정됩니다.
ClassCastException을 발생시킬 수 있습니다.예제 코드
class Animal {
public void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
// Upcasting
Animal animal = new Dog();
animal.sound(); // "Dog barks" 출력
// Downcasting
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.sound(); // "Dog barks" 출력
}
}
}
추상 클래스 (Abstract Class)
- 인스턴스화할 수 없는 클래스입니다.
- 추상 메소드(구현되지 않은 메소드)를 포함할 수 있습니다.
abstract키워드로 선언됩니다.
extends 키워드 사용.abstract class Animal {
public abstract void sound(); // 추상 메소드
public void sleep() { // 일반 메소드
System.out.println("Sleeping...");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();
animal.sound(); // "Dog barks" 출력
animal.sleep(); // "Sleeping..." 출력
}
}
인터페이스 (Interface)
- 클래스가 구현해야 하는 메소드의 집합입니다.
interface키워드로 선언됩니다.- 모든 메소드는 기본적으로 추상적이고 public입니다.
implements 키워드로 구현합니다.interface Animal {
void sound(); // 추상 메소드
default void sleep() { // 디폴트 메소드
System.out.println("Sleeping...");
}
}
class Dog implements Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();
animal.sound(); // "Dog barks" 출력
animal.sleep(); // "Sleeping..." 출력
}
}
상속, 오버라이딩, 다형성, 추상클래스와 인터페이스는 Java의 객체지향 프로그래밍(OOP)에서 핵심적인 역할을 하며, 실무 및 인터뷰에서도 자주 등장하는 주제입니다.
체크 예외 (Checked Exception)
IOException, SQLException 등 파일 입출력이나 데이터베이스 작업에서 자주 발생.try-catch 구문 또는 throws 키워드로 처리해야 함.비체크 예외 (Unchecked Exception)
NullPointerException, ArrayIndexOutOfBoundsException 등 프로그래머의 실수로 인해 발생.에러 (Error)
OutOfMemoryError, StackOverflowError 등.try-catch 구문과 예외 처리 방법
try-catch구문
- 예외 발생 가능성이 있는 코드를
try블록에 작성합니다.- 예외가 발생하면
catch블록에서 해당 예외를 처리합니다.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
try {
// 예외 발생 가능성 있는 코드
File file = new File("example.txt");
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException e) {
// 예외 처리
System.out.println("File not found: " + e.getMessage());
}
}
}
try 블록에 여러 개의 catch 블록을 작성할 수 있습니다.finally 블록개념
finally블록은 예외 발생 여부와 상관없이 항상 실행되는 블록입니다.- 자원을 해제하거나 정리(clean-up) 작업을 수행할 때 사용됩니다.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = null;
try {
File file = new File("example.txt");
scanner = new Scanner(file);
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
} finally {
// 자원 정리
if (scanner != null) {
scanner.close();
System.out.println("Scanner closed.");
}
}
}
}
finally는 예외가 발생하든 발생하지 않든 실행됩니다.catch에서 처리되지 않고 다시 던져질 경우에도 finally는 실행됩니다.개념
- Java에서 사용자가 직접 예외 클래스를 정의할 수 있습니다.
- 사용자 정의 예외는 기존 예외 클래스를 상속받아 구현됩니다.
- 일반적으로 체크 예외로 사용하려면
Exception을, 비체크 예외로 사용하려면RuntimeException을 상속받습니다.
// 사용자 정의 예외 클래스
class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
public class Main {
public static void main(String[] args) {
try {
validateAge(15); // 유효하지 않은 나이
} catch (CustomException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
// 사용자 정의 예외를 던지는 메소드
public static void validateAge(int age) throws CustomException {
if (age < 18) {
throw new CustomException("Age must be at least 18.");
}
}
}
throw 키워드로 예외를 던지고, throws 키워드로 호출자에게 예외를 전달합니다.위에서 언급한 네 가지 예외 처리 개념은 Java에서 안정적이고 유지보수 가능한 프로그램을 작성하는 데 매우 중요한 요소입니다.
Generic 클래스는 데이터 타입을 일반화하여 다양한 타입의 객체를 처리할 수 있도록 설계된 클래스입니다.
클래스 내부에서 사용할 데이터 타입을 컴파일 시점에 지정합니다.
타입 안정성을 보장하고, 코드 중복을 줄이며, 재사용성을 높이는 데 도움을 줍니다.
<T>와 같은 타입 매개변수를 사용합니다.T는 일반적으로 Type을 의미하며, 다른 이름(E, K, V, 등)을 사용할 수도 있습니다.만드는 방법
class GenericClass<T> { // T는 타입 매개변수
private T data;
public GenericClass(T data) {
this.data = data;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
사용 방법
public class Main {
public static void main(String[] args) {
// Integer 타입으로 제네릭 클래스 사용
GenericClass<Integer> intObj = new GenericClass<>(100);
System.out.println("Integer Value: " + intObj.getData()); // 100
// String 타입으로 제네릭 클래스 사용
GenericClass<String> strObj = new GenericClass<>("Hello");
System.out.println("String Value: " + strObj.getData()); // Hello
}
}
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
public class Main {
public static void main(String[] args) {
Pair<String, Integer> pair = new Pair<>("Age", 30);
System.out.println("Key: " + pair.getKey()); // Key: Age
System.out.println("Value: " + pair.getValue()); // Value: 30
}
}
class Box<T extends Number> { // Number의 하위 클래스만 허용
private T data;
public Box(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
public class Main {
public static void main(String[] args) {
Box<Integer> intBox = new Box<>(10); // Integer는 Number의 하위 클래스
Box<Double> doubleBox = new Box<>(5.5); // Double도 가능
// Box<String> strBox = new Box<>("Hello"); // 컴파일 오류
System.out.println("Integer Box: " + intBox.getData()); // 10
System.out.println("Double Box: " + doubleBox.getData()); // 5.5
}
}
String 클래스
- Java의
String클래스는 문자열을 다룰 수 있는 불변(immutable) 객체를 제공합니다.- 문자열을 한 번 생성하면 그 값을 변경할 수 없습니다.
java.lang.String패키지에 포함되어 있으며, import 없이 사용할 수 있습니다.- 문자열 리터럴로 생성되거나,
new String()생성자를 사용하여 생성됩니다.
public class Main {
public static void main(String[] args) {
// 문자열 리터럴로 생성
String str1 = "Hello";
// new 키워드로 생성
String str2 = new String("World");
System.out.println(str1); // Hello
System.out.println(str2); // World
}
}
length()String str = "Hello World";
System.out.println(str.length()); // 11
charAt(int index)String str = "Hello";
System.out.println(str.charAt(1)); // e
substring(int beginIndex, int endIndex)endIndex는 포함되지 않습니다.String str = "Hello World";
System.out.println(str.substring(0, 5)); // Hello
contains(CharSequence s)String str = "Hello World";
System.out.println(str.contains("World")); // true
System.out.println(str.contains("Java")); // false
equals(Object another)String str1 = "Hello";
String str2 = "Hello";
String str3 = "hello";
System.out.println(str1.equals(str2)); // true
System.out.println(str1.equals(str3)); // false
equalsIgnoreCase(String another)String str1 = "Hello";
String str2 = "hello";
System.out.println(str1.equalsIgnoreCase(str2)); // true
toUpperCase() 와 toLowerCase()String str = "Hello World";
System.out.println(str.toUpperCase()); // HELLO WORLD
System.out.println(str.toLowerCase()); // hello world
indexOf(String s)String str = "Hello World";
System.out.println(str.indexOf("World")); // 6
System.out.println(str.indexOf("Java")); // -1
replace(CharSequence target, CharSequence replacement)String str = "Hello World";
System.out.println(str.replace("World", "Java")); // Hello Java
trim()String str = " Hello World ";
System.out.println(str.trim()); // "Hello World"
split(String regex)String str = "apple,banana,grape";
String[] fruits = str.split(",");
for (String fruit : fruits) {
System.out.println(fruit);
}
// apple
// banana
// grape
startsWith(String prefix) 와 endsWith(String suffix)String str = "Hello World";
System.out.println(str.startsWith("Hello")); // true
System.out.println(str.endsWith("World")); // true
concat(String str)+ 연산자를 사용하는 것과 동일한 효과를 가집니다.String str1 = "Hello";
String str2 = "World";
System.out.println(str1.concat(" ").concat(str2)); // Hello World
isEmpty() / isBlank()isEmpty(): 문자열의 길이가 0인지 확인합니다. isBlank(): 문자열이 비어있거나 공백만 포함되어 있는지 확인합니다. (Java 11+)String str1 = "";
String str2 = " ";
System.out.println(str1.isEmpty()); // true
System.out.println(str2.isEmpty()); // false
System.out.println(str2.isBlank()); // true (Java 11 이상)
join(CharSequence delimiter, CharSequence... elements)Java 8+)String joined = String.join(", ", "apple", "banana", "grape");
System.out.println(joined); // apple, banana, grape
String은 불변(immutable) 객체이기 때문에, 문자열 조작 시 새로운 객체가 생성됩니다.- 문자열을 반복적으로 수정하거나 연결해야 하는 경우
StringBuilder또는StringBuffer를 사용하는 것이 효율적입니다.
StringBuilder 사용StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" My");
sb.append(" World!");
System.out.println(sb.toString()); // Hello My World!
이와 같이
String클래스는 다양한 메소드를 통해 문자열을 효과적으로 다룰 수 있습니다.
- Wrapper 클래스는 기본 데이터 타입(primitive type)을 객체(object)로 변환하기 위한 클래스를 말합니다.
- Java의 모든 기본 데이터 타입(int, double, char 등)에 해당하는 Wrapper 클래스가 존재합니다.
- 기본 타입을 객체로 다룰 수 있게 하여, 컬렉션 프레임워크(
List,Set,Map등)에서 활용하거나, 유틸리티 메소드를 제공받을 수 있습니다.
| 기본 타입 | Wrapper 클래스 |
|---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
Auto-boxing: 기본 타입 → Wrapper 객체로 자동 변환.
Unboxing: Wrapper 객체 → 기본 타입으로 자동 변환.
public class Main {
public static void main(String[] args) {
// Auto-boxing
Integer num = 10; // int → Integer
System.out.println(num); // 10
// Unboxing
int value = num; // Integer → int
System.out.println(value); // 10
}
}
valueOf()public class Main {
public static void main(String[] args) {
Integer intObj = Integer.valueOf(100);
Double doubleObj = Double.valueOf(12.34);
System.out.println(intObj); // 100
System.out.println(doubleObj); // 12.34
}
}
xxxValue()intValue(), doubleValue(), 등)public class Main {
public static void main(String[] args) {
Integer intObj = Integer.valueOf(100);
int intValue = intObj.intValue(); // Integer → int
System.out.println(intValue); // 100
}
}
parseXXX()parseInt(), parseDouble(), 등)public class Main {
public static void main(String[] args) {
int intValue = Integer.parseInt("123");
double doubleValue = Double.parseDouble("45.67");
System.out.println(intValue); // 123
System.out.println(doubleValue); // 45.67
}
}
toString()public class Main {
public static void main(String[] args) {
Integer intObj = Integer.valueOf(100);
String str = intObj.toString();
System.out.println(str); // "100"
}
}
int[] 등의 배열 사용을 고려.결론
Wrapper 클래스는 기본 타입을 객체로 다루어야 하는 상황에서 유용하며, 자바의 컬렉션 프레임워크, 문자열 처리, 데이터 변환 등에 필수적입니다. 하지만 성능 문제를 고려해 적절한 상황에서 사용하는 것이 중요합니다.
ArrayList는 동적 배열을 구현한 Java의 컬렉션 클래스입니다.
순서가 중요한 데이터를 저장할때 사용 합니다.
인덱스를 사용해 요소에 접근할 수 있습니다.
ArrayList 와 제네릭ArrayList는 기본적으로 제네릭 클래스로 설계되어 있으며, 원하는 데이터 타입을 제네릭으로 명시합니다.import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
// String 타입 ArrayList
List<String> stringList = new ArrayList<>();
stringList.add("Apple");
stringList.add("Banana");
// Integer 타입 ArrayList
List<Integer> intList = new ArrayList<>();
intList.add(10);
intList.add(20);
// 데이터 출력
System.out.println(stringList); // [Apple, Banana]
System.out.println(intList); // [10, 20]
}
}
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList list = new ArrayList(); // 제네릭 사용하지 않음
list.add("Apple");
list.add(10); // 서로 다른 타입 추가 가능
// 런타임 시 타입 오류 발생 가능
String fruit = (String) list.get(1); // ClassCastException
}
}
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
// list.add(10); // 컴파일 오류: String만 추가 가능
String fruit = list.get(0); // 형 변환 불필요
System.out.println(fruit); // Apple
}
}
ArrayList 생성 및 초기화import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
// ArrayList 객체를 List 타입으로 받기
List<String> list = new ArrayList<>();
}
}
List<Integer> list = new ArrayList<>(20); // 초기 크기 20
add(E e)List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
System.out.println(list); // [Apple, Banana, Cherry]
get(int index)System.out.println(list.get(1)); // Banana
set(int index, E element)list.set(1, "Blueberry");
System.out.println(list); // [Apple, Blueberry, Cherry]
remove(int index) 와 remove(Object o)list.remove(1); // 인덱스 1의 요소 삭제
list.remove("Cherry"); // 값 "Cherry" 삭제
System.out.println(list); // [Apple]
size()System.out.println(list.size()); // 1
contains(Object o)System.out.println(list.contains("Apple")); // true
System.out.println(list.contains("Mango")); // false
isEmpty()System.out.println(list.isEmpty()); // false
clear()list.clear();
System.out.println(list); // []
addAll(Collection<? extends E> c)List<String> otherList = new ArrayList<>();
otherList.add("Mango");
otherList.add("Grape");
list.addAll(otherList);
System.out.println(list); // [Mango, Grape]
for 루프List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
/*
- 출력결과 -
Apple
Banana
Cherry
*/
for 루프for (String item : list) {
System.out.println(item);
}
/*
- 출력결과 -
Apple
Banana
Cherry
*/
forEach() 메소드 (람다 사용)list.forEach(item -> System.out.println(item));
/*
- 출력결과 -
Apple
Banana
Cherry
*/
HashMap은 Java의 컬렉션 클래스 중 하나로, 키(key)와 값(value) 쌍으로 데이터를 저장합니다.
Map인터페이스를 구현하며, 데이터의 순서를 보장하지 않습니다.
키는 중복을 허용하지 않으며, 각 키는 고유합니다.
값은 중복을 허용합니다.
HashMap 객체는 일반적으로 Map 타입으로 선언하여 생성합니다.import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
// HashMap 객체를 Map 타입으로 선언
Map<String, Integer> map = new HashMap<>();
}
}
HashMap과 GenericsHashMap은 제네릭을 사용하여 키와 값의 타입을 명확히 지정할 수 있습니다.import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
// String 키와 Integer 값을 저장하는 HashMap
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 100);
map.put("Banana", 200);
System.out.println(map); // {Apple=100, Banana=200}
}
}
put(K key, V value)Map<String, Integer> map = new HashMap<>();
map.put("Apple", 100);
map.put("Banana", 200);
map.put("Apple", 150); // 기존 값(100)을 덮어씀
System.out.println(map); // {Apple=150, Banana=200}
get(Object key)null을 반환합니다.System.out.println(map.get("Apple")); // 150
System.out.println(map.get("Cherry")); // null
containsKey(Object key)HashMap에 존재하는지 확인합니다.System.out.println(map.containsKey("Apple")); // true
System.out.println(map.containsKey("Cherry")); // false
containsValue(Object value)HashMap에 존재하는지 확인합니다.System.out.println(map.containsValue(150)); // true
System.out.println(map.containsValue(300)); // false
remove(Object key)map.remove("Apple");
System.out.println(map); // {Banana=200}
size()HashMap에 저장된 키-값 쌍의 개수를 반환합니다.System.out.println(map.size()); // 1
isEmpty()HashMap이 비어 있는지 확인합니다.System.out.println(map.isEmpty()); // false
map.clear(); // 모든 데이터 삭제
System.out.println(map.isEmpty()); // true
keySet()HashMap에 저장된 모든 키를 반환합니다.System.out.println(map.keySet()); // [Banana]
values()HashMap에 저장된 모든 값을 반환합니다.System.out.println(map.values()); // [200]
for-each 반복문for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
forEach() 메소드 (람다 사용)map.forEach((key, value) -> {
System.out.println("Key: " + key + ", Value: " + value);
});
HashSet은 Java의 컬렉션 클래스 중 하나로, 중복을 허용하지 않는 요소들을 저장하는 데 사용됩니다.
Set인터페이스를 구현하며, 요소의 순서를 보장하지 않습니다.
내부적으로 HashMap을 사용하여 데이터를 저장하며, 빠른 검색과 삽입이 가능합니다.
HashSet 객체는 일반적으로 Set 타입으로 선언하여 생성합니다.import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
// HashSet 객체를 Set 타입으로 선언
Set<String> set = new HashSet<>();
}
}
HashSet과 GenericsHashSet은 제네릭을 사용하여 요소의 타입을 명확히 지정할 수 있습니다.import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
// String 타입 요소를 저장하는 HashSet
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
System.out.println(set); // [Apple, Banana]
}
}
add(E e)Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Apple"); // 중복 요소는 무시
System.out.println(set); // [Apple, Banana]
remove(Object o)set.remove("Apple");
System.out.println(set); // [Banana]
contains(Object o)HashSet에 존재하는지 확인합니다.System.out.println(set.contains("Banana")); // true
System.out.println(set.contains("Apple")); // false
size()HashSet에 저장된 요소의 개수를 반환합니다.System.out.println(set.size()); // 1
isEmpty()HashSet이 비어 있는지 확인합니다.System.out.println(set.isEmpty()); // false
set.clear(); // 모든 요소 제거
System.out.println(set.isEmpty()); // true
clear()HashSet의 모든 요소를 제거합니다.set.clear();
System.out.println(set); // []
for 반복문HashSet의 모든 요소를 순회하기 위해 향상된 for 반복문을 사용할 수 있습니다.for (String item : set) {
System.out.println(item);
}
forEach() 메소드 (람다 사용)forEach() 메소드를 사용하면 람다 표현식으로 간결하게 순회할 수 있습니다.set.forEach(item -> System.out.println(item));
Iterator를 이용한 순회Iterator를 사용하면 컬렉션의 요소를 안전하게 반복할 수 있습니다.import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Cherry");
// Iterator를 사용한 순회
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String item = it.next();
// Apple, Banana, Cherry 중에 하나가 무작위로 출력된다.
System.out.println(item);
}
}
HashSet 활용import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
String[] fruits = {"Apple", "Banana", "Apple", "Cherry", "Banana"};
Set<String> uniqueFruits = new HashSet<>();
for (String fruit : fruits) {
uniqueFruits.add(fruit);
}
System.out.println(uniqueFruits); // [Apple, Banana, Cherry]
}
}
HashSet을 사용하여 집합 연산을 수행할 수 있습니다.import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Integer> set1 = new HashSet<>();
set1.add(1);
set1.add(2);
set1.add(3);
Set<Integer> set2 = new HashSet<>();
set2.add(2);
set2.add(3);
set2.add(4);
// 교집합
Set<Integer> intersection = new HashSet<>(set1);
intersection.retainAll(set2);
System.out.println("Intersection: " + intersection); // [2, 3]
// 합집합
Set<Integer> union = new HashSet<>(set1);
union.addAll(set2);
System.out.println("Union: " + union); // [1, 2, 3, 4]
// 차집합
Set<Integer> difference = new HashSet<>(set1);
difference.removeAll(set2);
System.out.println("Difference: " + difference); // [1]
}
}