item 20 junghyunlyoo - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki
์๋ฐ๊ฐ ์ ๊ณตํ๋ ๋ค์ค ๊ตฌํ ๋งค์ปค๋์ฆ์ interface, abstract class 2๊ฐ์ง๊ฐ ์๋ค.
๋ ๋งค์ปค๋์ฆ ๋ชจ๋ ์ธ์คํด์ค ๋ฉ์๋๋ฅผ ๊ตฌํํ ์ ์๋ค.
(์ถ์ ํด๋์ค๋ ์๋ ์ ๊ณตํ๊ณ , ์ธํฐํ์ด์ค๋ java8์ ๋ฑ์ฅํ default ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ค)
ํํธ ์ธํฐํ์ด์ค๋ ์ถ์ํด๋์ค๋ณด๋ค ์ฌ๋ฌ๊ฐ์ง ๋์์ ์ด ์๋ค. ์๋์์ ํ๋์ฉ ์ดํด๋ณด์.
๋ ๋งค์ปค๋์ฆ์ ๊ฐ์ฅ ํฐ ์ฐจ์ด๋ ๋ฐ๋ก ์ด๊ฒ์ด๋ค.
์ถ์ํด๋์ค๊ฐ ์ ์ํ ํ์ ์ ์์ํ๋ ํด๋์ค๋ ๋ฐ๋์ ์ถ์ ํด๋์ค์ ํ์ ํด๋์ค๊ฐ ๋์ด์ผ ํ๋ค๋ ์ ์ด๋ค.
์๋ฐ๋ ๋จ์ผ ์์์ ์ง์ํ๋ค.
์ฆ ์ถ์ํด๋์ค๋ฅผ ์์๋ฐ์ผ๋ฉด ๋ค๋ฅธ ํด๋์ค๋ฅผ ์์๋ฐ์ ์๊ฐ ์๋ค.
๋ฐ๋ฉด ์ธํฐํ์ด์ค๋ฅผ ๋ค์ ๊ตฌํํ๋ ๊ฒ์ ํ์ฉ๋๋ค.
์ธํฐํ์ด์ค๊ฐ ์ ์ธํ ๋ฉ์๋๋ฅผ ๋ชจ๋ ์ ์ํ๊ณ ๊ทธ ์ผ๋ฐ ๊ท์ฝ์ ์ ์งํจ ํด๋์ค๋ผ๋ฉด
๋ค๋ฅธ ์ด๋ค ํด๋์ค๋ฅผ ์์ํ๋ ๋๋ ๋ค๋ฅธ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ๋ชจ๋ ๋์ผํ ํ์ ์ผ๋ก ์ทจ๊ธํ ์ ์๋ค.
๋ํ ์ด๋๊ฐ์์ ์ฌ์ฉ์ค์ธ ๊ธฐ์กด ํด๋์ค์ ๊ตฌํ, ๋๋ ์์์ ํตํ์ฌ ์์ ํ์ ์ ์ง์ ํ ๋๋, ์ด ๋์ ์ฐจ์ด์ ์ ๊ฐ๋๋ค.
๊ธฐ์กด ์ฌ์ฉ์ค์ธ ํด๋์ค์ ์ธํฐํ์ด์ค๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์๋์ ์ผ๋ก ๋ถ๋ด์ด ๋ํ๋ค.
์๋ํ๋ฉด implemets ๊ตฌ๋ฌธ์ ์ถ๊ฐํ๊ณ ์ธํฐํ์ด์ค์ ์ ์๋ ๋ฉ์๋๋ฅผ ์ ์ํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ด๋ค.
์๋ก ์ถ๊ฐ๋ง ํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด์ ์ฝ๋๋ค์ ์ํฅ์ด ๊ฑฐ์ ์๋ค.
๋์ผํ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๊ฒ๋ ๋ค๋ฅธ ํด๋์ค์๋ ์ํฅ์ด ์๋ค.
(Comparable, Iterable, AutoCloseable ์ธํฐํ์ด์ค๊ฐ ์ ํน์ง์ ๋ณด์ฌ์ฃผ๋ ์ฌ๋ก๋ผ๊ณ ๋ณผ ์ ์๋ค.)
ํ์ง๋ง ๊ธฐ์กด ์ฌ์ฉ์ค์ธ ํด๋์ค์ ์ถ์ ํด๋์ค๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์๋์ ์ผ๋ก ๋ถ๋ด์ด ํฌ๋ค.
์ด๋ค ํด๋์ค์ ์ถ์ ํด๋์ค๋ฅผ ์์ ํ์ ์ผ๋ก ์ง์ ํ๋ ค๊ณ ํ ๋ ์ถ์ ํด๋์ค์ ์๋น์ค ๋ก์ง์ด ์๋ฆฌํ์ฌ
ํ์ ํด๋์ค๊ฐ ์ด ๋ก์ง์ ๋ํ ์์กด์ฑ์ด ์๊ธฐ๋ฉด ์ด ์ถ์ ํด๋์ค๋ฅผ ์์ํ ๋ค๋ฅธ ํด๋์ค์ ๋ถ๋ด์ด ์๊ธฐ๊ฒ ๋๋ค.
์ถ์ ํด๋์ค์ ๋ฉ์๋๋ ํ๋ ๋ฑ์ด ํน์ ์์ ํด๋์ค์ ์ต์ ํ๋ ์๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด ์ถ์ ํด๋์ค๋ฅผ ์์ํ๊ฒ ๋ ๋ ๋ค๋ฅธ ํด๋์ค๋ ํน์ ์์ ํด๋์ค๊ฐ ์ข ์ํ๊ณ ์๋
์ถ์ ํด๋์ค์ ๋ฉ์๋๋ ํ๋ ๋๋ฌธ์ ๊ธฐ๋ฅ ๊ตฌํ์ ์ ํ์ด ์๊ธธ ์๋ ์๋ค.
ํน์ ํ์ํ์ง ์์ ๋ถ๋ถ๊น์ง ์์๋ฐ์์ผ ํ ์๋ ์๋ค.
๋์ ํ์ ์ ์ฃผ๋ ๊ธฐ๋ฅ์ ์ ํ์ ๊ธฐ๋ฅ์ ํผํฉํ๋ ๊ฒ์ด ๋ฏน์ค์ธ์ด๋ผ๊ณ ํ ์ ์๋ค.
(์ฃผ ๊ธฐ๋ฅ์ด ์๋ ๋ถ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ๊ธฐ๋ฒ)
์ธํฐํ์ด์ค๋ ์ถ์ํด๋์ค์ ๋ค๋ฅด๊ฒ ๊ธฐ๋ฅ์ ์ธ๋ถํํจ์ผ๋ก์จ ๋ฏน์ค์ธ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋ค.
์ถ์ํด๋์ค๋ 1๊ฐ์ฉ๋ฐ์ ์์ํ ์ ์์ง๋ง ์ธํฐํ์ด์ค๋ ์ฌ๋ฌ๊ฐ ๊ตฌํํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๊ธฐ์กด ํด๋์ค์ ์ถ์ ํด๋์ค๋ฅผ ์ถ๊ฐํ๋๊ฒ์ด ์ด๋ ต๊ธฐ ๋๋ฌธ์ ์ถ์ ํด๋์ค๋ก๋ ๋ฏน์ค์ธ์ ์ ์ํ ์ ์๋ค.
์ฑ ์์ ์ฌ๋ฌ๊ฐ ๊ฐ๊ณ ์๋ ์ธํฐํ์ด์ค๋ผ๋ฉด ์ฑ ์์ ์ต๋ํ ์ธ์ธํ๊ฒ ๋ถ๋ฆฌํ์ฌ
ํด๋น ์ธํฐํ์ด์ค ๊ตฌํ์ด ํ์ํ ๊ฐ์ฒด๋ค์ด ์ํ๋ ๊ธฐ๋ฅ์ ์ธํฐํ์ด์ค๋ง ์ ํํ์ฌ ๊ตฌํํ๋๋ก ํ๋ค.
์ด๋ฌํ ์ธ์ธํ ์ธํฐํ์ด์ค๋ฅผ ๋ฏน์ค์ธ ์ธํฐํ์ด์ค๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์๋ฅผ ๋ค์ด Comparable์ ์์ ์ ๊ตฌํํ ํด๋์ค์ ์ธ์คํด์ค๋ค๋ผ๋ฆฌ๋ ์์๋ฅผ ์ ํ ์ ์๋ค๊ณ ์ ์ธํ๋ ๋ฏน์ค์ธ ์ธํฐํ์ด์ค๋ค.
์ธํฐํ์ด์ค๋ ๋ฏน์ค์ธ ์ ์์ ์์ฑ๋ง์ถค์ด๋ค.
์ธํฐํ์ด์ค๋ก๋ ๊ณ์ธต๊ตฌ์กฐ๊ฐ ์๋ ํ์ ํ๋ ์์ํฌ๋ฅผ ๋ง๋ค ์ ์๋ค.
ํ์ ์ ๊ณ์ธต์ ์ผ๋ก ์ ์ํ๋ฉด ์๋ง์ ๊ฐ๋ ์ ๊ตฌ์กฐ์ ์ผ๋ก ์ ํํํ ์ ์์ง๋ง
ํ์ค์๋ ๊ณ์ธต์ ์๊ฒฉํ ๊ตฌ๋ถํ๊ธฐ ์ด๋ ค์ด ๊ฒฝ์ฐ๋ ์๋ค.
์๋ฅผ ๋ค์ด ๊ฐ์(Singer) ์ธํฐํ์ด์ค์ ์๊ณก๊ฐ(SongWriter) ์ธํฐํ์ด์ค๊ฐ ์๋ค๊ณ ํด๋ณด์.
public interface Singer {
AudioClip sing(Song s);
}
public interface Songwriter {
Song compose(int chartPosition);
}
์ฐ๋ฆฌ ์ฃผ๋ณ์ ์๊ณก๋ ํ๋ ๊ฐ์๊ฐ ์ ๋ฒ ์๋ค.
์ด ์ฝ๋์ฒ๋ผ ํ์ ์ ์ธํฐํ์ด์ค๋ก ์ ์ํ๋ฉด ๊ฐ์ ํด๋์ค๊ฐ Singer์ Songwriter ๋ชจ๋๋ฅผ ๊ตฌํํด๋ ์ ํ ๋ฌธ์ ๋์ง ์๋๋ค.
์ฌ์ง์ด Singer์ Songwriter ๋ชจ๋๋ฅผ ํ์ฅํ๊ณ ์๋ก์ด ๋ฉ์๋๊น์ง ์ถ๊ฐํ ์ 3์ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ ์๋ ์๋ค.
public interface SingerSongwriter extends Singer, Songwriter {
AudioClip strum();
void actSensitive();
}
์ด ์ ๋์ ์ ์ฐ์ฑ์ด ํญ์ ํ์ํ์ง๋ ์์ง๋ง ์ด๋ ๊ฒ ๋ง๋ค์ด๋ ์ธํฐํ์ด์ค๊ฐ ๊ฒฐ์ ์ ์ธ ๋์์ ์ค ์๋ ์๋ค.
๊ฐ์ ๊ตฌ์กฐ๋ฅผ ํด๋์ค๋ก ๋ง๋ค๊ธฐ ์ํด์ ๊ฐ๋ฅํ ์กฐํฉ ์ ๋ถ๋ฅผ ๊ฐ๊ฐ์ ํด๋์ค๋ก ์ ์ํ ๊ณ ๋๋น๋ง ๊ณ์ธต๊ตฌ์กฐ๊ฐ ๋ง๋ค์ด์ง ๊ฒ์ด๋ค.
์์ฑ์ด n๊ฐ๋ผ๋ฉด ์ง์ํด์ผ ํ ์กฐํฉ์ ์๋ 2^n๊ฐ๋ ๋๋ค. ํํ ์กฐํฉ ํญ๋ฐ์ด๋ผ ๋ถ๋ฅด๋ ํ์์ด๋ค.
๊ฑฐ๋ํ ํด๋์ค ๊ณ์ธต๊ตฌ์กฐ์๋ ๊ณตํต ๊ธฐ๋ฅ์ ์ ์ํด๋์ ํ์ ์ด ์์ผ๋
์์นซ ๋งค๊ฐ๋ณ์ ํ์ ๋ง ๋ค๋ฅธ ๋ฉ์๋๋ค์ ์์์ด ๋ง์ด ๊ฐ์ง ๊ฑฐ๋ํ ํด๋์ค๋ฅผ ๋ณ์ ์ ์๋ค.
์ธํฐํ์ด์ค๋ item 18์์ ๋ฑ์ฅํ๋ ๋ํผ ํด๋์ค ๊ด์ฉ๊ตฌ์ ์ ์ฉ๋๊ธฐ๋ ํ๋ค.
์ด๋ ๊ธฐ๋ฅ์ ํฅ์์ํค๋ ์์ ํ๊ณ ๊ฐ๋ ฅํ ์๋จ์ด ๋๋ค.
ํ์ ์ ์ถ์ ํด๋์ค๋ก ์ ์ํด๋๋ฉด ๊ทธ ํ์ ์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ ์์๋ฟ์ด๋ค.
์์ํด์ ๋ง๋ ํด๋์ค๋ ๋ํผ ํด๋์ค๋ณด๋ค ํ์ฉ๋๊ฐ ๋จ์ด์ง๊ณ ๊นจ์ง๊ธฐ๋ ๋ ์ฝ๋ค.
์ธํฐํ์ด์ค์ ๋ฉ์๋ ์ค ๊ตฌํ ๋ฐฉ๋ฒ์ด ๋ช ๋ฐฑํ ๊ฒ์ด ์๋ค๋ฉด ๊ทธ ๊ตฌํ์ ๋ํดํธ ๋ฉ์๋๋ก ์ ๊ณตํด ํ๋ก๊ทธ๋๋จธ๋ค์ ์ผ๊ฐ์ ๋์ด์ค ์ ์๋ค.
item 21์์ ๋ฑ์ฅํ๋ removeIf ๋ฉ์๋๊ฐ ๊ทธ ์์ด๋ค.
๋ํดํธ ๋ฉ์๋๋ฅผ ์ ๊ณตํ ๋๋ ์์ํ๋ ค๋ ์ฌ๋์ ์ํ ์ค๋ช
์ @implSpec ์๋ฐ๋
ํ๊ทธ๋ฅผ ๋ถ์ฌ ๋ฌธ์ํํด์ผ ํ๋ค. (item 19)
๋ํดํธ ๋ฉ์๋์๋ ์ ์ฝ์ ์๋ค.
๋ง์ ์ธํฐํ์ด์ค๊ฐ equals์ hashCode, toString ๊ฐ์ Object์ ๋ฉ์๋๋ฅผ ์ ์ํ๊ณ ์์ง๋ง ์ด๋ค์ ๋ํดํธ ๋ฉ์๋๋ก ์ ๊ณตํด์๋ ์ ๋๋ค.
์๋ํ๋ฉด ์ธํฐํ์ด์ค๋ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ๊ฐ์ฒด์ ์ํ์ ์ ๊ทผํ ์ ์๋๋ฐ,
equals๋ hashCode, toString ๋ฉ์๋๋ ์ผ๋ฐ์ ์ผ๋ก ๊ฐ์ฒด์ ์ํ๋ฅผ ํ์์ ์ผ๋ก ์ฐธ์กฐํด์ผํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๊ธฐ ๋๋ฌธ์ด๋ค.
๋ํ ์ธํฐํ์ด์ค๋ ์ธ์คํด์ค ํ๋๋ฅผ ๊ฐ์ง ์ ์๊ณ public์ด ์๋ ์ ์ ๋ฉค๋ฒ๋ ๊ฐ์ง ์ ์๋ค. (๋จ private ์ ์ ๋ฉ์๋๋ ์์ธ๋ค)
๋ง์ง๋ง์ผ๋ก, ์์ ์ด ๋ง๋ค์ง ์์ ์ธํฐํ์ด์ค์๋ ๋ํด๋ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ ์ ์๋ค.
ํํธ, ์ธํฐํ์ด์ค์ ์ถ์ ๊ณจ๊ฒฉ ๊ตฌํ ํด๋์ค๋ฅผ ํจ๊ป ์ ๊ณตํ๋ ์์ผ๋ก ์ธํฐํ์ด์ค์ ์ถ์ ํด๋์ค์ ์ฅ์ ์ ๋ชจ๋ ์ทจํ๋ ๋ฐฉ๋ฒ๋ ์๋ค.
์ธํฐํ์ด์ค๋ก๋ ํ์ ์ ์ ์ํ๊ณ , ํ์ํ๋ฉด ๋ํดํธ ๋ฉ์๋ ๋ช ๊ฐ๋ ํจ๊ป ์ ๊ณตํ๋ค.
๊ทธ๋ฆฌ๊ณ ๊ณจ๊ฒฉ ๊ตฌํ ํด๋์ค๋ ๋๋จธ์ง ๋ฉ์๋๋ค๊น์ง ๊ตฌํํ๋ค.
์ด๋ ๊ฒ ํด๋๋ฉด ๋จ์ํ ๊ณจ๊ฒฉ ๊ตฌํ์ ํ์ฅํ๋ ๊ฒ๋ง์ผ๋ก ์ด ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ๋ฐ ํ์ํ ์ผ์ด ๋๋ถ๋ถ ์๋ฃ๋๋ค.
๋ฐ๋ก ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด์ด๋ค.
๊ด๋ก์ ์ธํฐํ์ด์ค ์ด๋ฆ์ด Interface๋ผ๋ฉด
๊ทธ ๊ณจ๊ฒฉ ๊ตฌํ ํด๋์ค์ ์ด๋ฆ์ AbstractInterface๋ก ์ง๋๋ค.
์๋ฅผ ๋ค๋ฉด, AbstractCollection, AbstractSet, AbstractList, AbstractMap ๊ฐ๊ฐ์ด
๋ฐ๋ก ํต์ฌ ์ปฌ๋ ์
์ธํฐํ์ด์ค์ ๊ณจ๊ฒฉ ๊ตฌํ์ด๋ค.
(SkeletalCollection, SkeletalSet, SkeletalList, SkeletalMap ํํ๊ฐ ๋ ์ ์ ํ์์ง๋ ๋ชจ๋ฅด์ง๋ง
์ด๋ฏธ Abstract๋ฅผ ์ ๋์ด๋ก ์ฐ๋ ํํ๊ฐ ํ๊ณ ํ ์๋ฆฌ์ก์๋ค.)
๊ณจ๊ฒฉ ๊ตฌํ ์์ฑ์ ์ด๋ ต์ง ์๋ค.
๋จผ์ , ์ธํฐํ์ด์ค๋ฅผ ๋ถ์ํ์ฌ ๋ค๋ฅธ ๋ฉ์๋๋ค์ ๊ตฌํ์ ์ฌ์ฉ๋๋ ๊ธฐ๋ฐ ๋ฉ์๋๋ค์ ์ ์ ํ๋ค.
์ด ๊ธฐ๋ฐ ๋ฉ์๋๋ค์ ์ถ์ ๋ฉ์๋๊ฐ ๋๋ค.
๊ทธ๋ค์์ผ๋ก ๊ธฐ๋ฐ ๋ฉ์๋๋ค์ ์ฌ์ฉํด ์ง์ ๊ตฌํํ ์ ์๋ ๋ฉ์๋๋ฅผ ๋ชจ๋ ๋ํดํธ ๋ฉ์๋๋ก ์ ๊ณตํ๋ค.
equals์ hashCode๊ฐ์ Object์ ๋ฉ์๋๋ ๋ํดํธ ๋ฉ์๋๋ก ์ ๊ณตํ๋ฉด ์ ๋๋ค๋ ์ฌ์ค์ ํญ์ ์ ๋
ํ์.
๋ง์ฝ ์ธํฐํ์ด์ค์ ๋ฉ์๋ ๋ชจ๋๊ฐ ๊ธฐ๋ฐ ๋ฉ์๋์ ๋ํดํธ ๋ฉ์๋๊ฐ ๋๋ค๋ฉด ๊ณจ๊ฒฉ ๊ตฌํ ํด๋์ค๋ฅผ ๋ณ๋๋ก ๋ง๋ค ์ด์ ๋ ์๋ค.
๊ธฐ๋ฐ ๋ฉ์๋๋ ๋ํดํธ ๋ฉ์๋๋ก ๋ง๋ค์ง ๋ชปํ ๋ฉ์๋๊ฐ ๋จ์ ์๋ค๋ฉด
์ด ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ๊ณจ๊ฒฉ ๊ตฌํ ํด๋์ค๋ฅผ ํ๋ ๋ง๋ค์ด ๋จ์ ๋ฉ์๋๋ค์ ์์ฑํด ๋ฃ๋๋ค.
๊ณจ๊ฒฉ ๊ตฌํ ํด๋์ค์๋ ํ์ํ๋ฉด public์ด ์๋ ํ๋์ ๋ฉ์๋๋ฅผ ์ถ๊ฐํด๋ ๋๋ค.
๊ฐ๋จํ ์๋ก Map.Entry ์ธํฐํ์ด์ค๋ฅผ ์ดํด๋ณด์.
interface Entry<K, V> {
/**
* Returns the key corresponding to this entry.
*
* @return the key corresponding to this entry
* @throws IllegalStateException implementations may, but are not
* required to, throw this exception if the entry has been
* removed from the backing map.
*/
K getKey();
/**
* Returns the value corresponding to this entry. If the mapping
* has been removed from the backing map (by the iterator's
* {@code remove} operation), the results of this call are undefined.
*
* @return the value corresponding to this entry
* @throws IllegalStateException implementations may, but are not
* required to, throw this exception if the entry has been
* removed from the backing map.
*/
V getValue();
/**
* Replaces the value corresponding to this entry with the specified
* value (optional operation). (Writes through to the map.) The
* behavior of this call is undefined if the mapping has already been
* removed from the map (by the iterator's {@code remove} operation).
*
* @param value new value to be stored in this entry
* @return old value corresponding to the entry
* @throws UnsupportedOperationException if the {@code put} operation
* is not supported by the backing map
* @throws ClassCastException if the class of the specified value
* prevents it from being stored in the backing map
* @throws NullPointerException if the backing map does not permit
* null values, and the specified value is null
* @throws IllegalArgumentException if some property of this value
* prevents it from being stored in the backing map
* @throws IllegalStateException implementations may, but are not
* required to, throw this exception if the entry has been
* removed from the backing map.
*/
V setValue(V value);
/**
* Compares the specified object with this entry for equality.
* Returns {@code true} if the given object is also a map entry and
* the two entries represent the same mapping. More formally, two
* entries {@code e1} and {@code e2} represent the same mapping
* if<pre>
* (e1.getKey()==null ?
* e2.getKey()==null : e1.getKey().equals(e2.getKey())) &&
* (e1.getValue()==null ?
* e2.getValue()==null : e1.getValue().equals(e2.getValue()))
* </pre>
* This ensures that the {@code equals} method works properly across
* different implementations of the {@code Map.Entry} interface.
*
* @param o object to be compared for equality with this map entry
* @return {@code true} if the specified object is equal to this map
* entry
*/
boolean equals(Object o);
/**
* Returns the hash code value for this map entry. The hash code
* of a map entry {@code e} is defined to be: <pre>
* (e.getKey()==null ? 0 : e.getKey().hashCode()) ^
* (e.getValue()==null ? 0 : e.getValue().hashCode())
* </pre>
* This ensures that {@code e1.equals(e2)} implies that
* {@code e1.hashCode()==e2.hashCode()} for any two Entries
* {@code e1} and {@code e2}, as required by the general
* contract of {@code Object.hashCode}.
*
* @return the hash code value for this map entry
* @see Object#hashCode()
* @see Object#equals(Object)
* @see #equals(Object)
*/
int hashCode();
/**
* Returns a comparator that compares {@link Map.Entry} in natural order on key.
*
* <p>The returned comparator is serializable and throws {@link
* NullPointerException} when comparing an entry with a null key.
*
* @param <K> the {@link Comparable} type of then map keys
* @param <V> the type of the map values
* @return a comparator that compares {@link Map.Entry} in natural order on key.
* @see Comparable
* @since 1.8
*/
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> comparingByKey() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}
/**
* Returns a comparator that compares {@link Map.Entry} in natural order on value.
*
* <p>The returned comparator is serializable and throws {@link
* NullPointerException} when comparing an entry with null values.
*
* @param <K> the type of the map keys
* @param <V> the {@link Comparable} type of the map values
* @return a comparator that compares {@link Map.Entry} in natural order on value.
* @see Comparable
* @since 1.8
*/
public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K, V>> comparingByValue() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getValue().compareTo(c2.getValue());
}
/**
* Returns a comparator that compares {@link Map.Entry} by key using the given
* {@link Comparator}.
*
* <p>The returned comparator is serializable if the specified comparator
* is also serializable.
*
* @param <K> the type of the map keys
* @param <V> the type of the map values
* @param cmp the key {@link Comparator}
* @return a comparator that compares {@link Map.Entry} by the key.
* @since 1.8
*/
public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
}
/**
* Returns a comparator that compares {@link Map.Entry} by value using the given
* {@link Comparator}.
*
* <p>The returned comparator is serializable if the specified comparator
* is also serializable.
*
* @param <K> the type of the map keys
* @param <V> the type of the map values
* @param cmp the value {@link Comparator}
* @return a comparator that compares {@link Map.Entry} by the value.
* @since 1.8
*/
public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
}
}
getKey, getValue๋ ํ์คํ ๊ธฐ๋ฐ ๋ฉ์๋์ด๋ฉฐ, ์ ํ์ ์ผ๋ก setValue๋ ํฌํจํ ์ ์๋ค.
์ด ์ธํฐํ์ด์ค๋ equals์ hashCode์ ๋์ ๋ฐฉ์๋ ์ ์ํ์ฌ ๊ตฌํ์ฒด์์ ์ด ๋ฉ์๋๋ค์ ์ฌ์ ์ํ๋๋ก ๊ฐ์ ํ๋ค.
์๋๋ Map.Entry ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ AbstractMapEntry ์ถ์ ํด๋์ค์ด๋ค.
import java.util.*;
// ์ฝ๋ 20-2 ๊ณจ๊ฒฉ ๊ตฌํ ํด๋์ค (134-135์ชฝ)
public abstract class AbstractMapEntry<K, V>
implements Map.Entry<K, V> {
// ๋ณ๊ฒฝ ๊ฐ๋ฅํ ์ํธ๋ฆฌ๋ ์ด ๋ฉ์๋๋ฅผ ๋ฐ๋์ ์ฌ์ ์ํด์ผ ํ๋ค.
@Override
public V setValue(V value) {
throw new UnsupportedOperationException();
}
// Map.Entry.equals์ ์ผ๋ฐ ๊ท์ฝ์ ๊ตฌํํ๋ค.
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?, ?> e = (Map.Entry) o;
return Objects.equals(e.getKey(), getKey())
&& Objects.equals(e.getValue(), getValue());
}
// Map.Entry.hashCode์ ์ผ๋ฐ ๊ท์ฝ์ ๊ตฌํํ๋ค.
@Override
public int hashCode() {
return Objects.hashCode(getKey())
^ Objects.hashCode(getValue());
}
@Override
public String toString() {
return getKey() + "=" + getValue();
}
}
Object ๋ฉ์๋๋ค์ ๋ํดํธ ๋ฉ์๋๋ก ์ ๊ณตํด์๋ ์ ๋๋ฏ๋ก ํด๋น ๋ฉ์๋๋ค์ ๋ชจ๋ ์ด ๊ณจ๊ฒฉ ๊ตฌํ ํด๋์ค์ ๊ตฌํํ๋ค.
toString๋ ๊ธฐ๋ฐ ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๊ตฌํํด๋จ๋ค.
๊ณจ๊ฒฉ ๊ตฌํ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์์ํด์ ์ฌ์ฉํ๋ ๊ฑธ ๊ฐ์ ํ๋ฏ๋ก item 19์์ ์ด์ผ๊ธฐํ ์ค๊ณ ๋ฐ ๋ฌธ์ํ ์ง์นจ์ ๋ชจ๋ ๋ฐ๋ผ์ผ ํ๋ค.
๊ฐ๋ตํ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ์ ์ฝ๋์์๋ ๋ฌธ์ํ ์ฃผ์์ ์๋ตํ์ง๋ง
์ธํฐํ์ด์ค์ ์ ์ํ ๋ํดํธ ๋ฉ์๋๋ ๋ณ๋์ ์ถ์ ํด๋์ค๋ ๊ณจ๊ฒฉ ๊ตฌํ์ ๋ฐ๋์ ๊ทธ ๋์ ๋ฐฉ์์ ์ ์ ๋ฆฌํด ๋ฌธ์๋ก ๋จ๊ฒจ์ผ ํ๋ค.
ํํธ ๋จ์ ๊ตฌํ์ ๊ณจ๊ฒฉ ๊ตฌํ์ ์์ ๋ณ์ข ์ด๋ผ๊ณ ํ ์ ์๋ค. AbstractMap.SimpleEntry๊ฐ ์ข์ ์๋ค.
public static class SimpleEntry<K, V> implements Entry<K, V>, Serializable {
private static final long serialVersionUID = -8499721149061103585L;
private final K key;
private V value;
public SimpleEntry(K key, V value) {
this.key = key;
this.value = value;
}
public SimpleEntry(Entry<? extends K, ? extends V> entry) {
this.key = entry.getKey();
this.value = entry.getValue();
}
public K getKey() {
return this.key;
}
public V getValue() {
return this.value;
}
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof Entry)) {
return false;
} else {
Entry<?, ?> e = (Entry)o;
return AbstractMap.eq(this.key, e.getKey()) && AbstractMap.eq(this.value, e.getValue());
}
}
public int hashCode() {
return (this.key == null ? 0 : this.key.hashCode()) ^ (this.value == null ? 0 : this.value.hashCode());
}
public String toString() {
return this.key + "=" + this.value;
}
}
๋จ์ ๊ตฌํ๋ ๊ณจ๊ฒฉ ๊ตฌํ๊ณผ ๊ฐ์ด ์์์ ์ํด ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ๊ฒ์ด์ง๋ง ์ถ์ ํด๋์ค๊ฐ ์๋๋ ์ ์ด ๋ค๋ฅด๋ค.
๋ ๋ฆฝ๋ ์ถ์ ํด๋์ค์ ํํ๋ก๋ ๋ํดํธ ๋ฉ์๋๋ก ์ด๋ค์ง ์ธํฐํ์ด์ค์ ํํ๋ก๋ ๊ณจ๊ฒฉ ๊ตฌํ์ ์ ๋๋ก ์ค๊ณํ๋ค๋ฉด
๊ทธ ์ธํฐํ์ด์ค๋ก ๋๋ฆ์ ๊ตฌํ์ ๋ง๋ค๋ ค๋ ํ๋ก๊ทธ๋๋จธ์ ์ผ์ ์๋นํ ๋์ด์ค๋ค.
์๋ฅผ ๋ค์ด ๋ค์ ์ฝ๋๋ ์๋ฒฝํ ๋์ํ๋ List ๊ตฌํ์ฒด๋ฅผ ๋ฐํํ๋ AbstractList ๊ณจ๊ฒฉ ๊ตฌํ์ด ์ ์ฉ๋ ์ ์ ํฉํฐ๋ฆฌ๋ฉ์๋์ด๋ค.
static List<Integer> intArrayAsList(int[] a) {
Objects.requireNonNull(a);
// ๋ค์ด์๋ชฌ๋ ์ฐ์ฐ์๋ฅผ ์ด๋ ๊ฒ ์ฌ์ฉํ๋ ๊ฑด ์๋ฐ 9๋ถํฐ ๊ฐ๋ฅํ๋ค.
// ๋ ๋ฎ์ ๋ฒ์ ์ ์ฌ์ฉํ๋ค๋ฉด <Integer>๋ก ์์ ํ์.
return new AbstractList<>() {
@Override public Integer get(int i) {
return a[i]; // ์คํ ๋ฐ์ฑ(์์ดํ
6)
}
@Override public Integer set(int i, Integer val) {
int oldVal = a[i];
a[i] = val; // ์คํ ์ธ๋ฐ์ฑ
return oldVal; // ์คํ ๋ฐ์ฑ
}
@Override public int size() {
return a.length;
}
};
}
List ๊ตฌํ์ฒด๊ฐ ์ฌ๋ฌ๋ถ์๊ฒ ์ ๊ณตํ๋ ๊ธฐ๋ฅ๋ค์ ์๊ฐํ๋ฉด
์ด ์ฝ๋๋ ๊ณจ๊ฒฉ ๊ตฌํ์ ํ์ ์ ๋ณด์ฌ์ฃผ๋ ์ธ์์ ์ธ ์๋ผ ํ ์ ์๋ค.
์ด ์๋ int ๋ฐฐ์ด์ ๋ฐ์ Integer ์ธ์คํด์ค์ ๋ฆฌ์คํธ ํํ๋ก ๋ณด์ฌ์ฃผ๋ ์ด๋ํฐ์ด๊ธฐ๋ ํ๋ค.
int ๊ฐ๊ณผ Integer ์ธ์คํด์ค ์ฌ์ด์ ๋ณํ(๋ฐ์ฑ๊ณผ ์ธ๋ฐ์ฑ) ๋๋ฌธ์ ์ฑ๋ฅ์ ๊ทธ๋ฆฌ ์ข์ง ์๋ค.
๋ํ, ์ด ๊ตฌํ์์ ์ต๋ช ํด๋์ค(item 24) ํํ๋ฅผ ์ฌ์ฉํ์์ ์ฃผ๋ชฉํ ํ์๋ ์๋ค.
๊ณจ๊ฒฉ ๊ตฌํ ํด๋์ค์ ์๋ฆ๋ค์์ ์ถ์ ํด๋์ค์ฒ๋ผ ๊ตฌํ์ ๋์์ฃผ๋ ๋์์
์ถ์ ํด๋์ค๋ก ํ์ ์ ์ ์ํ ๋ ๋ฐ๋ผ์ค๋ ์ฌ๊ฐํ ์ ์ฝ์์๋ ์์ ๋กญ๋ค๋ ์ ์ ์๋ค.
๊ณจ๊ฒฉ ๊ตฌํ์ ํ์ฅํ๋ ๊ฒ์ผ๋ก ์ธํฐํ์ด์ค ๊ตฌํ์ด ๊ฑฐ์ ๋๋์ง๋ง ๊ผญ ์ด๋ ๊ฒ ํด์ผ ํ๋ ๊ฒ์ ์๋๋ค.
๊ตฌ์กฐ์ ๊ณจ๊ฒฉ ๊ตฌํ์ ํ์ฅํ์ง ๋ชปํ๋ ์ฒ์ง๋ผ๋ฉด ์ธํฐํ์ด์ค๋ฅผ ์ง์ ๊ตฌํํด์ผ ํ๋ค.
์ด๋ฐ ๊ฒฝ์ฐ๋ผ๋ ์ธํฐํ์ด์ค๊ฐ ์ง์ ์ ๊ณตํ๋ ๋ํดํธ ๋ฉ์๋์ ์ด์ ์ ์ฌ์ ํ ๋๋ฆด ์ ์๋ค.
๋ํ, ๊ณจ๊ฒฉ ๊ตฌํ ํด๋์ค๋ฅผ ์ฐํ์ ์ผ๋ก ์ด์ฉํ ์๋ ์๋ค.
์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ํด๋์ค์์ ํด๋น ๊ณจ๊ฒฉ ๊ตฌํ์ ํ์ฅํ private ๋ด๋ถ ํด๋์ค๋ฅผ ์ ์ํ๊ณ
๊ฐ ๋ฉ์๋ ํธ์ถ์ ๋ด๋ถ ํด๋์ค์ ์ธ์คํด์ค์ ์ ๋ฌํ๋ ๊ฒ์ด๋ค.
item 18์์ ๋ค๋ฃฌ ๋ํผํด๋์ค์ ๋น์ทํ ์ด ๋ฐฉ์์ ์๋ฎฌ๋ ์ดํธํ ๋ค์ค ์์์ด๋ผ ํ๋ค.