[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item19. 상속을 κ³ λ €ν•΄ μ„€κ³„ν•˜κ³  λ¬Έμ„œν™”ν•˜λΌ. 그렇지 μ•Šμ•˜λ”λΌλ©΄ 상속을 κΈˆμ§€ν•˜λΌ.

2023. 3. 3. 10:20ㆍJAVA/Effective JAVA

728x90

 

[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item19. 상속을 κ³ λ €ν•΄ μ„€κ³„ν•˜κ³  λ¬Έμ„œν™”ν•˜λΌ. 그렇지 μ•Šμ•˜λ”λΌλ©΄ 상속을 κΈˆμ§€ν•˜λΌ. 

[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item18. μƒμ†λ³΄λ‹€λŠ” μ»΄ν¬μ§€μ…˜μ„ μ‚¬μš©ν•˜λΌ. (tistory.com)

 

[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item18. μƒμ†λ³΄λ‹€λŠ” μ»΄ν¬μ§€μ…˜μ„ μ‚¬μš©ν•˜λΌ.

[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item18. μƒμ†λ³΄λ‹€λŠ” μ»΄ν¬μ§€μ…˜μ„ μ‚¬μš©ν•˜λΌ. 상속을 μ‚¬μš©ν•˜λ©΄ μ½”λ“œλ₯Ό μž¬μ‚¬μš©ν•  수 μžˆμ§€λ§Œ, 잘λͺ» μƒμ†ν•˜λ©΄ 였λ₯˜κ°€ λ°œμƒν•  수 μžˆλ‹€. μƒμœ„ ν΄λž˜μŠ€μ™€ ν•˜μœ„ ν΄λž˜μŠ€κ°€ λͺ¨λ‘ 같은 ν”„λ‘œκ·Έλž˜

hyejin.tistory.com

item18μ—μ„œλŠ” 상속을 염두에 두지 μ•Šκ³  μ„€κ³„ν•˜κ³  상속할 λ•Œ μ£Όμ˜μ λ„ λ¬Έμ„œν™”ν•΄λ†“μ§€ μ•Šμ€ μ™ΈλΆ€ 클래슀λ₯Ό 상속할 λ•Œμ˜ λ¬Έμ œμ μ— λŒ€ν•΄μ„œ μ–˜κΈ°ν•˜κ³  μžˆλ‹€. (μ΄λ•Œ 'μ™ΈλΆ€'λž€ ν”„λ‘œκ·Έλž˜λ¨Έμ˜ ν†΅μ œκΆŒ 밖에 μžˆμ–΄μ„œ μ–Έμ œ μ–΄λ–»κ²Œ 변경될지 λͺ¨λ₯΄λŠ” 상황을 λ§ν•œλ‹€.) 

 

 

 

1️⃣ μƒμ†μš© ν΄λž˜μŠ€λŠ” μž¬μ •μ˜ν•  수 μžˆλŠ” λ©”μ„œλ“œλ“€μ„ λ‚΄λΆ€μ μœΌλ‘œ μ–΄λ–»κ²Œ μ΄μš©ν•˜λŠ”μ§€(자기 μ‚¬μš©) λ¬Έμ„œλ‘œ 남겨야 ν•œλ‹€. 

: λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜λ©΄ μ–΄λ–€ 일이 μΌμ–΄λ‚˜λŠ”μ§€λ₯Ό μ •ν™•νžˆ μ •λ¦¬ν•˜μ—¬ λ¬Έμ„œλ‘œ 남겨야 ν•œλ‹€. 

 

클래슀의 API둜 곡개된 λ©”μ„œλ“œμ—μ„œ 클래슀 μžμ‹ μ˜ 또 λ‹€λ₯Έ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  μˆ˜λ„ μžˆλ‹€. 그런데 마침 ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œκ°€ μž¬μ •μ˜ κ°€λŠ₯ λ©”μ„œλ“œλΌλ©΄ κ·Έ 사싀을 ν˜ΈμΆœν•˜λŠ” λ©”μ„œλ“œμ˜ API μ„€λͺ…에 μ μ‹œν•΄μ•Ό ν•œλ‹€. 그리고 μΆ”κ°€λ‘œ μ–΄λ–€ μˆœμ„œλ‘œ ν˜ΈμΆœλ˜λŠ”μ§€, 각각의 호좜 κ²°κ³Όκ°€ μ΄μ–΄μ§€λŠ” μ²˜λ¦¬μ— μ–΄λ–€ 영ν–₯을 μ£ΌλŠ”μ§€λ„ λ‹΄μ•„μ•Ό ν•œλ‹€. 

더 λ„“κ²Œ λ§ν•˜λ©΄ μž¬μ •μ˜ κ°€λŠ₯ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  수 μžˆλŠ” λͺ¨λ“  상황을 λ¬Έμ„œλ‘œ 남겨야 ν•œλ‹€!!

 

API λ¬Έμ„œμ˜ λ©”μ„œλ“œ μ„€λͺ… 끝에 μ’…μ’… "Implemetation Requirements"둜 μ‹œμž‘ν•˜λŠ” μ ˆμ„ λ³Ό 수 μžˆλŠ”λ°, κ·Έ 뢀뢄이 κ·Έ λ©”μ„œλ“œμ˜ λ‚΄λΆ€ λ™μž‘ 방식을 μ„€λͺ…ν•˜λŠ” 곳이닀. 이 μ ˆμ€ λ©”μ„œλ“œ 주석에 @implSpec νƒœκ·Έλ₯Ό λΆ™μ—¬μ£Όλ©΄ μžλ°”λ… 도ꡬ가 생성해쀀닀. 

 

AbstractCollection

Implementation Requirements둜 μ‹œμž‘ν•˜λŠ” μ ˆμ—μ„œ λ©”μ„œλ“œμ˜ λ‚΄λΆ€ λ™μž‘ 방식에 λŒ€ν•΄μ„œ μ„€λͺ…ν•˜κ³  μžˆλŠ”λ° μ—¬κΈ°μ„œλŠ” iterator λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜λ©΄ remove λ©”μ„œλ“œμ˜ λ™μž‘μ— 영ν–₯을 μ€Œμ„ ν™•μ‹€νžˆ μ•Œ 수 μžˆλ‹€. 

 

 

❗ 그런데 쒋은 API λ¬Έμ„œλž€ 'μ–΄λ–»κ²Œ'κ°€ μ•„λ‹Œ '무엇'을 ν•˜λŠ”μ§€λ₯Ό μ„€λͺ…ν•΄μ•Ό ν•œλ‹€ λΌλŠ” κ²©μ–Έκ³ΌλŠ” λ§žμ§€μ•Šλ‹€. ν•˜μ§€λ§Œ 상속이 μΊ‘μŠν™”λ₯Ό ν•΄μΉ˜κΈ° λ•Œλ¬Έμ— μΌμ–΄λ‚˜κΈ° λ•Œ μ–΄μ©” 수 μ—†λ‹€.. 클래슀λ₯Ό μ•ˆμ „ν•˜κ²Œ 상속할 수 μžˆλ„λ‘ ν•˜λ €λ©΄ λ‚΄λΆ€ κ΅¬ν˜„ 방식을 μ„€λͺ…ν•΄μ•Όλ§Œ ν•œλ‹€. 

 

 

/**
 * item19. 상속을 κ³ λ €ν•΄ μ„€κ³„ν•˜κ³  λ¬Έμ„œν™”ν•˜λΌ. 그렇지 μ•Šμ•˜λ”λΌλ©΄ 상속을 κΈˆμ§€ν•˜λΌ.
 * Example class for java documentation for extendable class
 */
public class ExtendableClass
{
   /**
    * This method can be overridden to print any message
    *
    * @implSpec
    * Please use System.out.println()
    */
   public void doSomething()
   {
      System.out.println("hello");
   }
}

@implSpec νƒœκ·ΈλŠ” μžλ°” 8μ—μ„œ 처음 λ„μž…λ˜μ–΄μ„œ μžλ°”9λΆ€ν„° 본격적으둜 μ‚¬μš©λ˜κΈ° μ‹œμž‘ν–ˆλŠ”λ° μžλ°” 11의 μžλ°”λ…μ—μ„œλŠ” μ„ νƒμ‚¬ν•­μœΌλ‘œ λ‚¨κ²¨μ‘Œλ‹€. 

λ”°λΌμ„œ 이 νƒœκ·Έλ₯Ό ν™œμ„±ν™”ν•˜κΈ° μœ„ν•΄μ„œλŠ” -tag "implSpec:a:Implementation Requirements:"λ₯Ό 지정해주면 λœλ‹€. 

μžλ°”λ…μ„ μƒμ„±ν•˜κ³  λ‚˜λ©΄ method detailμ—μ„œ @implSpec νƒœκ·Έλ₯Ό μ‚¬μš©ν•΄μ„œ μž‘μ„±ν•œ λ©”μ„œλ“œ λ‚΄λΆ€ λ™μž‘ 방식에 λŒ€ν•œ μ„€λͺ…을 확인할 수 μžˆλ‹€. 

 

 

 

2️⃣ 클래슀의 λ‚΄λΆ€ λ™μž‘ κ³Όμ • 쀑간에 끼어듀 수 μžˆλŠ” ν›… hook 을 잘 μ„ λ³„ν•˜μ—¬ protected λ©”μ„œλ“œ ν˜•νƒœλ‘œ κ³΅κ°œν•΄μ•Ό ν•  μˆ˜λ„ μžˆλ‹€. 

μƒμ†μš© 클래슀λ₯Ό 섀계할 λ•Œ μ–΄λ–€ λ©”μ„œλ“œλ₯Ό protected둜 λ…ΈμΆœν•΄μ•Ό ν• μ§€λŠ” μ–΄λ–»κ²Œ κ²°μ •ν• κΉŒ 에 λŒ€ν•΄μ„œλŠ” 닡이 μ—†λ‹€. 

μ‹¬μ‚¬μˆ™κ΄˜μ„œ 잘 μ˜ˆμΈ‘ν•œ λ‹€μŒμ— μ‹€μ œ ν•˜μœ„ 클래슀λ₯Ό λ§Œλ“€μ–΄ μ‹œν—˜ν•΄λ³΄λŠ” 것이 μ΅œμ„ μ΄λ‹€..!! 

 

 

3️⃣ μƒμ†μš© 클래슀λ₯Ό μ‹œν—˜ν•˜λŠ” 방법은 직접 ν•˜μœ„ 클래슀λ₯Ό λ§Œλ“€μ–΄λ³΄λŠ” 것이 '유일'ν•˜λ‹€. 

 

 

4️⃣ μƒμ†μš©μœΌλ‘œ μ„€κ³„ν•œ ν΄λž˜μŠ€λŠ” 배포 전에 λ°˜λ“œμ‹œ ν•˜μœ„ 클래슀λ₯Ό λ§Œλ“€μ–΄ 검증해야 ν•œλ‹€.  

 

 

5️⃣ μƒμ†μš© 클래슀의 μƒμ„±μžλŠ” μ§μ ‘μ μœΌλ‘œλ“  κ°„μ ‘μ μœΌλ‘œλ“  μž¬μ •μ˜ κ°€λŠ₯ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•΄μ„œλŠ” μ•ˆλœλ‹€. 

: 이 κ·œμΉ™μ„ μ–΄κΈ΄λ‹€λ©΄ μ˜€λ™μž‘ν•  것이닀!! 

 

public class Super
{
   /**
    * μž¬μ •μ˜ κ°€λŠ₯ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” μƒμ„±μž -> λ”°λΌν•˜λ©΄ x
    */
   public Super()
   {
      overrideMe(); // μƒμ„±μžκ°€ μž¬μ •μ˜ κ°€λŠ₯ν•œ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜κ³  μžˆλ‹€.
   }
   
   public void overrideMe()
   {
   
   }
}
public final class Sub extends Super
{
   // μ΄ˆκΈ°ν™”λ˜μ§€ μ•Šμ€ final ν•„λ“œ, μƒμ„±μžμ—μ„œ μ΄ˆκΈ°ν™”ν•œλ‹€.
   private final Instant instant;
   
   Sub()
   {
      instant = Instant.now();
   }
   
   // μž¬μ •μ˜ κ°€λŠ₯ν•œ λ©”μ„œλ“œ. μƒμœ„ 클래슀의 μƒμ„±μžκ°€ ν˜ΈμΆœν•œλ‹€.
   @Override
   public void overrideMe()
   {
      System.out.println(instant);
   }
   
   public static void main(String[] args)
   {
      Sub sub = new Sub();
      sub.overrideMe();
   }
}

Sub은 Super 클래슀의 ν•˜μœ„ 클래슀둜 override λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν–ˆλ‹€. 

mainμ—μ„œ sub의 λ™μž‘ 방식을 μ˜ˆμΈ‘ν•΄λ³΄λ©΄ instant μ‹œκ°„ 2번 좜λ ₯될 것이라고 μƒκ°ν•œλ‹€. 

ν•˜μ§€λ§Œ 좜λ ₯ κ²°κ³Όλ₯Ό 확인해보면 

μ΄λ ‡κ²Œ λ™μž‘ν•˜λŠ” μ΄μœ λŠ” μƒμœ„ 클래슀의 μƒμ„±μžκ°€ ν•˜μœ„ 클래슀의 μƒμ„±μžλ³΄λ‹€ λ¨Όμ € μ‹€ν–‰λ˜λ―€λ‘œ ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ μž¬μ •μ˜ν•œ λ©”μ„œλ“œκ°€ ν•˜μœ„ 클래슀의 μƒμ„±μžλ³΄λ‹€ λ¨Όμ € ν˜ΈμΆœν•œλ‹€. 

μ΄λ•Œ κ·Έ μž¬μ •μ˜ν•œ λ©”μ„œλ“œκ°€ ν•˜μœ„ 클래슀의 μƒμ„±μžμ—μ„œ μ΄ˆκΈ°ν™”ν•˜λŠ” 값에 μ˜μ‘΄ν•œλ‹€λ©΄ μ˜λ„λŒ€λ‘œ λ™μž‘ν•˜μ§€ μ•Šκ²Œ λœλ‹€.. 

 

μ—¬κΈ°μ„œλ„ μƒμœ„ 클래슀의 μƒμ„±μžλŠ” ν•˜μœ„ 클래슀의 μƒμ„±μžκ°€ μΈμŠ€ν„΄μŠ€ ν•„λ“œλ₯Ό μ΄ˆκΈ°ν™”ν•˜κΈ°λ„ 전에 overrideMe λ₯Ό ν˜ΈμΆœν•˜κΈ° λ•Œλ¬Έμ— 첫번째 값은 null이 좜λ ₯λœλ‹€. 

 

 

6️⃣ 클래슀λ₯Ό μƒμ†μš©μœΌλ‘œ μ„€κ³„ν•˜λ €λ©΄ μ—„μ²­λ‚œ λ…Έλ ₯이 λ“€κ³  κ·Έ ν΄λž˜μŠ€μ— μ•ˆκΈ°λŠ” μ œμ•½λ„ μƒλ‹Ήν•˜λ‹€. 이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” κ°€μž₯ 쒋은 방법은 μƒμ†μš©μœΌλ‘œ μ„€κ³„ν•˜μ§€ μ•Šμ€ ν΄λž˜μŠ€λŠ” 상속을 κΈˆμ§€ν•˜λŠ” 것이닀. 

: 상속을 κΈˆμ§€ν•˜λŠ” 방법은 λ‘κ°€μ§€λ‘œ μ²«λ²ˆμ§ΈλŠ” 클래슀λ₯Ό final둜 μ„ μ–Έν•˜λŠ” 방법이고, λ‘λ²ˆμ§ΈλŠ” λͺ¨λ“  μƒμ„±μžλ₯Ό privateλ‚˜ package-private둜 μ„ μ–Έν•˜κ³  public 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό λ§Œλ“€μ–΄μ£ΌλŠ” 방법이닀. 

 

 

 

 

πŸ“š 정리

μƒμ†μš© 클래슀λ₯Ό μ„€κ³„ν•œλ‹€λŠ” 것은 클래슀 λ‚΄λΆ€μ—μ„œ 슀슀둜λ₯Ό μ–΄λ–»κ²Œ μ‚¬μš©ν•˜λŠ”μ§€ λͺ¨λ‘ λ¬Έμ„œλ‘œ 남겨야 ν•˜κ³ , 일단 λ¬Έμ„œν™”ν•œ 것은 κ·Έ ν΄λž˜μŠ€κ°€ μ“°μ΄λŠ” ν•œ λ°˜λ“œμ‹œ μ§€μΌœμ Έμ•Ό ν•œλ‹€. (그렇지 μ•ŠμœΌλ©΄.. κ·Έ λ‚΄λΆ€ κ΅¬ν˜„ 방식을 λ―Ώκ³  ν™œμš©ν•˜λ˜ ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ μ˜€λ™μž‘μ„ λ§Œλ“€μˆ˜ μžˆλ‹€.) 

λ”°λΌμ„œ 클래슀λ₯Ό ν™•μž₯ν•΄μ•Ό ν•˜λŠ” λͺ…ν™•ν•œ μ΄μœ κ°€ λ– μ˜€λ₯΄μ§€ μ•ŠλŠ”λ‹€λ©΄ 상속을 κΈˆμ§€ν•˜λŠ” 것이 더 λ‚˜μ„ 것이닀. 

상속을 κΈˆμ§€ν•˜λŠ” λ°©λ²•μœΌλ‘œλŠ” 클래슀λ₯Ό final둜 μ„ μ–Έν•˜κ±°λ‚˜ μƒμ„±μž λͺ¨λ‘λ₯Ό μ™ΈλΆ€μ—μ„œ μ ‘κ·Όν•  수 없도둝 λ§Œλ“€λ©΄ λœλ‹€. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90