item 13 incheol - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

Effective Java 3e ์•„์ดํ…œ 13๋ฅผ ์š”์•ฝํ•œ ๋‚ด์šฉ ์ž…๋‹ˆ๋‹ค.

๋ฉ”์„œ๋“œ ํ•˜๋‚˜ ์—†๋Š” cloneable ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋Œ€์ฒด ๋ฌด์Šจ ์ผ์„ ํ• ๊นŒ?

์ด ์ธํ„ฐํŽ˜์ด์Šค๋Š” Object์˜ protected ๋ฉ”์„œ๋“œ์ธ clone์˜ ๋™์ž‘ ๋ฐฉ์‹์„ ๊ฒฐ์ •ํ•œ๋‹ค. Cloneable์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค์—์„œ clone์„ ํ˜ธ์ถœํ•˜๋ฉด ๊ทธ ๊ฐ์ฒด์˜ ํ•„๋“œ๋“ค์„ ํ•˜๋‚˜ํ•˜๋‚˜ ๋ณต์‚ฌํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค์—์„œ ํ˜ธ์ถœํ•˜๋ฉด CloneNotSupportedException์„ ๋˜์ง„๋‹ค.

public class Stack {
	private Object[] elements;
	private int size = 0;
	...
}

Stack ํด๋ž˜์Šค๋ฅผ clone ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

๋ฐ˜ํ™˜๋œ Stack ์ธ์Šคํ„ด์Šค์˜ size ํ•„๋“œ๋Š” ์˜ฌ๋ฐ”๋ฅธ ๊ฐ’์„ ๊ฐ–๊ฒ ์ง€๋งŒ, elements ํ•„๋“œ๋Š” ์›๋ณธ Stack ์ธ์Šคํ„ด์Šค์™€ ๋˜‘๊ฐ™์€ ๋ฐฐ์—ด์„ ์ฐธ์กฐํ•  ๊ฒƒ์ด๋‹ค. ์›๋ณธ์ด๋‚˜ ๋ณต์ œ๋ณธ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๋‹ค๋ฅธ ํ•˜๋‚˜๋„ ์ˆ˜์ •๋˜์–ด ๋ถˆ๋ณ€์‹์„ ํ•ด์นœ๋‹ค๋Š” ์ด์•ผ๊ธฐ๋‹ค.

clone ๋ฉ”์„œ๋“œ๋Š” ์‚ฌ์‹ค์ƒ ์ƒ์„ฑ์ž์™€ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๋‚ธ๋‹ค.

์ฆ‰, clone์€ ์›๋ณต ๊ฐ์ฒด์— ์•„๋ฌด๋Ÿฐ ํ•ด๋ฅผ ๋ผ์น˜์ง€ ์•Š๋Š” ๋™์‹œ์— ๋ณต์ œ๋œ ๊ฐ์ฒด์˜ ๋ถˆ๋ณ€์‹์„ ๋ณด์žฅํ•ด์•ผ ํ•œ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ elements ๋ฐฐ์—ด์˜ clone์„ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

@Override
public Stack clone() {
	try {
		Stack result = (Stack) super.clone();
		result.elements = elements.clone();
		return result;
	} catch (CloneNotSupportedException e) {
		throw new AssertionError();
	}
}

๋”ฐ๋ผ์„œ ๋ฐฐ์—ด์„ ๋ณต์ œํ•  ๋•Œ๋Š” ๋ฐฐ์—ด์˜ clone ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ๊ถŒ์žฅํ•œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ clone์„ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ๋•Œ๋„ ์žˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ํ•ด์‹œํ…Œ์ด๋ธ”์šฉ clone ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž. ํ•ด์‹œํ…Œ์ด๋ธ” ๋‚ด๋ถ€๋Š” ๋ฒ„ํ‚ท๋“ค์˜ ๋ฐฐ์—ด์ด๊ณ , ๊ฐ ๋ฒ„ํ‚ท์€ ํ‚ค-๊ฐ’ ์Œ์„ ๋‹ด๋Š” ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ์—”ํŠธ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.

public class HashTable implements Cloneable {
	private Entry[] buckets = ...;

	private static class Entry {
		final Object key;
		Object value;
		Entry next;
		
		Entry(Object key, Object value, Entry next) {
			this.key = key;
			this.value = value;
			this.next = next;
		}
	}
	... // ๋‚˜๋จธ์ง€ ์ฝ”๋“œ๋Š” ์ƒ๋žต
}

@Override
public HashTable clone() {
	try {
		HashTable result = (HashTable) super.clone();
		result.buckets = buckets.clone();
		return result;
	} catch (CloneNotSupportedException e) {
		throw new AssertionError();
	}
}

๋ณต์ œ๋ณธ์€ ์ž์‹ ๋งŒ์˜ ๋ฒ„ํ‚ท ๋ฐฐ์—ด์„ ๊ฐ–์ง€๋งŒ, ์ด ๋ฐฐ์—ด์€ ์›๋ณธ๊ณผ ๊ฐ™์€ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์›๋ณธ๊ณผ ๋ณต์ œ๋ณธ ๋ชจ๋‘ ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ๋™์ž‘ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์ƒ๊ธด๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ๊ฐ ๋ฒ„ํ‚ท์„ ๊ตฌ์„ฑํ•˜๋Š” ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณต์‚ฌํ•ด์•ผ ํ•œ๋‹ค.

public class HashTable implements Cloneable {
	...

	Entry deepCopy() {
		return new Entry(key, value, next == null ? null : next.deepCopy());
	}

	@Override
	public HashTable clone() {
		try {
			HashTable result = (HashTable) super.clone();
			result.buckets = new Entry[buckets.length];
			for (int i = 0; i < buckets.length; i++)
				if (buckets[i] != null)
					result.buckets[i] = buckets[i].deepCopy();
				return result;
		} catch (CloneNotSupportedException e) {
			throw new AssertionError();
		}
}

์ด๋•Œ Entry์˜ deepCopy ๋ฉ”์„œ๋“œ๋Š” ์ž์‹ ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ ์ „์ฒด๋ฅผ ๋ณต์‚ฌํ•˜๊ธฐ ์œ„ํ•ด ์ž์‹ ์„ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•œ๋‹ค.

Cloneable์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ชจ๋“  ํด๋ž˜์Šค๋Š” clone์„ ์žฌ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋•Œ ์ ‘๊ทผ ์ œํ•œ์ž๋Š” public์œผ๋กœ ๋ฐ˜ํ™˜ ํƒ€์ž…์€ ํด๋ž˜์Šค ์ž์‹ ์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ๊ฐ€์žฅ ๋จผ์ € super.clone์„ ํ˜ธ์ถœํ•œ ํ›„ ํ•„์š”ํ•œ ํ•„๋“œ๋ฅผ ์ „๋ถ€ ์ ์ ˆํžˆ ์ˆ˜์ •ํ•œ๋‹ค.

๊ธฐ๋ณธ ํƒ€์ž… ํ•„๋“œ์™€ ๋ถˆ๋ณ€ ๊ฐ์ฒด ์ฐธ์กฐ๋งŒ ๊ฐ–๋Š” ํด๋ž˜์Šค๋ผ๋ฉด ์•„๋ฌด ํ•„๋“œ๋„ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ๋‹จ, ์ผ๋ จ๋ฒˆํ˜ธ๋‚˜ ๊ณ ์œ  ID๋Š” ๋น„๋ก ๊ธฐ๋ณธ ํƒ€์ž…์ด๋‚˜ ๋ถˆ๋ณ€์ผ์ง€๋ผ๋„ ์ˆ˜์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด ๋ชจ๋“  ์ž‘์—…์ด ๊ผญ ํ•„์š”ํ•œ ๊ฑธ๊นŒ?

๋‹คํ–‰ํžˆ๋„ ์ด์ฒ˜๋Ÿผ ๋ณต์žกํ•œ ๊ฒฝ์šฐ๋Š” ๋“œ๋ฌผ๋‹ค. Cloneable์„ ์ด๋ฏธ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•œ๋‹ค๋ฉด ์–ด์ฉ” ์ˆ˜ ์—†์ด clone์„ ์ž˜ ์ž‘๋™ํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์€ ์ƒํ™ฉ์—์„œ๋Š” ๋ณต์‚ฌ ์ƒ์„ฑ์ž์™€ ๋ณต์‚ฌ ํŒฉํ„ฐ๋ฆฌ๋ผ๋Š” ๋” ๋‚˜์€ ๊ฐ์ฒด ๋ณต์‚ฌ ๋ฐฉ์‹์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ณต์‚ฌ ์ƒ์„ฑ์ž๋ž€ ๋‹จ์ˆœํžˆ ์ž์‹ ๊ณผ ๊ฐ™์€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ๋งํ•œ๋‹ค.

๋ณต์‚ฌ ์ƒ์„ฑ์ž์™€ ๋ณต์‚ฌ ํŒฉํ„ฐ๋ฆฌ๋Š” ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ๊ตฌํ˜„ํ•œ '์ธํ„ฐํŽ˜์ด์Šค'ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

ํ•ต์‹ฌ ์ •๋ฆฌ

Cloneable์ด ๋ชฐ๊ณ  ์˜จ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ๋˜์งš์–ด๋ดค์„ ๋•Œ, ์ƒˆ๋กœ์šด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” ์ ˆ๋Œ€ Cloneable์„ ํ™•์žฅํ•ด์„œ๋Š” ์•ˆ ๋˜๋ฉฐ, ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋„ ์ด๋ฅผ ๊ตฌํ˜„ํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค. final ํด๋ž˜์Šค๋ผ๋ฉด Cloneable์„ ๊ตฌํ˜„ํ•ด๋„ ์œ„ํ—˜์ด ํฌ์ง€ ์•Š์ง€๋งŒ, ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ด€์ ์—์„œ ๊ฒ€ํ† ํ•œ ํ›„ ๋ณ„๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ์—†์„ ๋•Œ๋งŒ ๋“œ๋ฌผ๊ฒŒ ํ—ˆ์šฉํ•ด์•ผ ํ•œ๋‹ค. ๊ธฐ๋ณธ ์›์น™์€ '๋ณต์ œ ๊ธฐ๋Šฅ์€ ์ƒ์„ฑ์ž์™€ ํŒฉํ„ฐ๋ฆฌ๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒŒ ์ตœ๊ณ '๋ผ๋Š” ๊ฒƒ์ด๋‹ค. ๋‹จ, ๋ฐฐ์—ด๋งŒ์€ clone ๋ฉ”์„œ๋“œ ๋ฐฉ์‹์ด ๊ฐ€์žฅ ๊น”๋”ํ•œ ์ด ๊ทœ์น™์˜ ํ•ฉ๋‹นํ•œ ์˜ˆ์™ธ๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.