문서의 선택한 두 판 사이의 차이를 보여줍니다.
양쪽 이전 판 이전 판 다음 판 | 이전 판 마지막 판 양쪽 다음 판 | ||
study:java:javachobo:appendix [2010/03/19 21:11] gauryan |
study:java:javachobo:appendix [2010/03/19 22:23] gauryan |
||
---|---|---|---|
줄 1: | 줄 1: | ||
====== JDK 1.5에 추가된 기능 ====== | ====== JDK 1.5에 추가된 기능 ====== | ||
+ | |||
+ | ===== StringBuilder ===== | ||
+ | StringBuilder 가 새로 추가되었다. StringBuilder 는 StringBuffer 와 완전히 동일한 클래스이다. 다만 동기화(synchronization)처리를 하지 않기 때문에 멀티쓰레드 프로그래밍에서는 사용하면 안 되지만 멀티쓰레드 프로그래밍이 아닌 경우에는 StringBuffer 보다 바른 성능을 보장한다. | ||
+ | 동기화의 여부를 제외하고 두 클래스가 기능상으로 완전히 동일하기 때문에 코드에서 StringBuffer 를 StringBuilder 로 바꾸기만 하면 된다. 즉, StringBuffer 타입의 참조변수를 선언한 부분과 StringBuffer 의 생성자만 바꾸면 된다는 말이다. | ||
+ | <code java> | ||
+ | StringBuffer sb; | ||
+ | sb = new StringBuffer(); | ||
+ | sb.append(" | ||
+ | </ | ||
+ | <code java> | ||
+ | StringBuilder sb; | ||
+ | sb = new StringBuilder(); | ||
+ | sb.append(" | ||
+ | </ | ||
+ | StringBuffer도 충분히 성능이 좋기 때문에 성능향상이 반드시 필요한 경우를 제외하고는 기존에 작성한 코드에서 StringBuffer를 StringBuilder로 굳이 바꿀 필요는 없을 것이다. | ||
===== 오토박싱(autoboxing) ===== | ===== 오토박싱(autoboxing) ===== | ||
- | 컬렉션에는 객체로 저장해야하기 때문에 기본형 값을 저장하기 위해서는 Integer나 Long과 같은 Wrapper클래스를 사용해야했다. 그러나 이제부터는 기본형 값을 직접 컬렉션에 저장할 수 있다. 컴파일러에 의해서 자동적으로 Wrapper클래스로 변환되어 저장되는 | + | 컬렉션에는 객체로 저장해야하기 때문에 기본형 값을 저장하기 위해서는 Integer나 Long과 같은 Wrapper클래스를 사용해야했다. 그러나 이제부터는 기본형 값을 직접 컬렉션에 저장할 수 있다. 컴파일러에 의해서 자동적으로 Wrapper클래스로 변환되어 저장되는 |
+ | <code java> | ||
+ | ArrayList list = new ArrayList(); | ||
+ | list.add(new Integer(10)); | ||
+ | list.add(new Integer(20)); | ||
+ | list.add(new Integer(30)); | ||
+ | |||
+ | Integer i = (Integer)list.get(0); | ||
+ | int value = i.intValue(); | ||
+ | </ | ||
+ | 이전에는 위와 같은 코드를 사용했지만 이제는 아래와 같이 코드를 간략히 할 수 있다. | ||
+ | <code java> | ||
+ | ArrayList< | ||
+ | list.add(10); | ||
+ | list.add(20); | ||
+ | list.add(30); | ||
+ | |||
+ | int value = list.get(0); | ||
+ | </ | ||
===== 향상된 for 문 ===== | ===== 향상된 for 문 ===== | ||
줄 160: | 줄 193: | ||
**[주의]** 여기서 만일 Unit이 클래스가 아닌 인터페이스라 할지라도 키워드로 ' | **[주의]** 여기서 만일 Unit이 클래스가 아닌 인터페이스라 할지라도 키워드로 ' | ||
- | 예제 : / | + | * 예제 : / |
- | <code java> | + | |
import java.util.*; | import java.util.*; | ||
줄 200: | 줄 232: | ||
} | } | ||
</ | </ | ||
+ | |||
+ | Collections 클래스의 sort() 메서드의 선언부를 보면 다음과 같다. | ||
+ | <code java> | ||
+ | public static <T extends Comparable<? | ||
+ | --------------------------------- | ||
+ | | ||
+ | </ | ||
+ | - ArrayList 와 같이 List 인터페이스를 구현한 컬렉션을 매개변수의 타입으로 정의하고 있다. 그리고 그 컬렉션에는 ' | ||
+ | - ' | ||
+ | <code java> | ||
+ | public interface Comparable< | ||
+ | public int compareTo(T o); // 지정한 타입 T를 매개변수로 한다. | ||
+ | } | ||
+ | </ | ||
+ | Comparable 의 실제소스는 위와 같으며 이를 구현한 클래스의 예는 다음과 같다. | ||
+ | <code java> | ||
+ | class Student extends Person implements Comparable< | ||
+ | Student(int id, String name) { | ||
+ | super(id, name); | ||
+ | } | ||
+ | | ||
+ | public int compareTo(Person o) { | ||
+ | return this.id - o.id; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class Person { | ||
+ | int id; | ||
+ | String name; | ||
+ | | ||
+ | Person(int id, String name) { | ||
+ | this.id = id; | ||
+ | this.name = name; | ||
+ | } | ||
+ | | ||
+ | public String toString() { | ||
+ | return id + ":" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | Collections 의 sort()의 매개변수가 Comparable에 사용될 수 있는 타입이 Comparable 을 구현하는 클래스(Student)나 그 조상(Person)일 수 있다고 하였기 때문에 Student 객체를 담은 ArrayList 는 sort() 의 매개변수가 될 수 있는 모든 조건을 충족시킨다. | ||
+ | |||
+ | * 예제 : GenericsEx2.java <code java> | ||
+ | import java.util.*; | ||
+ | |||
+ | class Unit {} | ||
+ | class Tank extends Unit {} | ||
+ | class Dropship extends Unit {} | ||
+ | |||
+ | class GenericsEx2 { | ||
+ | ArrayList< | ||
+ | list.add(new Student(10, " | ||
+ | list.add(new Student(40, " | ||
+ | list.add(new Student(20, " | ||
+ | list.add(new Student(30, " | ||
+ | Conllections.sort(list); | ||
+ | | ||
+ | for(Person p : list) { | ||
+ | System.out.println(p); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class Student extends Person implements Comparable< | ||
+ | Student(int id, String name) { | ||
+ | super(id, name); | ||
+ | } | ||
+ | | ||
+ | // Comparable< | ||
+ | public int compareTo(Person o) { | ||
+ | return this.id - o.id; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class Person { | ||
+ | int id; | ||
+ | String name; | ||
+ | | ||
+ | Person(int id, String name) { | ||
+ | this.id = id; | ||
+ | this.name = name; | ||
+ | } | ||
+ | | ||
+ | public String toString() { | ||
+ | return id + ":" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== 타입에 안전한 열거형 (Typesafe enums) ===== | ||
+ | 이전까지 자바는 C언어와 달리 열거형이라는 것이 존재하지 않았으나 새로 추가되었다. 자바의 열거형은 C언어의 열거형보다 더 향상된 개념의 열거형으로 열거형이 갖는 값 뿐만아니라 타입까지 관리하기 때문에 보다 논리적인 오류를 줄일 수 있다. | ||
+ | <code java> | ||
+ | class Card { | ||
+ | static final int CLOVER | ||
+ | static final int HEART = 1; | ||
+ | static final int DIAMOND = 2; | ||
+ | static final int SPADE = 3; | ||
+ | | ||
+ | static final int TWO = 0; | ||
+ | static final int THREE = 1; | ||
+ | static final int FOUR = 2; | ||
+ | | ||
+ | final int kind; | ||
+ | final int num; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <code java> | ||
+ | class Card { | ||
+ | enum Kind { CLOVER, HEART, DIAMOND, SPADE } | ||
+ | enum Value { TWO, THREE, FOUR } | ||
+ | | ||
+ | final Kind kind; // 타입이 int가 아닌 Kind임에 유의하자. | ||
+ | final Value value; | ||
+ | } | ||
+ | </ | ||
+ | 이전 방식으로는 타입이 달라도 값이 같으면 조건식결과가 true였으나, | ||
+ | <code java> | ||
+ | if(Card.CLOVER == Card.TWO) | ||
+ | if(Card.Kind.CLOVER == Card.Value.TWO) // false | ||
+ | </ | ||
+ | |||
+ | * 예제 : EnumEx.java <code java> | ||
+ | import java.util.*; | ||
+ | |||
+ | class EnumEx { | ||
+ | public static void main(String[] args) { | ||
+ | Deck deck = new Deck(); | ||
+ | | ||
+ | System.out.println(deck.pick(0)); | ||
+ | System.out.println(deck.pick(1)); | ||
+ | System.out.println(deck.pick(2)); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class Card { | ||
+ | enum Kind { CLOVER, HEART, DIAMOND, SPADE } | ||
+ | enum Value { TWO, THREE, FOUR, FIVE, SIX, | ||
+ | | ||
+ | JACK, QUEEN, KING, ACE } | ||
+ | |||
+ | final Kind kind; | ||
+ | final Value value; | ||
+ | | ||
+ | Card(Kind kind, Value value) { | ||
+ | this.kind = kind; | ||
+ | this.value = value; | ||
+ | } | ||
+ | | ||
+ | Card() { | ||
+ | this(Kind.SPADE, | ||
+ | } | ||
+ | | ||
+ | public String toString() { | ||
+ | return " | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class Deck { | ||
+ | ArrayList< | ||
+ | | ||
+ | Deck() { | ||
+ | for(Card.Kind kind : Card.Kind.values()) { | ||
+ | for(Card.Value value : Card.Value.values()) { | ||
+ | cards.add(new Card(kind, value)); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | Card pick(int index) { | ||
+ | return cards.get(index); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== 가변인수 (Varargs) ===== | ||
+ | 기존에는 메서드의 매개변수 개수를 고정적으로 지정해주어야만 했으나 JDK 1.5 부터는 동적으로 매개변수의 개수를 지정해 줄 수 있게 되었다. | ||
+ | <code java> | ||
+ | public String concatenate(String s1, String s2) { /* 내용생략 */ } | ||
+ | public String concatenate(String s1, String s2, String s3) { /* 내용생략 */ } | ||
+ | public String concatenate(String s1, String s2, String s3, String s4) { /* 내용생략 */ } | ||
+ | ... | ||
+ | public String concatenate(String[] strArr) { /* 내용생략 */ } | ||
+ | </ | ||
+ | 문자열을 결합하여 반환하는 concatenate메서드를 위와 같이 오버로딩하여 정의하는 대신 아래와 같이 가변인수를 정의하면 된다. 가변인수는 ' | ||
+ | <code java> | ||
+ | public String concatenate(String... str) { /* 내용생략 */ } | ||
+ | </ | ||
+ | 가변인수의 대표적인 예는 PrintStream의 printf()와 MessageFormat의 format()이다. | ||
+ | <code java> | ||
+ | public PrintStream printf(String format, Object... args) { /* 내용생략 */ } | ||
+ | public static String format(String pattern, Object... arguments) { /* 내용생략 */ } | ||
+ | </ | ||
+ | 가변인수를 사용할 때 한 가지 주의해야할 점은 오버로딩을 하는 경우인데, | ||
+ | |||
+ | * 예제 : VarArgsEx1.java <code java> | ||
+ | class VarArgsEx1 { | ||
+ | public static void main(String[] args) { | ||
+ | System.out.println(concatenate(" | ||
+ | } | ||
+ | | ||
+ | static String concatenate(String delim, String... args) { | ||
+ | String result = ""; | ||
+ | | ||
+ | for(String str : args) { | ||
+ | result += str + delim; | ||
+ | } | ||
+ | | ||
+ | return result; | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | static String concatenate(String... args) { | ||
+ | return concatenate("", | ||
+ | } | ||
+ | */ | ||
+ | } | ||
+ | </ | ||
+ | concatenate 메서드는 매개변수로 입력된 문자열에 구분자를 사이에 포함시켜 결합해서 반환한다. 가변인수로 매개변수를 선언했기 때문에 문자열을 개수의 제약없이 매개변수로 지정할 수 있다. 위의 예제에서는 주석처리하였지만 concatenate 메서드의 또 다른 오버로딩된 메서드가 있다. | ||
+ | 이 두 메서드는 별 문제가 없어 보이지만 위의 예제에서 주석을 풀고 컴파일을 하면 아래와 같이 컴파일에러가 발생한다. | ||
+ | < | ||
+ | VarArgsEx1.java: | ||
+ | concatenate(java.lang.String, | ||
+ | method concatenate(java.lang.String...) in VarArgsEx1 match | ||
+ | | ||
+ | |||
+ | 1 error | ||
+ | </ | ||
+ | 에러의 내용을 살펴보면 두 오버로딩된 메서드를 구분되지 않아서 발생하는 것임을 알 수 있다. 가변인수를 선언한 메서드를 오버로딩할 때는 이와 같이 구별되지 못하는 경우가 발생하기 쉽기 때문에 주의해야 한다. 그래서 가능하면 가변인수를 사용한 메서드를 오버로딩하지 않는 것이 좋다. | ||
+ | |||
+ | ===== static import ===== | ||
+ | import 문을 사용하면 클래스의 패키지명을 생략할 수 있는 것과 같이 static import 문을 사용하면 static 멤버를 호출할 때 클래스명을 생략할 수 있다. 이러한 기능은 코딩을 편리하게 해주지만 남용하면 오히려 독이 될 수 있기 때문에 주의하도록 하자. | ||
+ | <code java> | ||
+ | import static java.lang.System.out; | ||
+ | import static java.lang.Math.*; | ||
+ | </ | ||
+ | 만일 위와 같이 static import 문을 선언하였다면, | ||
+ | <code java> | ||
+ | System.out.println(Math.random()); | ||
+ | </ | ||
+ | <code java> | ||
+ | out.println(random()); | ||
+ | </ | ||
+ | |||
+ | * 예제 : StaticImportEx1.java <code java> | ||
+ | import static java.lang.System.out; | ||
+ | import static java.lang.Math.*; | ||
+ | |||
+ | class StaticImportEx1 { | ||
+ | public static void main(String[] args) { | ||
+ | // System.out.println(Math.random()); | ||
+ | out.println(random()); | ||
+ | | ||
+ | // System.out.println(" | ||
+ | out.println(" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ |