회원 정보를 표현하는 가장 기본적인 클래스입니다. 생성자 체이닝과 this의 두 용도를 보여 줍니다.
public class Person {
String name;
int age;
String email;
Person(String name, int age, String email) {
this.name = name; // this.name = 필드, name = 매개변수
this.age = age;
this.email = email;
}
Person(String name, int age) {
this(name, age, "unknown@example.com"); // 3개짜리 생성자에 위임
}
boolean isAdult() {
return age >= 19;
}
Person birthday() { // 자기 자신 반환 → 체이닝 가능
this.age++;
return this;
}
@Override
public String toString() {
return name + "(" + age + ", " + email + ")";
}
public static void main(String[] args) {
Person p1 = new Person("김민수", 18, "[email protected]");
Person p2 = new Person("이서연", 30);
System.out.println(p1); // 출력: 김민수(18, [email protected])
System.out.println(p2); // 출력: 이서연(30, [email protected])
System.out.println(p1.isAdult()); // 출력: false
p1.birthday().birthday(); // 체이닝: 두 살 증가
System.out.println(p1.age + " " + p1.isAdult()); // 출력: 20 true
Person alias = p1; // 주소 복사
alias.name = "김민수(수정)";
System.out.println(p1.name); // 출력: 김민수(수정) — 같은 객체
}
}같은 이름 add가 매개변수에 따라 다르게 동작합니다. 자동 형변환에 의한 선택도 확인합니다.
public class Calculator {
int add(int a, int b) {
System.out.print("[int,int] ");
return a + b;
}
double add(double a, double b) {
System.out.print("[double,double] ");
return a + b;
}
int add(int a, int b, int c) {
System.out.print("[int,int,int] ");
return a + b + c;
}
String add(String a, String b) {
System.out.print("[String,String] ");
return a + b;
}
long add(long a, long b) {
System.out.print("[long,long] ");
return a + b;
}
// 반환 타입만 다른 오버로딩은 불가:
// double add(int a, int b) { ... } → 컴파일 오류: method already defined
public static void main(String[] args) {
Calculator c = new Calculator();
System.out.println(c.add(1, 2)); // 출력: [int,int] 3
System.out.println(c.add(1.5, 2.5)); // 출력: [double,double] 4.0
System.out.println(c.add(1, 2, 3)); // 출력: [int,int,int] 6
System.out.println(c.add("1", "2")); // 출력: [String,String] 12
System.out.println(c.add(1L, 2L)); // 출력: [long,long] 3
System.out.println(c.add(1, 2L)); // 출력: [long,long] 3 (int→long 승격)
System.out.println(c.add(1, 2.0)); // 출력: [double,double] 3.0 (int→double 승격)
}
}static 카운터로 총 주문 수와 다음 ID를 관리하고, static 유틸 메서드로 검증합니다.
public class OrderCounter {
static int totalOrders = 0; // 모든 주문이 공유
static final double TAX_RATE = 0.1; // 상수
long id; // 주문마다 다름
String customer;
int amount;
OrderCounter(String customer, int amount) {
if (!isValidAmount(amount)) {
throw new IllegalArgumentException("금액은 양수여야 합니다: " + amount);
}
totalOrders++; // 공유 카운터 증가
this.id = totalOrders; // 그 값을 내 ID로
this.customer = customer;
this.amount = amount;
}
static boolean isValidAmount(int amount) { // 객체 없이 호출 가능
return amount > 0;
// return this.amount > 0; → 컴파일 오류: static에서 this 불가
}
double amountWithTax() { // 인스턴스 메서드: this.amount 사용
return amount * (1 + TAX_RATE); // static 상수 접근은 OK
}
public static void main(String[] args) {
System.out.println(OrderCounter.isValidAmount(-5)); // 출력: false
System.out.println("생성 전 총주문: " + OrderCounter.totalOrders); // 출력: 생성 전 총주문: 0
OrderCounter a = new OrderCounter("Kim", 10000);
OrderCounter b = new OrderCounter("Lee", 25000);
OrderCounter c = new OrderCounter("Park", 3000);
System.out.println(a.id + " " + b.id + " " + c.id); // 출력: 1 2 3
System.out.println("총주문: " + OrderCounter.totalOrders); // 출력: 총주문: 3
System.out.println(b.amountWithTax()); // 출력: 27500.0
try {
new OrderCounter("Bad", 0);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage()); // 출력: 금액은 양수여야 합니다: 0
}
System.out.println("총주문: " + OrderCounter.totalOrders); // 출력: 총주문: 3 (실패는 안 셈)
}
}원시 타입, 참조의 필드 변경, 참조 재대입 세 가지를 한 번에 비교합니다.
public class CallByValueDemo {
static class Wallet {
int balance;
Wallet(int balance) { this.balance = balance; }
}
static void addTen(int x) {
x += 10;
System.out.println(" 메서드 안 x=" + x);
}
static void deposit(Wallet w, int amount) {
w.balance += amount; // 같은 객체의 필드 변경 → 반영
}
static void replace(Wallet w) {
w = new Wallet(999_999); // 복사본 w만 새 객체를 가리킴
System.out.println(" 메서드 안 balance=" + w.balance);
}
static void swap(Wallet a, Wallet b) { // 자바에서는 이런 swap이 불가능
Wallet tmp = a;
a = b;
b = tmp;
}
public static void main(String[] args) {
int n = 5;
addTen(n); // 출력: 메서드 안 x=15
System.out.println("원시 타입 후: " + n); // 출력: 원시 타입 후: 5
Wallet w = new Wallet(100);
deposit(w, 50);
System.out.println("필드 변경 후: " + w.balance); // 출력: 필드 변경 후: 150
replace(w); // 출력: 메서드 안 balance=999999
System.out.println("재대입 후: " + w.balance); // 출력: 재대입 후: 150
Wallet x = new Wallet(1), y = new Wallet(2);
swap(x, y);
System.out.println("swap 후: " + x.balance + " " + y.balance); // 출력: swap 후: 1 2
}
}Product 객체를 배열로 관리하며, 객체 배열의 칸이 null일 수 있음과 객체 간 협력을 보여 줍니다.
public class Inventory {
static class Product {
String code;
String name;
int stock;
int price;
Product(String code, String name, int stock, int price) {
this.code = code; this.name = name; this.stock = stock; this.price = price;
}
boolean take(int qty) {
if (qty > stock) return false;
stock -= qty;
return true;
}
int value() { return stock * price; }
@Override
public String toString() { return code + " " + name + " x" + stock; }
}
Product[] items = new Product[10]; // null 10칸
int count = 0;
void add(Product p) {
if (count == items.length) {
System.out.println("창고 가득 참");
return;
}
items[count++] = p;
}
Product find(String code) {
for (int i = 0; i < count; i++) { // count까지만 (그 뒤는 null)
if (items[i].code.equals(code)) return items[i];
}
return null;
}
long totalValue() {
long sum = 0;
for (int i = 0; i < count; i++) sum += items[i].value();
return sum;
}
public static void main(String[] args) {
Inventory inv = new Inventory();
inv.add(new Product("A1", "노트북", 5, 1_200_000));
inv.add(new Product("B2", "마우스", 40, 25_000));
inv.add(new Product("C3", "모니터", 8, 350_000));
System.out.println("총 재고 가치: " + inv.totalValue()); // 출력: 총 재고 가치: 9800000
Product p = inv.find("B2");
System.out.println(p.take(15) + " → " + p); // 출력: true → B2 마우스 x25
System.out.println(p.take(30) + " → " + p); // 출력: false → B2 마우스 x25
Product missing = inv.find("Z9");
System.out.println(missing == null ? "없는 상품" : missing.toString()); // 출력: 없는 상품
}
}