A Tour of Java V Sungjoo Ha April 3rd, 2015 Sungjoo Ha 1 / 28
Review First principle 문제가생기면침착하게영어로구글에서찾아본다. 타입은가능한값의집합과연산의집합을정의한다. 기본형이아니라면이름표가메모리에달라붙는다. 클래스로사용자정의타입을만든다. 프로그래밍은복잡도관리가중요하다. OOP 는객체가서로메시지를주고받는방식으로프로그램을구성해서복잡도관리를꾀한다. Sungjoo Ha 2 / 28
Review 각각의객체는기본형을사용하는것과비슷한느낌으로사용할수있어야한다. 인스턴스는개별적인상태를가진다. 객체를사용하는약속과구현을분리하기위해 interface 를사용한다. 특정타입이보장하는약속을사용해서다양한타입이같은인터페이스를사용하는폴리모피즘을구현할수있다. 계층적구조를지닌개념을표현하기위해상속을사용한다. 가능하면 interface 를상속에비해선호하도록한다. Sungjoo Ha 3 / 28
Generic 컨테이너는일반적인개념이고특정타입에묶이지않는다. 컨테이너가특정타입만받길원하지않는다. 가령링크드리스트는임의의타입을지닌데이터를받게하고싶다. Sungjoo Ha 4 / 28
MovieDatabase Example 1 class MovieNode { String name; MovieNode next; class MovieList { MovieNode head; class GenreNode { String name; GenreNode next; MovieList movielist; class GenreList { GenreNode head; public class MovieDatabase { public static void main(string[] args) { GenreList genrelist = new GenreList(); 과제 2 의수도코드이다. 만약구현해야하는것이 Movie 와 Genre 두개가아니라 100 가지라면어떻게해야할까? Sungjoo Ha 5 / 28
Object-Based Node class Node { private Object object; public void set(object object) { this.object = object; public Object get() { return object; public class NodeTest { public static void main(string[] args) { Node node = new Node(); node.set(1); System.out.println(node.get()); Node node2 = new Node(); node2.set("node"); System.out.println(node2.get()); 임의의타입을받을수있는링크드리스트의노드예제이다. 자바의모든클래스는 Object 클래스를상속받으므로이런방식으로작성하는것이가능하다. Sungjoo Ha 6 / 28
Object-Based Node public class NodeTest { public static void main(string[] args) { Node node = new Node(); node.set(1); System.out.println(node.get()); Integer i = (Integer) node.get(); System.out.println(i); String str = (String) node.get(); System.out.println(str); 위의코드는컴파일오류가발생하지않는다. 하지만런타임에오류가발생한다. Object 와타입캐스팅을사용하는접근은넣는데이터와나오는데이터의타입을보장할수없다. Sungjoo Ha 7 / 28
Generic Class 프로그램에버그가발생하는것은당연하다. 이를프로그램실행중에발견하는것보다컴파일타임에발견하길원한다. 제네릭 (Generic) 을사용해서컴파일타임에버그를발견할확률을높인다. Sungjoo Ha 8 / 28
Generic Node class NodeGeneric<T> { private T t; public void set(t t) { this.t = t; public T get() { return t; public class NodeTest2 { public static void main(string[] args) { NodeGeneric<Integer> node = new NodeGeneric<Integer>(); node.set(1); System.out.println(node.get()); NodeGeneric<String> node2 = new NodeGeneric<String>(); node2.set("node"); System.out.println(node2.get()); Integer i = node.get(); System.out.println(i); // String str = node.get(); // compile error // System.out.println(str); Sungjoo Ha 9 / 28
Generic Node 제네릭타입은타입을인자로받는클래스나인터페이스를지칭한다. <T > 가 NodeGeneric 이제네릭클래스임을표시한다. <> 는타입인자를표시하며 T 는타입변수를나타낸다. 기존 Node 클래스와비교해보면 Object 가 T 로변한것을알수있다. T 는기본형이아닌임의의타입이들어올수있다. 클래스, 인터페이스, 등등 암묵적인약속으로타입인자는대문자하나로표시한다. 프로그래머의원활한이해를위해 Sungjoo Ha 10 / 28
Object-Based MovieDatabase class Movie { String name; class Genre { String name; LinkedList movielist; class Node { Object obj; Node next; class LinkedList { Node head; public class MovieDatabase2 { public static void main(string[] args) { LinkedList genrelist = new LinkedList(); Sungjoo Ha 11 / 28
Generic MovieDatabase class Movie { String name; class Genre { String name; LinkedList<Movie> movielist; class Node<T> { T obj; Node<T> next; class LinkedList<T> { Node<T> head; public class MovieDatabase3 { public static void main(string[] args) { LinkedList<Genre> genrelist = new LinkedList<Genre>(); Sungjoo Ha 12 / 28
Object vs Generic class Node { final Object item; public Node(Object obj) { this.item = obj; class Node<T> { final T item; public Node(T obj) { this.item = obj; 코드상차이는적다. 제네릭이가져다주는이득을음미해보자. Sungjoo Ha 13 / 28
Generic 제네릭을통해컴파일타임에더강력한타입체크를할수있다. 제네릭을통해타입캐스팅을최소화할수있다. 제네릭을통해다양한타입에적용할수있는알고리즘을작성한다. 제네릭은컴파일시간에다양한작업을하며추가적인런타임부하가없다. Sungjoo Ha 14 / 28
Diamond NodeGeneric<Integer> node = new NodeGeneric<>(); node.set(1); System.out.println(node.get()); 자바 7 부터컨스트럭터호출에필요한타입인자를생략할수있다. 컴파일러가추론할수있다면 이를흔히다이아몬드라부른다. Sungjoo Ha 15 / 28
Multiple Type Parameters interface Pair<K, V> { public K getkey(); public V getvalue(); class MyPair<K, V> implements Pair<K, V> { private K key; private V value; public MyPair(K key, V value) { this.key = key; this.value = value; public K getkey() { return key; public V getvalue() { return value; 제네릭클래스는여러타입인자를받을수있다. 제네릭인터페이스도제네릭클래스와같은규칙을따른다. MyPair 클래스는 Pair 인터페이스를구현하고있다. Sungjoo Ha 16 / 28
Multiple Type Parameters Pair<String, Integer> p1 = new MyPair<String, Integer>("Dice", 6); Pair<String, String> p2 = new MyPair<>("Hello", "World"); Pair<String, NodeGeneric<Integer>> p = new MyPair<>("Data", new NodeGeneric<Integer>(10)); 처음예제에서 K 는 String, V 는 Integer 로초기화된다. Autonodeing 에의해 Integer 타입을기대하는곳에 int 를바로넣어도된다. 타입을기대하는곳에인자화된타입 (parameterized type) 을넣어도된다. V 에 Node<Integer > 타입을넣어줬다. Sungjoo Ha 17 / 28
Generic Example class Node<T> { // FIXME implement this final T item; public Node(T obj) { this.item = obj; 과제 2 뼈대코드의일부이다. Node 클래스는타입인자 T 를받는다. 그러므로 Node 는임의의타입을받아서이를 item 에저장하는역할을한다. Sungjoo Ha 18 / 28
Generic Example class Genre implements Comparable<Genre> { @Override public int compareto(genre other) { // TODO implement this throw new UnsupportedOperationException(); 과제 2 뼈대코드의일부이다. Genre 클래스는 Comparable 인터페이스를구현하고있다. Comparable 인터페이스는제네릭인터페이스이다. public interface Comparable<T > int compareto(t o) Genre 는 Comparable 의 T 의위치에 Genre 를넣은것이다. 그러므로 int compareto(genre other) 를구현해야한다. 의미상 Genre 는다른 Genre 와비교할수있는타입임을뜻한다. Sungjoo Ha 19 / 28
Bounded Type Parameters 제네릭에서사용할수있는타입의종류를한정하고싶을때가있다. 가령숫자에대한작업을하는클래스는숫자타입만받았으면한다. 이를위해 bounded type parameter 를사용한다. Sungjoo Ha 20 / 28
Bounded Type Parameters class MyNumber<T extends Number> { private T t; public void set(t t) { this.t = t; public T get() { return t; public int intvalue() { return t.intvalue(); Bounded type parameter 를선언하기위해타입인자의이름뒤에 extends 와함께상한 (upper bound) 을표시한다. 이맥락에서 extends 는클래스의확장 (extends) 과인터페이스의구현 (implements) 을모두포함한다. 즉, 특정클래스만받거나특정인터페이스만받는것을전부 extends 로나타낸다. T 는 Number 클래스를상속받은클래스여야만한다. 그러므로 Number 클래스가제공하는 intvalue() 메소드를호출할수있다. Sungjoo Ha 21 / 28
Bounded Type Parameters public class BoundedType { public static void main(string[] args) { MyNumber<Double> a = new MyNumber<>(); a.set(10.2); System.out.println(a.intValue()); //MyNumber<String> b = new MyNumber<>(); // compile error MyNumber 클래스는타입인자가 Number 혹은그후손이어야한다. 그러므로 String 을타입인자로받으면컴파일오류가난다. Sungjoo Ha 22 / 28
Bounded Type Parameters Example class ArrayBox<T> { private T[] array; public ArrayBox(T[] array) { this.array = array; public int countgreaterthan(t elem) { int count = 0; for (T e: array) { if (e > elem) { count++; return count; public class Compare { public static void main(string[] args) { Integer[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10; ArrayBox<Integer> a = new ArrayBox<>(array); int count = a.countgreaterthan(5); System.out.println(count); 이코드의문제는무엇일까? Sungjoo Ha 23 / 28
Bounded Type Parameters Example class ArrayBox<T extends Comparable<T>> { private T[] array; public ArrayBox(T[] array) { this.array = array; public int countgreaterthan(t elem) { int count = 0; for (T e: array) { if (e.compareto(elem) > 0) { count++; return count; > 연산은기본형에서만가능하다. 임의의타입 T 를비교하기위해서는 T 가비교가능해야한다. 그러므로 T 는 Comparable<T > 인터페이스를구현해야만한다. 비교는 compareto(t) 메소드를사용한다. 이를위해 T 는 bounded type parameter 이어야하며상한 (upper bound) 이 Comparable<T > 이다. Sungjoo Ha 24 / 28
Bounded Type Parameters Example public class MyLinkedList<T extends Comparable<T>> implements Iterable<T> 과제 2 뼈대코드의일부이다. MyLinkedList 는타입인자 T 를받는다. T 는 Comparable<T > 타입이어야한다. 즉, 다른 T 와비교가능해야한다. T 는 int compareto(t o) 메소드를구현해야한다. MyLinkedList 는 Iterable<T > 를구현한다. Iterator<T >iterator() 메소드를제공해야한다. Sungjoo Ha 25 / 28
Bounded Type Parameters Example MyLinkedList<String> mylist = new MyLinkedList<>(); MyLinkedList<Genre> mylist2 = new MyLinkedList<>(); String 은 Comparable<String > 을구현한다. 그러므로 MyLinkedList 의타입인자로사용할수있다. 마찬가지로 Genre 도 Comparable<Genre > 를구현하므로타입인자로사용할수있다. class Genre implements Comparable<Genre > Sungjoo Ha 26 / 28
Generic 제네릭은방대한주제이다. 스스로공부하기바란다. 제네릭메소드 (generic method) 와일드카드 (wildcard) 타입이레이져 (type erasure) http://docs.oracle.com/javase/tutorial/java/ generics/index.html Sungjoo Ha 27 / 28
Advice 제네릭을통해다양한타입에적용할수있는알고리즘을작성한다. 코드의중복은피하고코드재활용성을높인다. 특정타입에묶이지않은일반적인개념 / 컨테이너를표현하기위해제네릭을사용한다. 제네릭을사용해서컴파일타임에버그를발견할확률을높인다. 제네릭을사용할때미리타입인자가만족해야하는요구사항을따져본다. Sungjoo Ha 28 / 28