배열 자체를 넘기면 pass by reference
배열에 있는 요소를 넘기면 pass by value
public class Sample {
public static void changeSomething(int i) {
i++;
}
public static void main(String[] args) {
int[] i = {0};
changeSomething(i[0]);
System.out.println(i[0]);
}
}
>> 0
Enum
Enum 사용 예시
public enum Day {
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
class Date {
int year, month, day;
Day dayofday;
public void setDate(int year, int month, int day, Day dayofday) {
this.year = year;
this.month = month;
this.day = day;
this.dayofday = dayofday;
}
}
class Test {
public static void main(String[] args) {
Date date1 = new Date();
date1.setDate(2025, 1, 14, Day.Tuesday);
Date date2 = new Date();
date2.setDate(2025, 1, 21, Day.Tuesday);
System.out.println(date1.dayofday == date2.dayofday); //true
}
}
enum_method
name 메소드
- name() 메소드는 enum 객체가 가지고 있는 문자열을 return 합니다. 문자열은 enum 타입을 정의할 때 사용한 상수 이름과 동일합니다.
Suit suit = Suit.Spade;
suit.name();
ordinal 메소드
- ordinal() 메소드는 해당 enum 객체가 전체 enum 중 몇 번째 열거 객체인지 알려줍니다. 객체의 순번은 열거 상수의 정의 순서이며, 0에서 시작합니다.
enum Suit {
Spade,
Diamond,
Heart,
Club
}
Suit suit1 = Suit.Spade;
Suit suit2 = Suit.Diamond;
Suit suit3 = Suit.Heart;
Suit suit4 = Suit.Club;
System.out.println(suit1.ordinal()); // 0
System.out.println(suit2.ordinal()); // 1
System.out.println(suit3.ordinal()); // 2
System.out.println(suit4.ordinal()); // 3
compareTo 메소드
- compareTo() 메소드는 메소드 인자로 전달된 enum 타입을 기준으로 전 후로 몇 번째에 위치하는지 비교합니다.
Suit suit1 = Suit.Spade;
Suit suit2 = Suit.Club;
System.out.println(suit1.compareTo(suit2)); // -3
valueOf 메소드
- valueOf() 메소드는 인자로 전달된 문자열과 동일한 문자열을 가지는 enum 객체를 반환합니다.
Suit result = Suit.valueOf("Spade");
result.name(); // Spade
values 메소드
- values() 메소드는 해당 enum에 포함된 모든 열거 객체들을 배열로 만들어 return 합니다.
Suit suit = Suit.Spade;
Suit[] suits = suit.values();
for (Suit suit: suits) {
System.out.println(suit);
}
Enum 생성자
- enum의 각 열거형 상수에 추가 속성 부여
- 이름을 나타내는 상수와 함꼐 추가적인 속성을 사용할 수 있음
- 1생성자 파라미터 순서대로 속성을 부여
- 생성자는 private
- enum 타입은 고정된 상수의 집합으로, 컴파일시에 타입 안정성이 보장되어야 함
- 외부에서 접근 가능한 생성자가 없으므로, 실제로 final과 동일하게 동작
- Singleton을 일반화 함
public enum Day {
Sunday("일요일"),
Monday("월요일"),
Tuesday("화요일"),
Wednesday("수요일"),
Thursday("목요일"),
Friday("금요일"),
Saturday("토요일");
private String korDayName;
private Day(String korDayName) {
this.korDayName = korDayName;
}
public String getKorDayName() {
return this.korDayName;
}
}
class Date {
int year, month, day;
Day dayofday;
public void setDate(int year, int month, int day, Day dayofday) {
this.year = year;
this.month = month;
this.day = day;
this.dayofday = dayofday;
}
}
class Test {
public static void main(String[] args) {
Date date1 = new Date();
date1.setDate(2025, 1, 14, Day.Tuesday);
Date date2 = new Date();
date2.setDate(2025, 1, 21, Day.Tuesday);
System.out.println(date1.dayofday == date2.dayofday); // true
System.out.println(date2.dayofday.getKorDayName()); // 화요일
}
}
Singleton
public class NonSingleton {
private int accountNo = 0;
public NonSingleton() {}
public int getNextNumber() {
return accountNo++;
}
}
class Test {
public static void main(String[] args) {
NonSingleton counter1 = new NonSingleton();
NonSingleton counter2 = new NonSingleton();
System.out.println(counter1.getNextNumber()); // 0
System.out.println(counter1.getNextNumber()); // 1
System.out.println(counter2.getNextNumber()); // 0 <- 문제: 새로운 객체가 생성되어 번호가 초기화됨
System.out.println(counter2.getNextNumber()); // 1
}
}
- 새로운 객체를 생성할 때마다 accountNo가 0으로 초기화됩니다
- 은행 계좌번호와 같이 고유한 순차 번호가 필요한 경우 문제가 발생합니다
위는 싱글톤을 보장하지 못하는 코드다.
싱글톤을 보장하기 위해선 다음과 같이 해야한다.
public class Singleton {
private static Singleton instance;
private int accountNo = 0;
private Singleton() {} // private 생성자로 외부 생성 차단
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public synchronized int getNextNumber() {
return accountNo++;
}
}
class Test {
public static void main(String[] args) {
Singleton counter1 = Singleton.getInstance();
Singleton counter2 = Singleton.getInstance(); // 새로운 객체가 아닌 기존 객체를 반환
System.out.println(counter1.getNextNumber()); // 0
System.out.println(counter1.getNextNumber()); // 1
System.out.println(counter2.getNextNumber()); // 2 <- 정상: 번호가 연속해서 증가
System.out.println(counter2.getNextNumber()); // 3
}
}
- private 생성자: 외부에서 new 키워드로 객체 생성을 막습니다
- private static 인스턴스: 클래스 내부에서만 단일 인스턴스를 관리합니다
- public static getInstance() 메소드: 항상 동일한 인스턴스를 반환합니다
이렇게 구현하면 어디서 호출하더라도 항상 같은 인스턴스를 사용하게 되므로, 계좌번호와 같은 순차적인 값을 안전하게 관리할 수 있습니다.
Auto Boxing, Auto Unboxing
메소드 오버라이딩
public class Sample {
public static void main(String[] args) {
D d = new D();
C c = d;
B b = c;
A a = b;
a.a();
b.a();
c.a();
d.a();
}
}
class A {
public void a() {
System.out.println("A");
}
}
class B extends A {
public void a() {
System.out.println("B");
}
}
class C extends B {
public void a() {
System.out.println("C");
}
}
class D extends C {
public void a() {
System.out.println("D");
}
}
객체 생성과 참조:
D d = new D(); // 실제 객체는 D 타입으로 생성됨
C c = d; // D 객체를 C 타입으로 참조
B b = c; // D 객체를 B 타입으로 참조
A a = b; // D 객체를 A 타입으로 참조
여기서 중요한 점은 실제 생성된 객체는 D 타입이라는 것입니다.
동적 바인딩(Dynamic Binding):
- Java는 런타임에 실제 객체의 타입을 확인하고 그 객체의 메소드를 호출합니다.
- 참조 변수의 타입이 아닌, 실제 객체의 타입에 따라 메소드가 결정됩니다.
메소드 호출 과정:
a.a(); // 참조는 A 타입이지만 실제 객체는 D -> D의 a() 호출
b.a(); // 참조는 B 타입이지만 실제 객체는 D -> D의 a() 호출
c.a(); // 참조는 C 타입이지만 실제 객체는 D -> D의 a() 호출
d.a(); // 참조는 D 타입이고 실제 객체도 D -> D의 a() 호출
따라서 모든 호출에서 D 클래스의 a() 메소드가 실행되어 "D"가 출력됩니다.
만약 각각 다른 클래스의 메소드를 호출하고 싶다면, super 키워드를 사용하여 상위 클래스의 메소드를 명시적으로 호출해야 합니다:
class D extends C {
public void a() {
super.a(); // C의 메소드 호출
System.out.println("D");
}
}
Quiz
1.참조 타입의 메모리 할당 및 할당 해제:
- 메모리 할당: new 연산자를 사용하여 힙(heap) 영역에 객체를 생성합니다. 스택(stack)에는 이 객체의 주소를 가리키는 참조가 저장됩니다.
- 할당 해제: 가비지 컬렉터(Garbage Collector)가 자동으로 처리합니다. 객체를 참조하는 변수가 없게 되면(참조 카운트가 0이 되면) GC가 해당 객체를 메모리에서 제거합니다.
2. 참조 타입 변수의 null 상태:
- 객체를 가리키지 않는 참조 변수의 값은 null입니다.
- null인 참조 변수에 접근하면 NullPointerException이 발생합니다.
- 이를 방지하기 위해 객체 사용 전 null 체크를 하는 것이 좋습니다.
3. String 클래스의 특징:
- 불변(Immutable) 객체입니다: 한번 생성된 문자열은 변경할 수 없습니다.
- String Pool을 통한 메모리 최적화: 동일한 문자열 리터럴은 String Pool에서 재사용됩니다.
- 문자열 연산시 새로운 객체가 생성됩니다.
- 문자열 비교는 equals() 메소드를 사용해야 합니다.
- Thread-safe 합니다.
4. 모든 클래스의 기본 클래스:
- java.lang.Object가 모든 클래스의 최상위 클래스입니다.
- 명시적으로 상속을 선언하지 않아도 자동으로 Object 클래스를 상속받습니다.
5. Object 클래스의 주요 메소드:
- toString(): 객체의 문자열 표현을 반환
- equals(): 객체의 동등성 비교
- hashCode(): 객체의 해시코드 값을 반환
- clone(): 객체의 복사본을 생성
- getClass(): 객체의 런타임 클래스를 반환
- finalize(): 객체가 가비지 컬렉션되기 전에 호출
- wait(), notify(), notifyAll(): 스레드 동기화에 사용
'🚣활동 > NHN Academy' 카테고리의 다른 글
Stream (1) | 2025.01.24 |
---|---|
Lambda Expression (0) | 2025.01.20 |
객체 생성과 제거 (0) | 2025.01.16 |
객체지향 프로그래밍 (0) | 2025.01.13 |
static을 왜 사용하는가? (0) | 2025.01.09 |