public Pen(String init_color, int init_price) {
color = init_color;
price = init_price;
System.out.println("생성자를 이용하여 color, price를 초기화");
}
public class PenConstructorExample {
public static void main(String[] args) {
Pen blackPen = new Pen(); // 에러
blackPen.write(1); // 에러
Pen redPen = new Pen("빨간", 900);
redPen.write(2);
}
}
public pen() {}
public class Book {
String title;
String author;
int pageCount;
// 기본 생성자
public Book() {
// 모두 기본값 설정
this.title = "Unknown Title";
this.author = "Unknown Author";
this.pageCount = 0;
}
// 일부 정보만 받는 생성자
public Book(String title, String author) {
this.title = title;
this.author = author;
this.pageCount = 0; // 나머지는 기본값으로 초기화
}
// 모든 정보를 받는 생성자
public Book(String title, String author, int pageCount) {
this.title = title;
this.author = author;
this.pageCount = pageCount;
}
}

public class Student {
private String name;
private int age;
private String major;
// 생성자
public Student(String name, int age, String major) {
this.name = name;
this.age = age;
this.major = major;
}
// 학생 정보 출력 메서드
public void displayStudentInfo() {
System.out.printf("이름 : %s , 나이 : %d , 전공 : %s \n", name, age, major);
}
}
public class StudentTest {
public static void main(String[] args) {
// 객체 생성
Student student1 = new Student("홍길동", 20, "컴퓨터 공학");
Student student2 = new Student("김철수", 22, "전자 공학");
// 학생 정보 출력
System.out.println("첫 번째 학생 정보:");
student1.displayStudentInfo();
System.out.println("\n두 번째 학생 정보:");
student2.displayStudentInfo();
}
}
메서드 중복이란 같은 이름의 메서드를 여러 개 선언할 수 있도록 하는 기능입니다. 단, 매개변수의 타입, 개수, 순서가 달라야 합니다.
public class MyClass {
public void abc(int i, String str) {
System.out.println("정수와 문자열이 입력됨");
}
public void abc(double a, double b) {
System.out.println("부동소수점이 입력됨");
}
public void abc(String str) {
System.out.println("문자열이 입력됨");
}
}
public class OverloadingExample {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.abc(100, "자바"); // 정수와 문자열이 입력됨
obj.abc(3.5, 4.3); // 부동소수점이 입력됨
obj.abc("자바"); // 문자열이 입력됨
obj.abc(100, 200); // abc(double, double) 메서드가 호출됨
}
}
메서드 오버로딩을 활용하면 코드의 가독성과 재사용성이 높아집니다.
매개변수의 개수를 미리 정할 수 없을 때 가변 인자(...)를 사용하여 여러 개의 값을 받을 수 있습니다.
public class Calculator {
public int sum(int... values) { // 가변 인자 사용
int sum = 0;
for (int value : values) {
sum += value;
}
return sum;
}
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println(calc.sum(1, 2, 3, 4, 5)); // 15 출력
}
}
가변 인자 주의사항
sum(int[], int...) 같은 형식은 불가능).public class Logger {
public void log(Object... args) {
String message = (String) args[0];
Exception error = (Exception) args[1];
System.out.println("로그 메시지: " + message);
error.printStackTrace();
}
public static void main(String[] args) {
Logger logger = new Logger();
logger.log("에러 발생!", new RuntimeException("예외 정보"));
}
}
가변 인자 내부에서 형변환을 통해 특정 자료형을 구별하여 사용할 수 있습니다.
제네릭은 타입을 지정하여 코드의 안정성과 재사용성을 높이는 기법입니다.
✅제네릭 없이 사용하는 경우
class Box1 {
private Object value;
public void setValue(Object value) {
this.value = value;
}
public Object getValue() {
return value;
}
}
public class NonGenericExample {
public static void main(String[] args) {
Box1 stringBox = new Box1();
stringBox.setValue("Hello, Java!");
Box1 intBox = new Box1();
intBox.setValue(42);
// 형변환 필요
String stringValue = (String) stringBox.getValue();
int intValue = (int) intBox.getValue();
System.out.println(stringValue + " " + intValue);
}
}
형변환이 필요하여 실수로 잘못된 타입을 할당하면 오류가 발생할 가능성이 높습니다.
✅ 제네릭을 사용하는 경우
class Box2<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
public class GenericExample {
public static void main(String[] args) {
Box2<String> stringBox = new Box2<>();
stringBox.setValue("Hello, Java!");
Box2<Integer> intBox = new Box2<>();
intBox.setValue(42);
// 형변환 불필요
String stringValue = stringBox.getValue();
int intValue = intBox.getValue();
System.out.println(stringValue + " " + intValue);
}
}
제네릭을 사용하면 형변환 없이 안전하게 데이터를 처리할 수 있습니다.
타입 추론이란 컴파일러가 코드 문맥을 통해 타입을 자동으로 결정하는 기능입니다.
제네릭 타입 추론 예제
// 타입 추론 사용 전
List<String> myList = new ArrayList<String>();
// 타입 추론 사용 후 (<> 내부 타입을 생략할 수 있음)
List<String> myList = new ArrayList<>();
var를 활용한 타입 추론 예제
// 올바른 사용
var myVar = "Hello, Java!";
// 오류: 초기화되지 않은 변수는 사용할 수 없음
// var uninitializedVar;
// 잘못된 사용 (var로 선언된 변수는 다른 타입으로 재할당 불가)
var x = 10; // int 타입으로 추론
// x = "Hello"; // 오류 발생
var는 코드 가독성을 위해 특정 상황에서만 사용하는 것이 좋습니다.
람다 표현식에서 타입 추론 예제
// 타입 명시 (사용 전)
MyFunction myFunc = (String s) -> s.length();
// 타입 추론 (사용 후)
MyFunction myFunc = (s) -> s.length();
제네릭의 와일드카드 (? 사용)
public void printBox(Box2<?> box) { // 어떤 타입이든 받을 수 있음
System.out.println(box.getValue());
}
<?>를 사용하면 모든 타입을 받을 수 있어 범용성이 높아집니다.
💡 타입 제한 (extends 활용)
public <T extends Number> void printNumber(T num) {
System.out.println("숫자: " + num);
}
T extends Number를 사용하면 숫자 타입만 허용할 수 있습니다.
import 선언과 패키지import 구문은 다른 패키지의 클래스나 인터페이스를 사용할 때 전체 경로를 반복해서 쓰지 않도록 도와주는 문법입니다.import java.util.ArrayList;
public class MyArrayListExample {
public static void main(String[] args) {
ArrayList<String> myList = new ArrayList<>();
// myList를 이용한 작업 수행
}
}
import java.util.ArrayList;을 사용하면 ArrayList를 전체 패키지 경로 없이 바로 사용할 수 있습니다.import static 선언import static을 사용하면 특정 클래스의 정적(static) 멤버를 직접 참조할 수 있습니다.Math.sqrt를 가져오면 sqrt(값) 형태로 간편하게 사용할 수 있습니다.import static java.lang.Math.sqrt;
public class ImportStaticExample {
public static void main(String[] args) {
double result = sqrt(16.0);
System.out.println("Square root of 16 is: " + result);
}
}
✔️ Math.sqrt(16.0) 대신 sqrt(16.0)만 사용해도 되므로 코드가 더 간결해집니다.
package hello;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
✔️ package hello; 선언을 통해 hello라는 패키지 안에 HelloWorld 클래스를 포함합니다.
| 접근 제한자 | 설명 |
|---|---|
public | 어떤 클래스에서든 접근 가능 |
protected | 동일 패키지 또는 상속받은 클래스에서 접근 가능 |
default (아무것도 안 씀) | 동일 패키지 내에서만 접근 가능 |
private | 해당 클래스 내부에서만 접근 가능 |
package com.example.mypackage;
public class MyClass {
// 패키지 내에서만 접근 가능한 메서드
void packagePrivateMethod() {
System.out.println("패키지 내부에서만 접근 가능");
}
}
package com.example.otherpackage;
import com.example.mypackage.MyClass;
public class AnotherClass {
public static void main(String[] args) {
MyClass myObject = new MyClass();
// myObject.packagePrivateMethod(); // ❌ 컴파일 오류 발생 (다른 패키지에서 접근 불가)
}
}
✔️ packagePrivateMethod()는 default 접근 수준이므로 같은 패키지 내에서만 호출할 수 있습니다.
✔️ 클래스 다이어그램에서는 속성을 필드(변수)로 표현합니다.
public class Car {
String brand; // 자동차 브랜드
int year; // 제조 연도
public Car(String brand, int year) {
this.brand = brand;
this.year = year;
}
}
✔️ Car 클래스는 brand와 year 속성을 갖고 있으며, 자동차의 브랜드와 제조 연도를 나타냅니다.
+---------------------+
| Car |
+---------------------+
| - brand: String |
| - year: int |
+---------------------+
| + Car(brand, year) |
+---------------------+

✔️ Car 클래스에는 brand와 year 속성이 있으며, 생성자를 통해 초기화됩니다.

public class Rectangle {
// 클래스 변수
public static int count = 0;
// 인스턴스 변수
private int width;
private int height;
private double area;
// 생성자
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
this.setArea();
}
// 너비 설정 및 반환 메서드
public void setWidth(int width) {
this.width = width;
setArea();
}
public int getWidth() {
return width;
}
// 높이 설정 및 반환 메서드
public void setHeight(int height) {
this.height = height;
setArea();
}
public int getHeight() {
return height;
}
// 면적 설정 및 반환 메서드
public void setArea() {
this.area = width * height;
}
public double getArea() {
return area;
}
}

public class Customer {
String name;
char gender;
String email;
int birthYear;
public Customer(String name, char gender, String email, int birthYear) {
this.name = name;
this.gender = gender;
this.email = email;
this.birthYear = birthYear;
}
public Customer() {
}
}