Java/πŸ“• Effective Java

[Effective Java] ν΄λž˜μŠ€μ™€ μΈν„°νŽ˜μ΄μŠ€ δΈ­

soogoori 2024. 10. 5. 21:49

18. μƒμ†λ³΄λ‹€λŠ” μ»΄ν¬μ§€μ…˜ μ‚¬μš©

λ‹€λ₯Έ νŒ¨ν‚€μ§€μ˜ ꡬ체 클래슀λ₯Ό μƒμ†ν•˜λŠ” 일은 μœ„ν—˜

 

  • λ©”μ„œλ“œ 호좜과 달리 상속은 μΊ‘μŠν™”λ₯Ό 깨뜨림 πŸ‘‰ μƒμœ„ ν΄λž˜μŠ€κ°€ μ–΄λ–»κ²Œ κ΅¬ν˜„λ˜λŠλƒμ— 따라 ν•˜μœ„ 클래슀의 λ™μž‘μ— 이상 생길 수 있음
  • μƒμœ„ ν΄λž˜μŠ€λŠ” λ¦΄λ¦¬μ¦ˆλ§ˆλ‹€ λ‚΄λΆ€ κ΅¬ν˜„μ΄ λ‹¬λΌμ§ˆ 수 μžˆλŠ”λ°, 그둜 인해 ν•˜μœ„ ν΄λž˜μŠ€κ°€ μ˜€λ™μž‘ν•  수 있음 

✳️ 상속을 잘λͺ» μ‚¬μš©ν•œ 예 

public class InstrumentedHashSet<E> extends HashSet<E> {
    
    private int addCount = 0;
    
    public InstrumentedHashSet(){
     
    }
    
    public InstrumentedHashSet(int initCap, float loadFactor){
        super(initCap, loadFactor);
    }
    
    @Override
    public boolean add(E e){
        addCount ++;
        return super.add(e);
    }
    
    @Override
    public boolean addAll(Collection<? extends E> c){
        addCount += c.size();
        return super.addAll(c);
    }
    
    public int getAddCount(){
        return getAddCount();
    }
}
InstrumentedHashSet<String> s = new InstrumentedHashSet<>();
s.addAll(List.of("ν‹±", "탁탁", "νŽ‘"));

μœ„μ™€ 같은 μ½”λ“œμ—μ„œ addAll λ©”μ„œλ“œλ‘œ μ›μ†Œ 3개λ₯Ό λ”ν–ˆλ‹€κ³  ν–ˆμ„ λ•Œ, κ²°κ³ΌλŠ” 3이 μ•„λ‹Œ 6을 λ°˜ν™˜ν•œλ‹€.

HashSet의 addAll λ©”μ„œλ“œκ°€ 각 μ›μ†Œλ₯Ό add λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•΄ μΆ”κ°€ν•˜λŠ”λ°, μ΄λ•Œ λΆˆλ¦¬λŠ” add λ©”μ„œλ“œλŠ” InstrumentedHashSetμ—μ„œ μž¬μ •μ˜ν•œ λ©”μ„œλ“œλ‹€. κ·ΈλŸ¬λ―€λ‘œ addCount에 값이 μ€‘λ³΅ν•΄μ„œ 더해져 6을 λ°˜ν™˜ν•˜λŠ” 것이닀. 

 

이외에도 λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜λŠ” λŒ€μ‹  μƒμœ„ ν΄λž˜μŠ€μ— μƒˆλ‘œμš΄ λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•΄ μž¬μ •μ˜μ™€ κ΄€λ ¨λœ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλŠ” 방법을 생각할 μˆ˜λ„ μžˆλ‹€. ν•˜μ§€λ§Œ 이 λ©”μ„œλ“œκ°€ μš°μ—°νžˆλ„ ν•˜μœ„ν΄λž˜μŠ€μ— μΆ”κ°€ν•œ λ©”μ„œλ“œμ™€ μ‹œκ·Έλ‹ˆμ²˜κ°€ κ°™κ³  λ°˜ν™˜ νƒ€μž…μ€ λ‹€λ₯΄λ‹€λ©΄ ν•΄λ‹Ή ν΄λž˜μŠ€λŠ” 컴파일 μ‘°μ°¨ λ˜μ§€ μ•Šμ„ 수 μžˆλ‹€. ν˜Ήμ—¬λ‚˜ λ°˜ν™˜ νƒ€μž…μ΄ κ°™λ‹€λ©΄ μƒμœ„ 클래슀의 μƒˆ λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•œ κ²ƒμ΄λ‹ˆ μž¬μ •μ˜μ™€ κ΄€λ ¨λœ λ¬Έμ œκ°€ 또 λ‹€μ‹œ λ°œμƒν•  수 μžˆλ‹€.


✳️ μ»΄ν¬μ§€μ…˜ 

 

μœ„μ™€ 같은 상속과 κ΄€λ ¨λœ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλŠ” 방법은 'μ»΄ν¬μ§€μ…˜' 이닀.

κΈ°μ‘΄ 클래슀λ₯Ό ν™•μž₯ν•˜λŠ” λŒ€μ‹ , μƒˆλ‘œμš΄ 클래슀λ₯Ό λ§Œλ“€κ³  private ν•„λ“œλ‘œ κΈ°μ‘΄ 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό μ°Έμ‘°ν•˜κ²Œ ν•˜λ©΄ λœλ‹€. 

κΈ°μ‘΄ ν΄λž˜μŠ€κ°€ μƒˆλ‘œμš΄ 클래슀의 κ΅¬μ„±μš”μ†Œλ‘œ μ“°μΈλ‹€λŠ” λœ»μ—μ„œ μ»΄ν¬μ§€μ…˜(ꡬ성)이라 ν•˜λŠ” 것이닀. 

 

μƒˆ 클래슀의 μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œλ“€μ€ κΈ°μ‘΄ 클래슀(private ν•„λ“œλ‘œ μ°Έμ‘°)의 λŒ€μ‘ν•˜λŠ” λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•΄μ„œ κ·Έ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€ = 전달(Forwarding)

 

✴️ 전달 클래슀 

public class ForwardingSet<E> implements Set<E>{
	private final Set<E> s; // private ν•„λ“œλ‘œ κΈ°μ‘΄ 클래슀의 μΈμŠ€ν„΄μŠ€ μ°Έμ‘° 
    public ForwardingSet(Set<E> s) {this.s = s;} // Set의 μΈμŠ€ν„΄μŠ€λ₯Ό 인수둜 λ°›λŠ” μƒμ„±μž
    
    // 전달 λ©”μ„œλ“œ
    public void clear() { s.clear(); }
    public boolean contains(Object o) {return s.contains(o); }
    public boolean isEmpty() { return s.isEmpty(); }
    public int size() { return s.size(); }
    public Iterator<E> iterator() { return s. iterator(); }
    public boolean add(E e) { return s.add(e); }
    public boolean remove(Object o) {return s.remove(o); }
    public boolean containsAll(Collection<?> c) { return s.containsAll(c); }
    public boolean addAll(Collection<? extends E> c) { return s.addAll(c); }
    public boolean removeAll(Collection<?> c) { return s.removeAll(c); }
    public boolean retainAll(Collection<?> c) { return s.retainAll(c); }
    public Object[] toArray() { return s.toArray(); }
    public <T> T[] toArray(T[] a) { return s.toArray(a); }
    @Override public boolean equals(Object o) { return s.equals(o); }
    @Override public int hashCode() {return s.hashCode(); }
    @Override public String toString() { return s.toString(); }
}

 

✴️ 래퍼 클래슀 

public class InstrumentedSet<E> extends ForwardingSet<E> {

    private int addCount = 0;

    public InstrumentedSet(Set<E> s) {
        super(s);
    }

    @Override
    public boolean add(E e) {
        addCount++;
        return super.add(e);
    }

    @Override 
    public boolean addAll (Collection< ? extends E > c){
        addCount += c.size();
        return super.addAll(c); 

    }

    public int getAddCount () {
        return addCount;
    }
}

λ‹€λ₯Έ Set μΈμŠ€ν„΄μŠ€λ₯Ό 감싸고 μžˆλ‹€λŠ” λœ»μ—μ„œ InstrumentedSetκ³Ό 같은 클래슀λ₯Ό 래퍼 클래슀라고 ν•œλ‹€ = Decorator Pattern

 

전달 λ©”μ„œλ“œλ“€μ„ μž‘μ„±ν•˜λŠ” 것이 μ§€λ£¨ν•˜κ² μ§€λ§Œ, μž¬μ‚¬μš©ν•  수 μžˆλŠ” 전달 클래슀λ₯Ό μΈν„°νŽ˜μ΄μŠ€ λ‹Ή ν•˜λ‚˜μ”©λ§Œ λ§Œλ“€μ–΄λ‘λ©΄ μ›ν•˜λŠ” κΈ°λŠ₯을 λ§μ”Œμš°λŠ” 전달 ν΄λž˜μŠ€λ“€μ„ μ†μ‰½κ²Œ κ΅¬ν˜„ν•  수 μžˆλ‹€. 


κ·Έλ ‡λ‹€λ©΄ 상속은 μ–Έμ œ μ‚¬μš©λ˜λŠ” κ²ƒμΌκΉŒ??

 

λ°˜λ“œμ‹œ ν•˜μœ„ ν΄λž˜μŠ€κ°€ μƒμœ„ 클래슀의 'μ§„μ§œ' ν•˜μœ„ νƒ€μž…μΈ μƒν™©μ—μ„œλ§Œ μ‚¬μš©ν•˜λ©΄ λœλ‹€. 

즉, is-a 관계일 λ•Œλ§Œ μƒμ†ν•˜λ©΄ λ˜λŠ” 것이닀. 

 

 

19. 상속을 κ³ λ €ν•΄ μ„€κ³„ν•˜κ³  λ¬Έμ„œν™”ν•˜κΈ°. 그렇지 μ•ŠμœΌλ©΄ 상속 κΈˆμ§€

μƒμ†μš© ν΄λž˜μŠ€λŠ” μž¬μ •μ˜ν•  수 μžˆλŠ” λ©”μ„œλ“œλ“€μ„ λ‚΄λΆ€μ μœΌλ‘œ μ–΄λ–»κ²Œ μ΄μš©ν•˜λŠ”μ§€ λ¬Έμ„œλ‘œ 남겨야 함

 

 

20. 좔상 ν΄λž˜μŠ€λ³΄λ‹€λŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό μš°μ„  !

닀쀑 κ΅¬ν˜„μš© νƒ€μž…μœΌλ‘œλŠ” μΈν„°νŽ˜μ΄μŠ€κ°€ κ°€μž₯ 적합

 

μžλ°”κ°€ μ œκ³΅ν•˜λŠ” 닀쀑 κ΅¬ν˜„ λ©”μ»€λ‹ˆμ¦˜μ€ μΈν„°νŽ˜μ΄μŠ€μ™€ 좔상 클래슀 두 가지가 μžˆλ‹€.

 

  • μΈν„°νŽ˜μ΄μŠ€
    • μΈν„°νŽ˜μ΄μŠ€κ°€ μ„ μ–Έν•œ λ©”μ„œλ“œλ₯Ό λͺ¨λ‘ μ •μ˜ν•˜κ³  일반 κ·œμ•½μ„ 잘 지킨 클래슀라면 λ‹€λ₯Έ μ–΄λ–€ 클래슀λ₯Ό μƒμ†ν–ˆλ“  같은 νƒ€μž…μœΌλ‘œ 취급됨 
  • 좔상 클래슀
    • 좔상 ν΄λž˜μŠ€κ°€ μ •μ˜ν•œ νƒ€μž…μ„ κ΅¬ν˜„ν•˜λŠ” ν΄λž˜μŠ€λŠ” λ°˜λ“œμ‹œ 좔상 클래슀의 ν•˜μœ„ ν΄λž˜μŠ€κ°€ λ˜μ–΄μ•Ό 함
    • μžλ°”λŠ” 단일 μƒμ†λ§Œ μ§€μ›ν•˜λ―€λ‘œ μƒˆλ‘œμš΄ νƒ€μž…μ„ μ •μ˜ν•˜λŠ” 데 μ œμ•½μ΄ 있음 
interface Vehicle {
    void drive();
}

class Car {
    // Car만의 κ³ μœ ν•œ λ©”μ„œλ“œ
    public void honk() {
        System.out.println("Honk!");
    }
}

// Carλ₯Ό μƒμ†λ°›μœΌλ©΄μ„œ Vehicle μΈν„°νŽ˜μ΄μŠ€λ„ κ΅¬ν˜„
class SportsCar extends Car implements Vehicle {
    @Override
    public void drive() {
        System.out.println("Driving a sports car!");
    }
}

πŸ‘‰ SportsCarκ°€ Carλ₯Ό μƒμ†λ°›μ•˜μ§€λ§Œ 그와 상관없이 Vehicle μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν–ˆκΈ° λ•Œλ¬Έμ—, Vehicle νƒ€μž…μœΌλ‘œ μ·¨κΈ‰ν•  수 있음


✳️ μΈν„°νŽ˜μ΄μŠ€ μž₯점 

  • κΈ°μ‘΄ ν΄λž˜μŠ€μ—λ„ μ†μ‰½κ²Œ μƒˆλ‘œμš΄ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•΄ 넣을 수 있음
    • μΈν„°νŽ˜μ΄μŠ€κ°€ μš”κ΅¬ν•˜λŠ” λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•˜κ³  클래슀 선언에 implements ꡬ문만 μΆ”κ°€ν•˜λ©΄ 됨
    • λ§Œμ•½ 두 ν΄λž˜μŠ€κ°€ 같은 좔상 클래슀λ₯Ό ν™•μž₯ν•˜κΈΈ μ›ν•œλ‹€λ©΄ κ·Έ 좔상 ν΄λž˜μŠ€λŠ” 계측 ꡬ쑰 상 두 클래슀의 곡톡 쑰상이어야 함
      πŸ‘‰ μƒˆλ‘œ μΆ”κ°€λœ 좔상 클래슀의 λͺ¨λ“  μžμ†μ΄ 이λ₯Ό μƒμ†ν•˜κ²Œ 됨. κ·Έλ ‡κ²Œ ν•˜λŠ” 것이 μ μ ˆν•˜μ§€ μ•Šμ€ μƒν™©μ—μ„œλ„ κ°•μ œλ‘œ ν•  μˆ˜λ°–μ— μ—†μŒ
  • 믹슀인(mixin) μ •μ˜μ— μ•ˆμ„±λ§žμΆ€
    • mixin : νŠΉμ • ν΄λž˜μŠ€κ°€ 상속 없이 λ‹€λ₯Έ 클래슀의 κΈ°λŠ₯을 μž¬μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•˜λŠ” 방식
  • 계측 ꡬ쑰가 μ—†λŠ” νƒ€μž… ν”„λ ˆμž„μ›Œν¬λ₯Ό λ§Œλ“€ 수 있음 
public interface Singer{
	public void sing();
}

public interface SongWriter{
	public void compose();
}

public interface SingerSongWriter extends Singer, SongWriter{
	public void actSensitive();
}

Singer와 SongWriter λͺ¨λ‘λ₯Ό ν™•μž₯ν•˜κ³  μƒˆλ‘œμš΄ λ©”μ„œλ“œκΉŒμ§€ μΆ”κ°€ν•œ 제3의 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ •μ˜ν•  수 있음


✳️ μΈν„°νŽ˜μ΄μŠ€μ™€ 좔상 골격 κ΅¬ν˜„ 클래슀 ν•¨κ»˜ μ‚¬μš© πŸ‘‰ ν…œν”Œλ¦Ώ λ©”μ„œλ“œ νŒ¨ν„΄ 

  • μΈν„°νŽ˜μ΄μŠ€λ‘œλŠ” νƒ€μž… μ •μ˜ + λ””ν΄νŠΈ λ©”μ„œλ“œ 
  • 골격 κ΅¬ν˜„ ν΄λž˜μŠ€λŠ” λ‚˜λ¨Έμ§€ λ©”μ„œλ“œκΉŒμ§€ κ΅¬ν˜„
    πŸ‘‰ μΈν„°νŽ˜μ΄μŠ€μ˜ 기본적인 κ΅¬ν˜„μ„ μ œκ³΅ν•˜λ©΄μ„œ, 일뢀 λ©”μ„œλ“œλŠ” 좔상 λ©”μ„œλ“œλ‘œ 남겨두어 ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ κ΅¬ν˜„ν•˜λ„λ‘ λ§Œλ“œλŠ” 클래슀
  • 관둀상 μΈν„°νŽ˜μ΄μŠ€μ˜ 이름이 Interface라면 골격 κ΅¬ν˜„ ν΄λž˜μŠ€λŠ” AbstractInterface둜 μ§€μŒ
public abstract class AbstractList<E> implements List<E> {
    // List μΈν„°νŽ˜μ΄μŠ€μ˜ 일뢀 λ©”μ„œλ“œλŠ” 미리 κ΅¬ν˜„
    @Override
    public boolean add(E e) {
        add(size(), e);
        return true;
    }

    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    // 핡심 λ©”μ„œλ“œλŠ” μ—¬μ „νžˆ 좔상 λ©”μ„œλ“œλ‘œ 남겨둠
    public abstract E get(int index);
    public abstract int size();
    public abstract void add(int index, E element);
}
public class MyArrayList<E> extends AbstractList<E> {
    private E[] data;
    private int size;

    public MyArrayList() {
        data = (E[]) new Object[10];
        size = 0;
    }

    @Override
    public E get(int index) {
        return data[index];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public void add(int index, E element) {
        data[index] = element;
        size++;
    }
}

 

 

 

 

21. μΈν„°νŽ˜μ΄μŠ€λŠ” κ΅¬ν˜„ν•˜λŠ” μͺ½μ„ 생각해 μ„€κ³„ν•˜κΈ°

  • μžλ°” 8μ—μ„œ μΈν„°νŽ˜μ΄μŠ€μ— λ””ν΄νŠΈ λ©”μ„œλ“œκ°€ 좔가됨 πŸ‘‰ λžŒλ‹€ ν™œμš©ν•˜κΈ° μœ„ν•΄μ„œ
default boolean removeIf(Predicate<? super E> filter) { 
    Objects.requireNonNull(filter); 
    boolean result = false; 
    for(Iterator<E> it = iterator(); it.hasNext(); ) { 
        if(filter.test(it.next())) { 
            it.remove(); 
            result = true; 
        } 
    } 
    return result; 
}

removeIfλŠ” Collection μΈν„°νŽ˜μ΄μŠ€μ— μΆ”κ°€λœ λ””ν΄νŠΈ λ©”μ„œλ“œμ΄λ‹€. 

이 λ©”μ„œλ“œλŠ” λͺ¨λ“  Collection κ΅¬ν˜„μ²΄μ™€ 잘 μ–΄μš°λŸ¬μ§€λŠ” 것은 μ•„λ‹ˆλ‹€. 

 

μ•„νŒŒμΉ˜μ˜ SynchronizedCollection ν΄λž˜μŠ€λŠ” ν΄λΌμ΄μ–ΈνŠΈκ°€ μ œκ³΅ν•œ 객체둜 락을 κ±°λŠ” λŠ₯λ ₯을 μΆ”κ°€λ‘œ μ œκ³΅ν•˜κ³  μžˆλ‹€.

ν•˜μ§€λ§Œ removeIf λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜κ³  μžˆμ§€ μ•Šλ‹€. 즉, λͺ¨λ“  λ©”μ„œλ“œ ν˜ΈμΆœμ„ μ•Œμ•„μ„œ 동기화해주지 λͺ»ν•˜λŠ” 것이닀. 

removeIf의 κ΅¬ν˜„μ€ 동기화에 κ΄€ν•΄ 아무것도 λͺ¨λ₯΄λ―€λ‘œ 락 객체λ₯Ό μ‚¬μš©ν•  수 μ—†μ–΄ removeIfλ₯Ό ν˜ΈμΆœν•˜λ©΄ ConcurrentModificationException이 λ°œμƒν•˜κ±°λ‚˜ λ‹€λ₯Έ 예기치 λͺ»ν•œ 결과둜 μ΄μ–΄μ§ˆ 수 μžˆλ‹€. 

 

μ΄λŸ¬ν•œ 문제λ₯Ό μ˜ˆλ°©ν•˜κΈ° μœ„ν•΄ μžλ°”μ—μ„œλŠ” κ΅¬ν˜„ν•œ μΈν„°νŽ˜μ΄μŠ€μ˜ λ””ν΄νŠΈ λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜κ³ , λ‹€λ₯Έ λ©”μ„œλ“œμ—μ„œλŠ” λ””ν΄νŠΈ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜κΈ° 전에 ν•„μš”ν•œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λ„λ‘ ν–ˆλ‹€. 

 

 

 

 

 

22.  μΈν„°νŽ˜μ΄μŠ€λŠ” νƒ€μž…μ„ μ •μ˜ν•˜λŠ” μš©λ„λ‘œλ§Œ μ‚¬μš©ν•˜κΈ°

ν΄λž˜μŠ€κ°€ μ–΄λ–€ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œλ‹€ = μžμ‹ μ˜ μΈμŠ€ν„΄μŠ€λ‘œ 무엇을 ν•  수 μžˆλŠ”μ§€λ₯Ό ν΄λΌμ΄μ–ΈνŠΈμ— μ–˜κΈ°ν•΄μ£ΌλŠ” 것
μƒμˆ˜ 곡개용 μˆ˜λ‹¨μœΌλ‘œ μ‚¬μš© X

 

  • μƒμˆ˜ μΈν„°νŽ˜μ΄μŠ€ = static final ν•„λ“œλ‘œλ§Œ 가득 μ°¬ μΈν„°νŽ˜μ΄μŠ€
    • 클래슀 λ‚΄λΆ€μ—μ„œ μ‚¬μš©ν•˜λŠ” μƒμˆ˜λŠ” μ™ΈλΆ€ μΈν„°νŽ˜μ΄μŠ€κ°€ μ•„λ‹ˆλΌ λ‚΄λΆ€ κ΅¬ν˜„μ— 해당함
    • μƒμˆ˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” 것은 λ‚΄λΆ€ κ΅¬ν˜„μ„ 클래슀의 API둜 λ…ΈμΆœν•˜λŠ” ν–‰μœ„μ΄λ―€λ‘œ μ‚¬μš©μžμ—κ²Œ ν˜Όλž€μ„ 쀄 수 μžˆκ±°λ‚˜ ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œκ°€ λ‚΄λΆ€ κ΅¬ν˜„μ— ν•΄λ‹Ήν•˜λŠ” 이 μƒμˆ˜λ“€μ— μ’…μ†λ˜κ²Œ 함 
  • μƒμˆ˜λ₯Ό κ³΅κ°œν•  λͺ©μ μ΄λΌλ©΄ κ·Έ ν΄λž˜μŠ€λ‚˜ μΈν„°νŽ˜μ΄μŠ€ μžμ²΄μ— μΆ”κ°€ν•΄μ•Ό 함
    • μ—΄κ±° νƒ€μž…μœΌλ‘œ λ‚˜νƒ€λ‚΄κΈ° μ ν•©ν•œ μƒμˆ˜λΌλ©΄ μ—΄κ±° νƒ€μž…(ENUM)으둜 !
    • μΈμŠ€ν„΄μŠ€ν™”ν•  수 μ—†λŠ” μœ ν‹Έλ¦¬ν‹° ν΄λž˜μŠ€μ— λ‹΄μ•„ κ³΅κ°œν•˜κΈ°
      πŸ‘‰ μ •μ˜λœ μƒμˆ˜λ₯Ό ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ‚¬μš©ν•˜λ €λ©΄ 클래슀 μ΄λ¦„κΉŒμ§€ λͺ…μ‹œν•΄μ•Ό 함 = PhysicalConstants.AVOGARDOS_NUMBER
// μƒμˆ˜ μœ ν‹Έλ¦¬ν‹° 클래슀
public class PhysicalConstants {
    private PhysicalConstants() {} // μΈμŠ€ν„΄μŠ€ν™” 방지
    
    static final double AVOGADROS_NUMBER = 6.022;
    static final double BOLTZMANN_CONSTANT = 1.38;
    static final double ELECTRON_MASS = 9.109;
}