Java - 제네릭스, Wildcard, 열거형, Thread

|

package Week02.day0718;

import java.sql.Date;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;

public class 실습8일차수정 {

 public static void main(String[] args) {
	 
		/* 1. 개가 예방접종을 맞음. - .
		 * 2. 예방접종기록을 저장.(기록을 넣기 위해 클래스(arraylist에 넣음)를 만들어야함. -접종명, 접종날짜를 저장)
		 * - 체크로직1 : (단, 동일한 날짜에 같은 예방접종을 맞으면 안됨)
		 * - 체크로직2 : (예방접종간격이 존재 - 어긋나면 오류멘트 출력.)
		 * 3. 예방접종 이력 출력.
		 * --- 추가 실습-----
		 * addHandler - hashset
		 * getTotalHandlePeriod - 총 훈련기간을 day로 리턴
		 * addFamliy - 가족추가, hashmap에 넣음. 클래스로 만들어서 넣어도 됨.
		 */
	 
	 Dog d1 = new Dog("멍뭉이", 3, "셰퍼드");
	 Dog d2 = new Dog("냥냥이", 2, "진도견");
	 Dog d3 = new Dog("왈왈이", 1, "보더콜리");

  try {
   d1.shotInoculate("독감", Date.valueOf("2019-07-01"));
   d2.shotInoculate("홍역", Date.valueOf("2019-07-01"));
   d3.shotInoculate("광견병", Date.valueOf("2019-07-01"));
   d3.shotInoculate("광견병", Date.valueOf("2019-07-01"));
  } catch (Exception e) {
   e.printStackTrace();
  }

  d1.printInoculateHistory();
  d2.printInoculateHistory();
  d3.printInoculateHistory();

  d1.addHandler("홍길동", "2019-01-05", "2019-02-01");
  d1.addHandler("홍길동", "2019-01-05", "2019-02-01");
  d1.addHandler("김길동", "2019-05-09", "2019-05-30");
  try {
   System.out.println("Period:" + d1.getTotalHandlerPeriod());
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

class Dog {
 private String name; // 개이름
 private int age; // 개나이
 private String kind; //품종
 private ArrayList inoculate = new ArrayList(); // 예방접종
 private HashSet handler = new HashSet();
 private HashMap family = new HashMap();

 Dog(String name, int age, String kind) {
  this.name = name;
  this.age = age;
  this.kind = kind;
 }

 public void shotInoculate(String name, Date date) throws Exception {
//		예방접종을 하다
//   - inoculate 속성에 이름과 날자에 해당하는 예방접종 정보 저장
//   - 동일한 날자에 같은 예방접종을 하면 안된다 
//   - 품종별 예방접종 가능 기간이 아니면 오류 발생
//      “예방접종 가능 기간이 아닙니다”
	
//	** 예방접종간격:
//		  - 셰퍼드: 7일 이상
//		  - 진도견: 10일 이상
//		  - 보더콜리: 15일 이상
  Inoculate in = new Inoculate(name, date);

  // 같은 정보가 있는지 Check  - contains 활용.
  if (inoculate.contains(in)) {
   throw new Exception("중복된 예방접종입니다");
  }

  // 품종별 예방접종 가능 기간이 아닌지 Check
  Collections.sort(inoculate); // 정렬

  Inoculate max = null;
  if (inoculate.size() > 0) { //isEmpty 로 해도됨.
   max = (Inoculate) inoculate.get(inoculate.size() - 1);

   long day = 0;
   if ("셰퍼드".equals(this.kind)) {
    day = diffOfDate(max.getDate().toString(), date.toString());
    if (day < 7)
     throw new Exception("예방접종 가능기간이 아닙니다");
   } else if ("진도견".equals(this.kind)) {
    day = diffOfDate(max.getDate().toString(), date.toString());
    if (day < 10)
     throw new Exception("예방접종 가능기간이 아닙니다");
   } else if ("보더콜리".equals(this.kind)) {
    day = diffOfDate(max.getDate().toString(), date.toString());
    if (day < 15)
     throw new Exception("예방접종 가능기간이 아닙니다");
   }
  }

  inoculate.add(in);
 }

 public void printInoculateHistory() {
//		예방접종 이력을 날자별 정렬하여 출력한다,
//   형식: ‘{0} - {1}’, {0}: 날자, {1}:예방접종명
//   날자는 xxxx.xx.xx Format으로 출력한다
	 
		Iterator it = inoculate.iterator();
		while(it.hasNext()) {
			String msg = "{0} - {1}";
			Object[] arguments = {name, ((Inoculate)it.next()).getName()};
			String result = MessageFormat.format(msg, arguments);
			System.out.println(result);
		}
 }

 public void addHandler(String name, String strDt, String endDt) { //set은 중복여부 체크할필요없음.
  Handler h = new Handler(name, strDt, endDt); //HashSet 사용. equals와 hash코드를 적절히 재정의해줘야함.
  handler.add(h); //equals를 반드시 재정의해줘야 중복저장안됨.
 }

 public int getTotalHandlerPeriod() throws Exception {  //Handler의 훈련기간 리턴.
  Iterator it = handler.iterator();

  int sum = 0; //콜렉션에 변동사항이 있으면 안됨. 상식임.

  while (it.hasNext()) {
   Handler h = (Handler) it.next(); //여러 객체 불러올땐 ,담아놓고 호출해야함.

   String strDt = h.getStrDt();
   String endDt = h.getEndDt();

   long lo = diffOfDate(strDt, endDt);

   sum += lo;
  }

  return sum;
 }

 public long diffOfDate(String begin, String end) throws Exception {
  System.out.println(begin + "~" + end);
  SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

  java.util.Date beginDate = formatter.parse(begin);
  java.util.Date endDate = formatter.parse(end);

  long diff = endDate.getTime() - beginDate.getTime();
  long diffDays = diff / (24 * 60 * 60 * 1000);

  return diffDays;
 }
}

class Handler {
 private String name;
 private String strDt;
 private String endDt;

 Handler(String name, String strDt, String endDt) {
  this.name = name;
  this.strDt = strDt;
  this.endDt = endDt;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getStrDt() {
  return strDt;
 }

 public void setStrDt(String strDt) {
  this.strDt = strDt;
 }

 public String getEndDt() {
  return endDt;
 }

 public void setEndDt(String endDt) {
  this.endDt = endDt;
 }

 public boolean equals(Object obj) {
  String thisTmp = name + strDt + endDt;
  String tmp = ((Handler) obj).getName() + ((Handler) obj).getStrDt() + ((Handler) obj).getEndDt();

  System.out.println("equals 호출");
  if (obj != null && obj instanceof Handler) { // obj가 Handler의 Instance이냐?
   boolean b = thisTmp.equals(tmp);
   System.out.println("비교:" + b);
   return b; // 같이 같은지 비교
  } else {
   return false;
  }
 }

 public int hashCode() { // HashCode 사용 - 중복 값을 빠르게 검색하고 Add시 어디에 집어 넣을지 결정합니다
  return Objects.hash(name, strDt, endDt);
 }

 public String toString() {
  // Card인스턴스의 kind와 number를 문자열로 반환한다.
  return "name : " + name + ", startDt : " + strDt + ", endDt : " + endDt;
 }

}

class Inoculate implements Comparable {
 String name;
 Date date;

 Inoculate(String name, Date date) {
  this.name = name;
  this.date = date;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public Date getDate() {
  return date;
 }

 public void setDate(Date date) {
  this.date = date;
 }

 public boolean equals(Object obj) {
  if (obj != null && obj instanceof Inoculate) { // obj가 Inoculate의 Instance
   return name.equals(((Inoculate) obj).name); // 같이 같은지 비교
  } else {
   return false;
  }
 }

 @Override
 public int compareTo(Object arg) { // compareTo 재정의.
  Inoculate param = (Inoculate) arg;

  return date.toString().compareTo(param.getDate().toString());
 }
}

--------------------------------------------------------------------------

package Week02.day0718;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

class Student implements Comparable{
	String name;
	int score;

	public String getName() {
		return name;
	}

	public int getScore() {
		return score;
	}

	public Student(String name, int score) {
		this.name = name;
		this.score = score;
	}
	
	public int compareTo(Object s) {
		if(this.score < ((Student)s).getScore()) {
			return -1;
		} else if (this.score > ((Student)s).getScore()) {
			return 1;
		}
		return 0;
	}
	
}

public class ArrayListEx4 {

	public static void main(String[] args) {
		
		List list = new ArrayList();
		
		list.add(new Student("a", 5));
		list.add(new Student("b", 10));
		list.add(new Student("c", 1));
		list.add(new Student("d", 52));
		list.add(new Student("e", 23));
		
		Collections.sort(list);
		
		Iterator it = list.iterator();
		
		while(it.hasNext()) {
			System.out.println(((Student)it.next()).getScore()); // 1 5 10 23 52 출력
		}

	}

}
--------------------------------------------------------------------------

package Week02.day0718;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

class Student1{
	int rollno;
	String name, address;
	
	public Student1(int rollno, String name, String address) {
		this.rollno = rollno;
		this.name = name;
		this.address = address;
	}
	
	public String toString() {
		return this.rollno + " " + this.name + " " + this.address;
	}
}

class Sortbyroll implements Comparator<Student1>{
	public int compare(Student1 a, Student1 b) {
		return a.rollno - b.rollno;
	}
}

public class ComparatorEx2 {

	public static void main(String[] args) {
		ArrayList<Student1> ar = new ArrayList<Student1>();
		ar.add(new Student1(111, "bbbb", "london"));
		ar.add(new Student1(131, "aaaa", "nyc"));
		ar.add(new Student1(121, "cccc", "jaipur"));
		
		System.out.println("Unsorted");
		for(int i=0; i<ar.size(); i++)
			System.out.println(ar.get(i));
		
		Collections.sort(ar, new Sortbyroll());
		for(int i=0; i<ar.size(); i++)
			System.out.println(ar.get(i));
	}
}

//출력값
/*Unsorted
111 bbbb london
131 aaaa nyc
121 cccc jaipur
111 bbbb london
121 cccc jaipur
131 aaaa nyc
 */ 

--------------------------------------------------------------------------

package Week02.day0718;

import java.util.ArrayList;

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

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 Toy{
	public String toString() {return "Toy";}
}

public class FruitBoxEx1 {
	
	//제네릭스.

	public static void main(String[] args) {
		Box<Fruit> fruitBox = new Box<Fruit>();
		Box<Apple> appleBox = new Box<Apple>();
		Box<Toy> toyBox = new Box<Toy>();
		Box<Toy> toyBox2 = new Box<>(); //생성자에 타입생략가능 jdk1.7
		//Box<Grape> grapeBox = new Box<Apple>(); // 에러. 타입 불일치. 생성시에는 타입이 일치해야 함.
		
		fruitBox.add(new Fruit());
		fruitBox.add(new Apple()); // OK. void add(Fruit item), Apple는 Fruit의 자식
		
		appleBox.add(new Apple());
		appleBox.add(new Apple());
		//appleBox.add(new Toy()); //에러. Box<Apple>에는 Apple만 담을수 있음.
		
		toyBox.add(new Toy());
		//toyBox.add(new Apple()); //에러 . Box<Toy>에는 Apple만 담을수 있음.
		
		System.out.println(fruitBox); // [Fruit, Apple]
		System.out.println(appleBox); // [Apple, Apple]
		System.out.println(toyBox); // [Toy]
	} // main의 끝

}

--------------------------------------------------------------------------
package Week02.day0718;

import java.util.ArrayList;

class Fruit1 implements Eatable{
	public String toString() {return "Fruit";}
}

class Apple1 extends Fruit1{public String toString() {return "Apple";}}
class Grape1 extends Fruit1{public String toString() {return "Grape";}}
class Toy1{public String toString() {return "Toy" ; }}

interface Eatable{}

public class FruitBoxEx2 {

	public static void main(String[] args) {
		
		FruitBox<Fruit1> fruitBox = new FruitBox<Fruit1>(); //Eatable의 자식
		FruitBox<Apple1> appleBox = new FruitBox<Apple1>(); //Fruit의 자식
		FruitBox<Grape1> grapeBox = new FruitBox<Grape1>(); //Fruit의 자식
//		FruitBox<Grape> appleBox = new FruitBox<Apple>(); // 에러, 타입 불일치
//		FruitBox<Toy> toyBox = new FruitBox<Toy>(); // 에러.
		
		fruitBox.add(new Fruit1());
		fruitBox.add(new Apple1());
		fruitBox.add(new Grape1());
		appleBox.add(new Apple1());
//		appleBox.add(new Grape()); //에러. Grape는 Apple의 자손이 아님
		grapeBox.add(new Grape1());
		
		System.out.println("fruitBox-" + fruitBox); // fruitBox-[Fruit, Apple, Grape]
		System.out.println("appleBox-" + appleBox); // appleBox-[Apple]
		System.out.println("grapeBox-" + grapeBox); // grapeBox-[Grape]
	}
}

class FruitBox<T extends Fruit1 & Eatable> extends Box1<T>{}

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

--------------------------------------------------------------------------

package Week02.day0718;

import java.util.ArrayList;

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

class Juicer{ // Jucier는 Generic class 가 아니고 static 메소드에서 Generic 클래스 사용시
	static Juice makeJuice(FruitBox1<? extends Fruit> box) {
		String tmp = "";
		
		for(Fruit f : box.getList())
			tmp+=f+" ";
		return new Juice(tmp);
	}
}

public class FruitBoxEx3 {

	public static void main(String[] args) {
		
		//와일드카드
        //<? extends T> : 와일드카드의 상한제한, T와 그 자손들만 가능
        //<? super T> : 와일드 카드의 하한제한, T와 그 조상들만 가능
        //<?> : 제한없음, 모든 타입이 가능
		FruitBox1<Fruit> fruitBox = new FruitBox1<Fruit>();
		FruitBox1<Apple> appleBox = new FruitBox1<Apple>();
		
		fruitBox.add(new Apple());
		fruitBox.add(new Grape());
		appleBox.add(new Apple());
		appleBox.add(new Apple());
		
		System.out.println(Juicer.makeJuice(fruitBox)); // Apple Grape Juice
		System.out.println(Juicer.makeJuice(appleBox)); // Apple Apple Juice
	} // main
}

class FruitBox1<T extends Fruit> extends Box2<T>{}

class Box2<T>{
	//class FruitBox<T extends Fruit>
	ArrayList<T> list = new ArrayList<T>();
	void add(T item) {list.add(item);}
	T get(int i) {return list.get(i);}
	ArrayList<T> getList(){return list;}
	int size() {return list.size();}
	public String toString() {return list.toString();}
}


--------------------------------------------------------------------------

package Week02.day0718;

enum Direction {EAST, SOUTH, WEST, NORTH}

public class EnumEx1 {

	public static void main(String[] args) {
		
		//열거형
		//열거형 값을 할당하는 3가지 방법
		Direction d1 = Direction.EAST;
		Direction d2 = Direction.valueOf("WEST");
		Direction d3 = Enum.valueOf(Direction.class, "EAST");
		
		System.out.println("d1=" + d1); // d1=EAST
		System.out.println("d2=" + d2); // d2=WEST
		System.out.println("d3=" + d3); // d3=EAST
		
		System.out.println("d1==d2 ? " + (d1==d2)); //  false
		System.out.println("d1==d3 ? " + (d1==d3)); // true
		System.out.println("d1.equals(d3) ? " + d1.equals(d3)); // true
//		System.out.println("d2> d3 ? " + (d1 > d3)); // 에러 , 비교구분 불가능
		System.out.println("d1.compareTo(d3) ? " + (d1.compareTo(d3))); // 0
		System.out.println("d1.compareTo(d2) ? " + (d1.compareTo(d2))); // -2
		
		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) // for(Direction d : Direction.values())
			System.out.printf("%s=%d%n", d.name(), d.ordinal());
		/*EAST=0
		SOUTH=1
		WEST=2
		NORTH=3
		 */

	}

}


--------------------------------------------------------------------------
/* Thread */
1. 하나의 프로그램을 프로세스라고 할때, Thread는 하나의 프로그램 내에서의 실행 단위
2. 호출 스택
- JVM에서 main()메소드를 호출
- main()에서 새로운 Thread를 시작
- JVM은 두 Thread가 종료될 때까지 새로운 Thread와 원래의 Main Thread 사이를 왔다 갔다 한다.



package Week02.day0718;

class ThreadSample extends Thread {// 3. Thread 클래스 상속 - 하위 클래스가 Thread 클래스의 run 메소드 재정의
	int number;
	ThreadSample(int n){
		super(); number = n;
	}
	ThreadSample(String s, int n){
		super(s); number = n;
	}
	
	public void run() {
		int n = 3;
		while(n<number) {
			if(isPrimeNumber(n))
				System.out.println(getName() + ": " + n + " is prime number");
			n++;
			try {
				sleep(100); 
			}catch (InterruptedException e) {
			}
		}
	}
	
	public boolean isPrimeNumber(int n) {
		int i;
		for(i = 2; i<=(n/2); i++) 
			if((n%i)==0)
				return (false);
			return (true);
	}
}

public class ThreadTest {

	public static void main(String[] args) {
		
		ThreadSample primeThread = new ThreadSample(30);
		System.out.println("PrimeThread:"+primeThread);
		primeThread.setName("PrimeThread");
		System.out.println("PrimeThread:"+primeThread);
		primeThread.start(); // thread시작시 알아서 run 메소드 호출

	}

}

//출력값
//PrimeThread:Thread[Thread-0,5,main]
//PrimeThread:Thread[PrimeThread,5,main]
//PrimeThread: 3 is prime number
//PrimeThread: 5 is prime number
//PrimeThread: 7 is prime number
//PrimeThread: 11 is prime number
//PrimeThread: 13 is prime number
//PrimeThread: 17 is prime number
//PrimeThread: 19 is prime number
//PrimeThread: 23 is prime number
//PrimeThread: 29 is prime number
//..............

--------------------------------------------------------------------------

package Week02.day0718;

class PrimeThread implements Runnable{
	int number;
	String name;
	PrimeThread(int n){
		name = null ; number = n;
	}
	PrimeThread(String s, int n){
		name = s; number = n;
	}
	
	public void run() {
		int n = 3;
		while(n<number) {
			if(isPrimeNumber(n))
				System.out.println(name + ": " + n + " is prime number");
			n++;
			try {
				Thread.sleep(100); // 0.1초 thread일시정지후 실행대기 상태로
			}catch (InterruptedException e) {
			}
		}
	}
	
	public boolean isPrimeNumber(int n) {
		int i;
		for(i = 2; i<=(n/2); i++) 
			if((n%i)==0)
				return (false);
			return (true);
	}
}

/* Runnable Interface를 구현 */
1. Thread의 하위클래스를 만들지 않고서도 Thread로 수행될 클래스를 만들 수있는방법을 제공

public class RunnableTest {

	public static void main(String[] args) {
		//Runnable interface를 implements한 Class를 인자로 넣어서
		//Thread생성
		
		Thread primeThread = new Thread(new PrimeThread(30));
		System.out.println("PrimeThread : " + primeThread);
		primeThread.setName("PrimeThread");
		System.out.println("PrimeThread : " + primeThread);
		primeThread.start();

	}

}

//출력값
//PrimeThread : Thread[Thread-0,5,main]
//PrimeThread : Thread[PrimeThread,5,main]
//null: 3 is prime number
//null: 5 is prime number
//null: 7 is prime number
//null: 11 is prime number
//null: 13 is prime number
//null: 17 is prime number
//null: 19 is prime number
//null: 23 is prime number
//null: 29 is prime number
//....................

/* Thread 환경에서 사용하는 함수 설명 */
1. public final int getPriority : 스레드의 우선순위를 얻는다
2. public final void setPriority(int newPriority) : 스레드의 우선순위를 주어진 값으로 설정
3. public final void suspend() : 스레드를 잠시 쉬게한다
4. public final void resume() : 다시 시작
5. void destory() : 스레드를 파괴

/* Thread 스케줄러 */
1. 스케줄러는 어떤 Thread가 실행되어야 하는지 얼마나 오랫동안 실행되어야 하는지 결정
2. 스케줄러는 사용자가 마음대로 제어할 수 없다.
3. sleep 메소드 : thread를 대기상태가 되도록 만듬
4. Thread 우선순위 결정 : 1 ~ 10 (숫자가 높을수록 우선순위 높다)
And