6. 제네릭, 가변변수, 익명클래스, Collection프레임워크

제네릭

오버로딩을 대체할 수 있으며 유용하다.

메소드에 제네릭을 적용

1
2
3
4
5
6
7
8
public <T,P,Q,R> void println( T t ) {
System.out.println(t);
}

public static void main(String args[]) {
println( 10 );
println( true );
}

메소드 반환형에 제네릭 적용

1
2
3
4
5
6
7
public <T, P> List<P> println( T t ) {
System.out.println( t );

List<P> list = new ArrayList<P>();

return list;
}

제네릭 배열을 어떻게 동적으로 생성하느냐

1
2
3
4
5
6
7
8
9
10
11
12
13
public MyStack( E[] objects, int capacity ) {
//buffer = new E[ capacity ]; 오류발생
//방법1.
buffer = ( E[] ) Array.newInstance(objects.getClass(), capacity);
//방법2. 방법2가 더 선호된다. 객체를 생성하지 않아도 된다는점 때문에
buffer = ( E[] )Array.newInstance(Object.class, capacity);
//방법3. 방법 2와 일치하는방식이다.
buffer = ( E[] )new Object[capacity];
//방법 3을 제일 많이 쓴다.

this.capacity = capacity;
currentIndex = 0;
}

제네릭 호출 방식

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {

MyStack<String> stack = new MyStack<String>(3);
//String의 스택을 생성한다.

MyStack<?> stack = new MyStack<String>(3);
//모든 타입의 객체를 생성하겠다.

}

public .... f(List<? extends Shape>){
// Shape를 상속한 것들의 리스트를 파라미터로 받음
//와일드 카드를 사용해서 제네릭 타입 제한하기.
...
}

가변변수

가변변수를 배우기 전에는 파라미터에 배열을 넣을 생각을 할 것이다. 하지만 이를 대체할 수 있는것이 가변변수이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String args[]) {
println2( "둘리" );
println2( "둘리", "마이콜" );
println2( "둘리", "마이콜", "또치");

//println3( new String[]{"둘리", "마이콜", "또치"}); 배열사용

}
public static void println2(String ... params) {
for( String s : params){
System.out.println(s);
}
}

아래의 경우 Object를 파라미터로 주면 캐스팅을 계속 해줘야한다.

1
2
3
4
5
6
7
public <T> void println( T t) {
System.out.println(t);
}

public void println(Object o ) {
System.out.println(o);
}

익명클래스

파라미터를 전달하는 부분에서 객체를 생성하여 메소드를 호출.
객체를 생성하지 않고 메소드 호출부분에서 객체를 생성함.

1
2
3
4
5
6
7
8
9
//anonymous class object
draw( new Drawable() {

@Override
public void draw() {
// TODO Auto-generated method stub
System.out.println("한 번만 만들고 버릴 도형을 그렸습니다");
}
});

Collection

Collection인터페이스는 inteator() 메소드를 갖고 있다.
List, Set 클래스는 Collection클래스를 구현하며 List는 중복허용, 순서를 갖는다. 그러나 Set는 중복을 허용하지 않으며 순서를 갖지 않는다.
List인터페이스는 add, get, remove를 갖는다.
LinkedList, ArrayList가 List 인터페이스를 구현한다.

ArrayList는 빈번한 삽입,삭제가 일어나는 경우 사용하면 안된다. 그 과정이 길기 떄문에.
LinkedList는 삽입삭제가 유용하나 10000번째 놈이면 10000번을 next해야한다.

멀티스레드에서 ArrayList, LinkedList의 add를 사용할 때는 동기화 처리를 해줘야한다. 하지만 Vector은 멀티스레드 환경에서 동기화를 해주지 않아도 된다.

ArrayList , LinkedList, VectorTest2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class ArrayListTest {

public static void main(String[] args) {
List<String> list = new ArrayList<String>();
LinkedList<String>();
Vector<String>();

//삽입
list.add( "둘리" );
list.add( "마이콜" );
list.add( "도우넛" );

//순회1
int count = list.size();
for( int i = 0; i < count ; i++) {
String s = list.get( i );
System.out.println(i);
}

//제거
list.remove( 1 );

//순회2
Iterator<String> it = list.iterator();
while( it.hasNext() ) {
String s = it.next();
System.out.println( s );
}

//순회3
for( String s : list) {
System.out.println( s );
}
}
}

Vector

1.2 시대의 Vector인터페이스는 addElement, elementAt, removeElement, elements메소드를 갖고 있다. 그 후 1.2이후에 생긴 List를 구현하여 List의 메소드를 갖는다. Vector를 사용하려면 Vector 메소드를 사용하거나 List 인터페이스 내부의 메소드만 사용하든가 해야 복잡해지지 않는다.

과거 Vector을 사용하는 방식. 호환성 때문에 존재할뿐.. 사용일 지양하자.

VectorTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class VectorTest {
public static void main(String[] args) {
Vector<String> v = new Vector<String>();

v.addElement( "둘리" );
v.addElement( "마이콜" );
v.addElement( "도우넛" );

//순회1
Enumeration<String> e = v.elements();
while( e.hasMoreElements() ) {
String s = e.nextElement();
System.out.println( s );
}

//삭제
v.removeElementAt( 1 );

System.out.println("=====================");
//순회2
int count = v.size();
for( int i=0; i< count; i++) {
String s = v.elementAt( i );
System.out.println( s );
}
}
}

Set

Set 인터페이스는 key, value로 구성된다. key를 통해 value에 접근할 수 있다.
HashSet, TreeSet가 Map인터페이스를 구현한다.
hashCode를 오버라이드 하여 사용하여야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class HashSetTest {

public static void main(String[] args) {
Set<Value> set = new HashSet<Value>();

Value v1 =new Value(10);
Value v2 =new Value(5);
Value v3 =new Value(10);
Value v4 =new Value(20);

set.add(v1);
set.add(v2);
set.add(v3);
set.add(v4);

//존재여부 확인
System.out.println(set.contains(new Value(10)));

//삭제
set.remove( new Value(10) );

//순회
Iterator<Value> it = set.iterator();
while( it.hasNext() ){
Value v = it.next();
System.out.println(v);
}
}
}

성능향상을 위해 hash를 오버라이드 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Value {
private int value;

public Value( int value ) {
this.value = value;
}


@Override
public String toString() {
return "Value [value=" + value + "]";
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + value;
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Value other = (Value) obj;
if (value != other.value)
return false;
return true;
}

Stack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class StackTest {
public static void main(String[] args) {
Stack<String> stack = new Stack<String>();

stack.push("둘리");
stack.push("마이콜");
stack.push("도우넛");
stack.push("길동");

System.out.println( stack.isEmpty() );
System.out.println( stack.pop() );
System.out.println( stack.pop() );
System.out.println( stack.peek() ); //pop을 하지않고 확인만
System.out.println( stack.pop() );
System.out.println( stack.pop() );

//스택은 비어있는 경우 pop호출 시 예외가 발생한다.
System.out.println( stack.pop() );

}

}

Queue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class QueueTest {

public static void main(String[] args) {
Queue<String> queue = new LinkedList<String>();

queue.offer("둘리");
queue.offer("마이콜");
queue.offer("도우너");
queue.offer("길동");

System.out.println( queue.isEmpty() );
System.out.println( queue.poll() );
System.out.println( queue.poll() );

System.out.println( queue.peek() );

System.out.println( queue.poll() );
System.out.println( queue.poll() );

System.out.println( queue.isEmpty() );
System.out.println( queue.poll() );
//스택은 예외가 발생했지만 큐는 null이 리턴된다.
}
}

Map

Map 인터페이스가 존재하는데 HashMap, HashTable가 이를 구현한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<String, Integer>();

map.put("둘리", 100);
map.put("마이콜", 50);
map.put("도우넛", 80);
map.put("길동", 90);

//중복
map.put( "둘리" , 0); //덮어쓴다.

//auto unboxing
int score = map.get( "둘리" );
System.out.println(score);

map.remove( "둘리" );

//평균 ( 키를 모르는데 어떻게할까?)
int sum = 0;
Set<String> keySet = map.keySet();
Iterator<String> it = keySet.iterator();
while( it.hasNext() ) {
String key = it.next();
System.out.println( key );
int s = map.get( key );
sum += s;
}
System.out.println( "평균 : "+ sum / keySet.size() );
}
Share