Skip to content

Latest commit

 

History

History
555 lines (457 loc) · 13.1 KB

220312.md

File metadata and controls

555 lines (457 loc) · 13.1 KB

와일드 카드 <?>

하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능

ArrayList<? extends Product> list = new ArrayList<Tv>();
ArrayList<? extends Product> list = new ArrayList<Audio>();
ArrayList<Product> list = new ArrayList<Tv>();
  • <? extends T >
    • 와일드 카드의 상한 제한. T와 그 자손들만 가능
  • <? super T>
    • 와일드 카드의 하한 제한. T와 그 조상들만 가능
  • <?>
    • 제한 없음. 모든 타입이 가능. ? extends Object와 동일

메소드의 매개변수에 와일드 카드를 사용

package ch02;

import java.util.*;

class Fruit { public String toString() { return "Fruit"; }}
class Apple extends Fruit { public String toString() { return "Apple"; }}
class Grape extends Fruit { public String toString() { return "Grape"; }}

class Juice {
	String name;
	
	Juice(String name) { this.name = name + "Juice";}
	public String toString() { return name; }
}

class Juicer {
	static Juice makeJuice(FruitBox<? extends Fruit> box) {
		String tmp = "";
		
		for(Fruit f : box.getList()) 
			tmp += f + " ";
		return new Juice(tmp);
	}
}

public class EX3 {

	public static void main(String[] args) {
		FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
		FruitBox<Apple> appleBox = new FruitBox<Apple>();
		
		fruitBox.add(new Apple());
		fruitBox.add(new Grape());
		appleBox.add(new Apple());
		appleBox.add(new Apple());
		
		System.out.println(Juicer.makeJuice(fruitBox));
		System.out.println(Juicer.makeJuice(appleBox));
	}
	
}

class FruitBox<T extends Fruit> extends Box<T> {}

class Box<T> {
	ArrayList<T> list = new ArrayList<T>();
	void add(T item) { list.add(item); }
	ArrayList<T> getList() { return list; }
	int size() { return list.size(); }
	public String toString() { return list.toString(); }
}

Apple Grape Juice
Apple Apple Juice

지네릭 메소드

지네릭 타입이 선언된 메소드(타입 변수는 메소드 내에서만 유효)

static <T> void sort(List<T> list, Comparator<? super T> c)

클래스의 타입 매개변수와 메소드의 타입 매개변수 는 별개

class FruitBox<T> {
    ...
    static <T> void sort(List<T> list, Comparator<? super T> c>){
        ... // 타입 문자가 일치하지만 다른 타입 변수가 사용된다.
    }
}

메소드를 호출할 때마다 타입을 대입해야 한다.

메소드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름 생략 불가

System.out.println(<Fruit>makeJuice(fruitBox)); // 에러
System.out.println(this.<Fruit>makeJuice(fruitBox));
System.out.println(Juicer.<Fruit>makeJuice(fruitBox));

지네릭 타입의 형변환

지네릭 타입과 원시 타입 간의 형변환은 바람직 하지 않다.(경고 발생)

Box<Object> objBox = null;
Box box = (Box)objBox;      // 지네릭 타입 -> 원시 타입, 실행은 되나 경고 발생
objBox = (Box<Object>)box;  // 원시타입 -> 지네릭 타입, 실행은 되나 경고 발생

objBox = (Box<Object>)strBox; // 에러
strBox = (Box<String>)objBox; // 에러

와일드 카드가 사용된 지네릭 타입으로는 형변환 가능

Box<Object> objBox = (Box<Object>)new Box<String>(); // 에러
Box<? extends Object> wBox = (Box<? extends Object>)new Box<String>();
Box<? extends Object> wBox = new Box<String>(); // 위 문장과 동일하다.

지네릭 타입의 제거

컴파일러는 지네릭 타입을 제거하고, 필요한 곳에 형변환을 넣는다. (하위 호환성을 위해)

  • 지네릭 타입의 경계(bound)를 제거
class Box<T extends Fruit> {
    void add(T t) {
        ...
    }
}
class Box {
    void add(Fruit t) {
        ...
    }
}
  • 지네릭 타입 제거 후에 타입이 불일치하면, 형변환을 추가
T get(int i) {
    return list.get(i);
}
Fruit get(int i) {
    return (Fruit)list.get(i);
}
  • 와일드 카드가 포함된 경우, 적절한 타입으로 형변환 추가
static Juice makeJuice(FruitBox<? extends Fruit> box) {
    String tmp = "";
    
    for(Fruit f : box.getList()) 
        tmp += f + " ";
    return new Juice(tmp);
}
static Juice makeJuice(FruitBox box) {
    String tmp = "";
    Iterator it = box.getList().iterator();
    whiel(it.hasNext()) {
        tmp += (Fruit)it.next() + " ";
    }
    return new Juice(tmp);
}

열거형(enum)

관련된 상수들을 같이 묶어 놓은 것. Java는 타입에 안전한 열거형을 제공
Java의 열거형은 타입을 모두 체크한다는 뜻이다.

class Card { //   0      1       2       3
    enum Kind {CLOVER, HEART, DIAMOND, SPADE} // 자동으로 0부터 대입된다.
    enum Value {TWO, THREE, FOUR}

    final Kind Kind; // 타입이 int가 아닌 Kind임에 유의
    final Value value;
}

열거형을 정의하는 법

enum 열거형이름 { 상수명1, 상수명2, ... }

열거형 타입의 변수를 선언하고 사용하는 법

enum Direction { EAST, SOUTH, WEST, NORTH }
class Unit {
    int x, y;
    Direction dir; // 열거형 인스턴스 변수를 선언

    void init() {
        dir = Direction.EAST // 유닛의 방향을 EAST로 초기화
    }
}

열거형 상수의 비교에 ==와 compareTo() 사용가능

if(dir==Direction.EAST){
    x++;
} else if (dir > Direction.WEST) { // 에러. 열거형 상수에 비교연산자 사용불가
    ...
} else if (dir.compareTo(Direction.WEST) > 0){ // compareTo()는 가능
    ...
}

열거형의 조상 - java.lang.Enum

모든 열거형은 Enum의 자손이며, 아래의 메소드를 상속받는다.

메소드 설명
Class getDeclaringClass() 열거형의 Class객체를 반환
String name() 열거형 상수의 이름을 문자열로 반환
int ordinal() 열거형 상수가 정의된 순서를 반환(0부터 시작)
T valueOf(Class enumType, String name) 지정된 열거형에서 name과 일치하는 열거형 상수를 반환

values(), valueOf()는 컴파일러가 자동으로 추가

static E[] values()
static E valueOf(String name)

Direction[] dArr = Direction.values();

for(Direction d : dArr) // for(Direction d : Direction.values())
    System.out.printf("%s=%d%n", d.name(), d.ordinal());

예제

package ch02;

import java.util.*;

enum Direction { EAST, SOUTH, WEST, NORTH }

public class EX3 {

	public static void main(String[] args) {
		Direction d1 = Direction.EAST;
		Direction d2 = Direction.valueOf("WEST");
		Direction d3 = Enum.valueOf(Direction.class, "EAST");
		
		System.out.println("d1="+d1);
		System.out.println("d2="+d2);
		System.out.println("d3="+d3);
		
		System.out.println("d1==d2 ? " + (d1==d2));
		System.out.println("d1==d3 ? " + (d1==d3));
		System.out.println("d1.equals(d3) ? "+d1.equals(d3));
		System.out.println("d1.compareTo(d3) ? "+(d1.compareTo(d3)));
		System.out.println("d1.compareTo(d2) ? "+(d1.compareTo(d2)));
		
		switch(d1) {
		case EAST: // Direction.EAST라고 쓸 수 없다.
			System.out.println("The direction is EAST."); break;
		case SOUTH:
			System.out.println("The direction is SOUTH."); break;
		case WEST:
			System.out.println("The direction is WEST."); break;
		case NORTH:
			System.out.println("The direction is NORTH."); break;
		default:
			System.out.println("Invalid direction."); break;
		}
		
		Direction[] dArr = Direction.values(); // 열거형의 모든 상수를 배열로 반환
		
		for(Direction d : dArr)
			System.out.printf("%s=%d%n", d.name(), d.ordinal());
		
	}
	
}

d1=EAST
d2=WEST
d3=EAST
d1==d2 ? false
d1==d3 ? true
d1.equals(d3) ? true
d1.compareTo(d3) ? 0
d1.compareTo(d2) ? -2
The direction is EAST.
EAST=0
SOUTH=1
WEST=2
NORTH=3

열거형에 멤버 추가하기

불연속적인 열거형 상수의 경우, 원하는 값을 괄호안에 넣는다. 괄호 안에 여러 개를 넣는 것도 가능하다.

enum Direction { EAST(1),  SOUTH(5), WEST(-1), NORTH(10) }

괄호를 사용하려면, 인스턴스 변수와 생성자를 새로 추가해 줘야 한다.

enum Direction {
    EAST(1), SOUTH(5), WEST(-1), NORTH(10); // 끝에 세미콜론 추가

    private final int value; // 정수를 저장할 필드(인스턴스 변수)를 추가
    Direction(int value) { this.value = value; } // 생성자 추가

    public int getValue() { return value; }
}

열거형의 생성자는 묵시적으로 private이므로, 외부에서 객체 생성 불가

Direction d = new Direction(1); // 에러

예시

package ch02;

import java.util.*;

enum Direction {
    EAST(1, ">"), SOUTH(2, "V"), WEST(3, "<"), NORTH(4, "^"); // 끝에 세미콜론 추가

    private static final Direction[] DIR_ARR = Direction.values();
    private final int value;
    private final String symbol;
    
    Direction(int value, String symbol) {
    	this.value = value;
    	this.symbol = symbol;
    }

    public int getValue() { return value; }
    public String getSymbol() {return symbol; }
    
    public static Direction of(int dir) {
    	if (dir < 1 || dir > 4)
    		throw new IllegalArgumentException("Invalid value : " + dir);
    	
    	return DIR_ARR[dir-1];
    }
    
    // 방향을 회전시키는 메소드. num의 값만큼 90도씩 시계방향으로 회전한다.
    public Direction rotate(int num) {
    	num = num % 4;
    	if(num < 0) num += 4; // num이 음수일 때는 시계반대 방향으로 회전
    	
    	return DIR_ARR[(value-1+num) % 4];
    }
    
    public String toString() {
    	return name()+getSymbol();
    }
}

public class EX3 {

	public static void main(String[] args) {
		for(Direction d : Direction.values())
			System.out.printf("%s=%d%n", d.name(), d.getValue());
	
		Direction d1 = Direction.EAST;
		Direction d2 = Direction.of(1);
		
		System.out.printf("d1=%s, %d%n", d1.name(), d1.getValue());
		System.out.printf("d2=%s, %d%n", d2.name(), d2.getValue());
		System.out.println(Direction.EAST.rotate(1));
		System.out.println(Direction.EAST.rotate(2));
		System.out.println(Direction.EAST.rotate(-1));
		System.out.println(Direction.EAST.rotate(-2));
		
	}
	
}

EAST=1
SOUTH=2
WEST=3
NORTH=4
d1=EAST, 1
d2=EAST, 1
SOUTHV
WEST<
NORTH^
WEST<

백준 10926번

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		String buffer = s.nextLine();
		System.out.println(buffer+"??!");
		
	}
	
}

백준 18108번

import java.util.*;

public class Main {

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int buffer = s.nextInt();
		System.out.println(buffer-543);
		
	}
	
}

백준 14681번

package ch02;

import java.util.*;

public class Main {

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int x = s.nextInt();
		int y = s.nextInt();
		int answer = (x > 0 ? (y > 0 ? 1 : 4) : (y > 0 ? 2 : 3));
		System.out.println(answer);
		
	}
	
}

백준 2525번

import java.util.*;

public class Main {

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int h = s.nextInt();
		int m = s.nextInt();
		int duration = s.nextInt();
		
		m += duration;
		if (m >= 60) {
			h += m / 60;
			m %= 60;
		}
		if (h >= 24) {
			h -= 24;
		}
		System.out.printf("%d %d", h, m);
	}
	
}

백준 2480번

package ch02;

import java.util.*;

public class Main {

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int dice1 = s.nextInt();
		int dice2 = s.nextInt();
		int dice3 = s.nextInt();
		int reward = 0;
		
		if (dice1 == dice2 && dice1 == dice3) {
			reward = 10000 + dice1*1000;
		} else if (dice1 != dice2 && dice1 != dice3 && dice2 != dice3) {
			if (dice1 > dice2) {
				if(dice1 > dice3) {
					reward = dice1*100;
				} else {
					reward = dice3*100;
				}
			} else {
				if (dice2 > dice3) {
					reward = dice2*100;
				} else {
					reward = dice3*100;
				}
			}
		} else {
			if(dice1 == dice2) {
				reward = 1000 + dice1*100;
			} else if (dice1 == dice3) {
				reward = 1000 + dice1*100;
			} else {
				reward = 1000 + dice2*100;
			}
		}
		
		System.out.println(reward);
	}

	
}

조금 보기 쉽게 손 본 버전

package ch02;

import java.util.*;

public class Main {

	public static void main(String[] args) {
		ArrayList<Integer> diceBox = new ArrayList<>(3);
		getDice(diceBox);	
		diceBox.sort(Comparator.naturalOrder());
		int reward = 0;
		int result = 0;
		Set<Integer> s = new HashSet<>(diceBox);
		
		if(s.size() == 1)
			result = 0;
		else if(s.size() == 2)
			result = 1;
		else
			result = 2;
		
		reward = getReward(diceBox, result);
		System.out.println(reward);
		
	}
	
	public static int getReward(ArrayList<Integer> diceBox, int winType) {
		int reward;
		switch(winType) {
			case 0:
				reward =  10000 + diceBox.get(0) * 1000;
				break;
			case 1:
				if(diceBox.get(0).equals(diceBox.get(1)))
					reward = 1000 + diceBox.get(0)*100;
				else
					reward = 1000 + diceBox.get(1)*100;
				break;
			case 2:
				reward = diceBox.get(2)*100;
				break;
			default:
				reward = 0;				
		}
		return reward;
	}
	
	public static void getDice(ArrayList diceBox) {
		Scanner s = new Scanner(System.in);
		for(int i = 0; i<3; i++) {
			diceBox.add(s.nextInt());
		}
		
	}

	
}