1. List<>
: 중복 허용, 순서 유지(인덱스 OK)
1) ArrayList<>
: 참조 유리 / 삽입, 삭제, 추가 어려움
2) LinkedList<>
: 삽입, 삭제, 추가 용이 / 참조 불리
2. Set<>
: 중복 불가, 순서 없음(인덱스 NO)
1) HashSet<>
: 검색 속도
2) TreeSet<>
: 정렬
3. Map<K, V>
1) HashMap<K, V>
: 검색 속도
2) TreeMap<K, V>
: 정렬
[실습코드]
1. [과제] 전화번호부 4.0 : CONTROLLER(PhonebookManager)만 수정하여 배열을 배열리스트로 자료구조 변경하기!
package phonebook04.list;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
// CONTROLLER 객체
// 어플리케이션의 동작, 데이터 처리, (Business logic 담당)
public class PhonebookManager implements Pb {
private ArrayList<PhonebookModel> pbList = new ArrayList<PhonebookModel>();
// 몇 개의 데이터가 저장되었는지
private int count = 0;
// singleton 적용
private PhonebookManager() { }
private static PhonebookManager instance = null;
public static PhonebookManager getInstance() {
if(instance == null) {
instance = new PhonebookManager();
}
return instance;
} // end getInstance()
// 전화번호부 생성 등록
@Override
public int insert(String name, String phoneNum, String memo) {
// 매개변수 검증 : 이름 필수
if(name == null || name.trim().length() == 0) {
throw new PhonebookException("insert() 이름입력오류 : ", Pb.ERR_EMPTY_STRING);
}
PhonebookModel model = new PhonebookModel((count + 1), name, phoneNum, memo, new Date());
pbList.add(model);
count++;
return 1;
}
@Override
public PhonebookModel[] selectAll() {
return pbList.toArray(new PhonebookModel[pbList.size()]);
}
// 특정 uid 의 데이터 검색 리턴
// 못찾으면 null 리턴
@Override
public PhonebookModel selectByUid(int uid) {
for(int index = 0; index < count; index++) {
if(index == uid) {
return pbList.get(uid);
}
}
return null; // 못찾으면 null 리턴
} // end selectByUid()
@Override
public int updateByUid(int uid, String name, String phoneNum, String memo) {
// 매개변수 검증
if(uid < 1) {
throw new PhonebookException("update() uid 오류 : " + uid, Pb.ERR_UID);
}
// 이름 필수
if(name == null || name.trim().length() == 0) {
throw new PhonebookException("update() 이름입력 오류 : ", Pb.ERR_EMPTY_STRING);
}
// 특정 uid 값을 가진 데이터의 배열 인덱스 찾기
int index = findIndexByUid(uid);
if(index < 0) {
throw new PhonebookException("update() 없는 uid", Pb.ERR_UID);
}
System.out.println(index);
pbList.set((index - 1), new PhonebookModel((index),name, phoneNum, memo, new Date()));
return 1;
}
@Override
public int deleteByUid(int uid) {
// 매개변수 검증
if(uid < 1) {
throw new PhonebookException("deleteByUid() uid 오류 : " + uid, Pb.ERR_UID);
}
int index = findIndexByUid(uid);
if(index < 0) {
throw new PhonebookException("deleteByUid() 없는 uid", Pb.ERR_UID);
}
pbList.remove(uid-1);
return 1;
}
// 현재 데이터 중 가능 큰 uid값을 찾아서 리턴
private int getMaxUid() {
int maxUid = 0;
maxUid = count;
return maxUid;
}
// 특정 uid 값을 가진 데이터의 배열 인덱스 찾기
// 못찾으면 -1 리턴
private int findIndexByUid(int uid) {
for(int index = 0; index < count; index++) {
if(index == uid) {
System.out.println("findIndexByUid : "+uid);
return uid;
}
}
return -1;
}
} // end PhonebookManager
// 예외 클래스 정의
// 예외발생하면 '에러 코드' + '에러 메시지'를 부여하여 관리하는게 좋다.
class PhonebookException extends RuntimeException{
private int errCode = Pb.ERR_GENERIC;
// 생성자 만들기
public PhonebookException() {
super("Phonebook 예외 발생");
}
public PhonebookException(String msg) {
super(msg);
}
public PhonebookException(String msg, int errCode) {
super(msg);
this.errCode = errCode;
}
// Throwable 의 getMessage 를 오버라이딩 가능
@Override
public String getMessage() {
String msg = "ERR-" + errCode + "]" +Pb.ERR_STR[errCode]
+ " " + super.getMessage();
return msg;
}
} // PhonebookException
** 쌤이 선택한 학생의 코드..!!
package phonebook04.list;
import java.util.ArrayList;
import java.util.Arrays;
// CONTROLLER 객체
// 어플리케이션의 동작, 데이터 처리(CRUD), (Business logic 담당)
public class PhonebookManager implements Pb {
private ArrayList<PhonebookModel> pbList = new ArrayList<PhonebookModel>();
// singleton적용
private PhonebookManager() {}
private static PhonebookManager instance = null;
public static PhonebookManager getInstance() {
if (instance == null) {
instance = new PhonebookManager();
}
return instance;
} // end getInstance()
// 전화번호부 생성 등록
@Override
public int insert(String name, String phoneNum, String memo) {
// 매개변수 검증 : 이름 필수
if(name == null || name.trim().length() == 0) {
throw new PhonebookException("insert() 이름입력오류: ", Pb.ERR_EMPTY_STRING);
}
PhonebookModel p = new PhonebookModel(name, phoneNum, memo);
p.setUid(getMaxUid() + 1);
pbList.add(p);
return 1;
}
@Override
public PhonebookModel[] selectAll() {
PhonebookModel[] pb = new PhonebookModel[pbList.size()];
for (int i = 0; i < pbList.size(); i++) {
pb[i] = pbList.get(i);
}
return pb;
// 아래와 같이 한줄로 가능! toArray() : List<> --> 배열로 변환
// return pbList.toArray(new PhonebookModel[pbList.size()]);
}
// 특정 uid 의 데이터 검색 리턴
// 못찾으면 null 리턴
@Override
public PhonebookModel selectByUid(int uid) {
for (int i = 0; i < pbList.size(); i++) {
if(pbList.get(i).getUid() == uid) {
return pbList.get(i);
}
}
return null; // 못찾으면 null 리턴
}// end selectByUid()
@Override
public int updateByUid(int uid, String name, String phoneNum, String memo) {
// 매개변수 검증
if(uid < 1)
throw new PhonebookException("update() uid 오류: " + uid, Pb.ERR_UID);
if(name == null || name.trim().length() == 0) // 이름 필수
throw new PhonebookException("update() 이름입력 오류: ", Pb.ERR_EMPTY_STRING);
// 특정 uid 값을 가진 데이터의 배열 인덱스 찾기
int index = findIndexByUid(uid);
if(index < 0)
throw new PhonebookException("update() 없는 uid: " + uid, Pb.ERR_UID);
pbList.get(index).setName(name);
pbList.get(index).setPhoneNum(phoneNum);
pbList.get(index).setMemo(memo);
return 1;
}
@Override
public int deleteByUid(int uid) {
// 매개변수 검증
if(uid < 1)
throw new PhonebookException("deleteByUid() uid 오류: " + uid, Pb.ERR_UID);
int index = findIndexByUid(uid);
if(index < 0)
throw new PhonebookException("deleteByUid() 없는 uid: " + uid, Pb.ERR_UID);
pbList.remove(index);
return 1;
}
// 현재 데이터중 가장 큰 uid 값을 찾아서 리턴
private int getMaxUid() {
int maxUid = 0;
if(pbList.size() > 0) {
int uid = pbList.get((pbList.size() - 1)).getUid();
if(maxUid < uid) maxUid = uid;
}
// for (PhonebookModel p : pbList) {
// if(maxUid < p.getUid()) {
// maxUid = p.getUid();
// }
// }
return maxUid;
}
// 특정 uid 값을 가진 데이터의 배열 인덱스 찾기
// 못찾으면 -1 리턴
private int findIndexByUid(int uid) {
for (int i = 0; i < pbList.size(); i++) {
if(pbList.get(i).getUid() == uid) return i;
}
return -1;
}
} // end PhonebookManager
// 예의 클래스 정의
// 예외발생하면 '에러코드' + '에러메세지'를 부여하여 관리하는게 좋다.
class PhonebookException extends RuntimeException {
private int errCode = Pb.ERR_GENERIC;
public PhonebookException() {
super("Phonebook 예외 발생");
}
public PhonebookException(String msg) {
super(msg);
}
public PhonebookException(String msg, int errCode) {
super(msg);
this.errCode = errCode;
}
// Throwable 의 getMessage 를 오버라이딩 가능
@Override
public String getMessage() {
String msg = "ERR-" + errCode + "]" + Pb.ERR_STR[errCode] +
" " + super.getMessage();
return msg;
}
} // end PhonebookException
2. Lec22_Collection
1) com.lec.java.collection14 패키지, Collection14Main 클래스
package com.lec.java.collection14;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
/* java.util.Collections 클래스
Collections 클래스는 여러 유용한 알고리즘을 구현한 메소드들을 제공
대부분 클래스메소드 (static) 형태로 제공됨
정렬(sort)
섞기(shuffle)
탐색(search)
*/
public class Collection14Main {
public static void main(String[] args) throws ParseException {
System.out.println("Collections 메소드");
List<String> list1 = new LinkedList<String>();
list1.add("장수영");
list1.add("김진영");
list1.add("고유성");
System.out.println(list1); // List 의 toSting 결과 형태 출력
System.out.println("sort()");
// sort()
// 기본적으로 속도가 비교적 빠르고 안전성이 보장되는 Merge Sort 사용
Collections.sort(list1);
System.out.println(list1); // 정렬 후 결과!
System.out.println();
List<Date> list2 = new LinkedList<Date>();
// 문자열 "2018-08-16" --> Date객체
list2.add(new SimpleDateFormat("yyyy-MM-dd").parse("2018-08-16"));
list2.add(new SimpleDateFormat("yyyy-MM-dd").parse("2017-05-21"));
list2.add(new SimpleDateFormat("yyyy-MM-dd").parse("2022-03-03"));
System.out.println(list2);
Collections.sort(list2);
System.out.println(list2); // 날짜 오름차순으로 정렬
// String 타입이면 알파벳 순으로 정렬된다.
// Date 타입이면 날짜순으로 정렬된다
// ★ String 과 Date 는 기본적으로 Comparable<T> 인터페이스가 구현되었기 때문.
// ※ String 온라인 도움말 확인해보자
System.out.println();
List<Student> list3 = new LinkedList<Student>();
list3.add(new Student("Susie", 50));
list3.add(new Student("James", 80));
list3.add(new Student("Kevin", 30));
System.out.println(list3);
System.out.println();
System.out.println("Comparable 구현, sort() 적용");
// Student 에 Comparable<> 구현 안되어 있으면 에러..!!
// 만약 Comparable<> 구현 전에 컴파일 하면 아래와 같은 에러 발생
// The method sort(List<T>) in the type Collections
// is not applicable for the arguments(List<Student>)
// Comparable<> 구현하면 사용 가능해지면서 대소 비교가 가능해짐...!!
Collections.sort(list3);
// Comparable<> 구현 후 실행
System.out.println(list3); // 정렬 후 출력
// 역순 정렬
System.out.println();
System.out.println("reverseOrder() 적용");
Collections.sort(list3, Collections.reverseOrder());
System.out.println(list3);
System.out.println();
System.out.println("reverse() 적용");
Collections.reverse(list3);
System.out.println(list3);
// Comparator<> 적용
// Collections.sort 메소드는 두 번째 인자로 Comparator 인터페이스를 받을 수 있도록 해놓았습니다.
// Comparator 인터페이스의 compare 메소드를 오버라이드 하면 됩니다.
System.out.println("Comparator<> 적용");
Collections.sort(list3, new Asc()); // '이름' 오름차순
System.out.println(list3);
// '이름' 내림차순
Collections.sort(list3, new Desc()); // '이름' 오름차순
System.out.println(list3);
// Collections 에서 많이 쓰이는 인터페이스임
// Comparable 은 클래스 자체에 구현하는 인터페이스 compareTo(자기사진 vs 매개변수)
// Comparator 는 두개의 객체 비교하는 기능제공 인터페이스 compare(매개변수1 vs 매개변수2)
// 구현된 객체가 매개변수 등에 넘겨지는 형태로 많이 쓰임
// Shuffling 하기 (섞기)
System.out.println();
System.out.println("shuffle()");
Collections.shuffle(list1);
System.out.println(list1);
Collections.shuffle(list1);
System.out.println(list1);
// 배열에서 랜덤으로 3명만 뽑기
String[] arr = {"안녕", "하세요", "치킨", "먹고 싶어요", "집에 가고 싶다",
"잠도 자고 싶다", "잠이 부족해", "탈주하고 싶다", "도망가고 싶다"};
List<String> arrList = Arrays.asList(arr); // 배열 --> List<>
// ( List<> 의 toArray() 의 반대)
Collections.shuffle(arrList);
arrList = arrList.subList(0, 3); // index 0부터 3전까지의 List<> 생성
System.out.println(arrList);
// min(), max()
// Comparable 메소드 영향 받음
System.out.println();
System.out.println("min(), max()");
System.out.println(Collections.min(list1));
System.out.println(Collections.max(list1));
System.out.println(Collections.min(list3));
System.out.println(Collections.max(list3));
// copy()
System.out.println();
List<Student> list4 = new LinkedList<Student>();
list4.add(new Student("aaa", 10));
list4.add(new Student("bbb", 20));
list4.add(new Student("ccc", 30));
System.out.println("copy() 전");
System.out.println(list4);
System.out.println("copy() 후");
Collections.copy(list4, list3);
System.out.println(list4);
System.out.println("\n프로그램 종료");
} // end main
} // end class
// 처음은 Comparable 구현 없이 해보고,
// 에러 확인한 다음에는 Student 클래스에서 Comparable 구현한 뒤
// 메인 메소드에서 Collections.sort(list3) 출력해보기
class Student implements Comparable<Student>{
String name;
double point;
public Student(String name, double point) {
super();
this.name = name;
this.point = point;
}
@Override
public String toString() {
return this.name + ":" + this.point + "점";
}
// compareTo() 메소드는 매개변수 객체를 '자신'과 비교하여
// 작으면 음수, 같으면 0, 크면 양수를 리턴한다.
@Override
public int compareTo(Student o) {
// 점수 오름차순
// if(o.point > this.point) return -1; // 내가 더 작으면 음수
// if(this.point > o.point) return 1; // 내가 더 크면 양수
// return 0; // 같으면 0
// 점수 내림차순
if(o.point < this.point) return -1; // 내가 더 작으면 음수
if(this.point < o.point) return 1; // 내가 더 크면 양수
return 0; // 같으면 0
}
} // end class
// Student를 이름(name) 오름차순으로 정렬해줄 수 있는 Comparator<> 제공
class Asc implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
// 이름
return o1.name.compareTo(o2.name);
}
} // end Asc
// Student를 이름(name) 내림차순으로 정렬해줄 수 있는 Comparator<> 제공
class Desc implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
// 이름
return o2.name.compareTo(o1.name);
}
} // end Asc
3. Lec31_Java_Util
1) com.lec.java.datetime01 패키지, DateTime01Main 클래스
package com.lec.java.datetime01;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/*
* 날짜를 다루기 위해 자바에선 java.util.Date 클래스 제공 JDK 1.0 부터..
* 이후 보완하여 java.util.Calendar 등장 JDK 1.1 부터..
* java.time 패키지 제공 JDK 1.8 (Java8)부터
*
* 지금은 java.time 패키지만으로 충분하긴 하나..
* 오랜시간 Date, Calendar 를 사용하여 만들었으므로 이 또한 알긴 알아야 한다
*
*/
public class DateTime01Main {
public static void main(String[] args) throws Exception{
System.out.println("Date객체로 날짜 다루기");
// 현재 날짜 얻어오기, 생성자가 현재 날짜, 시간을 얻어온다.
Date now = new Date(); // import java.util.date;
String strNow = now.toString();
System.out.println("1. Date 의 toString() 사용한 출력");
System.out.println(strNow);
System.out.println();
System.out.println("2. Date 의 get..()을 사용한 출력");
// Date객체의 대부분의 메소드들은 현재 deprecated 됨.
int year = now.getYear() + 1900; // 연도는 1900 이후 경과 년도
int month = now.getMonth() + 1; // 시작을 0부터
int day= now.getDate(); // 날짜
int weekDay = now.getDay(); // 요일 : 일요일이 0
int hour = now.getHours();
int minute = now.getMinutes();
int second = now.getSeconds();
System.out.println(year + "년 " + month + "월 " + day + "일 "
+ hour + "시 " + minute + "분 " + second + "초");
System.out.println();
System.out.println("3. SimpleDateFormat 사용한 출력");
SimpleDateFormat fmt = new SimpleDateFormat("yyyy년 MM월 dd일 hh시 mm분 ss초");
String strNow2 = fmt.format(now);
System.out.println(strNow2);
// yyyy-MM-dd hh:mm:ss 형식 출력
// 포맷에 사용되는 문자열 종류 : 자바의 정석 교재 p544
// H: 시간 (0~23), h : 시간 (1~12)
System.out.println(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
// ※ 현재 Date() 객체는 생성자를 제외하고는 거의다 deprecated 되어 있다.
System.out.println();
System.out.println("Date 테스트");
long baseTime = System.currentTimeMillis(); // 현재시간을 ms로 리턴
// 1970-01-01 00:00:00 UTC 기준으로 경과된 ms
//System.out.println(baseTime);
long surTime = baseTime + 2000; // 2초 뒤의 시간값 ms
SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.KOREA);
String mTime = mSimpleDateFormat.format(new Date(baseTime));
String mTime2 = mSimpleDateFormat.format(new Date(surTime));
System.out.println(mTime);
System.out.println(mTime2);
// 문자열을 Date 타입으로 파싱하기
System.out.println();
System.out.println("문자열 -> Date");
String oldstring = "2018-08-16 14:21:52.3";
Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S", Locale.KOREA).parse(oldstring);
System.out.println(date);
// 경과시간 체크하기
System.out.println();
System.out.println("경과시간");
long start = System.currentTimeMillis();
for(int i = 0; i < 5; i ++) {
System.out.println(i);
Thread.sleep(1000); // 1초간 딜레이
}
long end = System.currentTimeMillis();
long lapTime = end - start; // 경과시간
System.out.println("경과시간 : " + lapTime + " ms");
// nanosec : 10E-9초
start = System.nanoTime();
end = System.nanoTime();
System.out.println();
System.out.println("millisec -> time");
long durationInMillis = 1000000;
long millis = durationInMillis % 1000;
long sec = (durationInMillis / 1000) % 60;
long min = (durationInMillis / (1000 * 60)) % 60;
long hr = (durationInMillis / (1000 * 60 * 60)) % 24;
String time = String.format("%02d:%02d:%02d.%03d", hr, min, sec, millis);
System.out.println(time);
} // end main()
} // end class
[추가] Date객체 대부분의 메소드들은 현재 deprecated됨(곧 사라질 코드이기 때문에 사용을 권장하지 않는다는 뜻)
2) com.lec.java.datetime02 패키지, DateTime02Main 클래스
package com.lec.java.datetime02;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
/*
Calendar 객체
Calendar 는 추상클래스다. 그래서 new로 생성 불가.
날짜와 시간을 계산하는 방식(역법) 지역, 문화, 나라에 따라 다르기 때문에
이를 상속받아 개별적으로 구현함
Calendar 는 날짜/시간을 계산하는 꼭 필요한 메소드만 제공하고
특정한 역법(날싸 시간계산 ex: 음력) 은 상속받은 클래스에서 구현
특별히 상속할 필요 없으면 getInstance() static 메소드 호출
*/
public class DateTime02Main {
public static void main(String[] args) {
System.out.println("Calendar객체로 날짜 다루기");
// 특별한 역법을 쓰지 않는 경우. 우리나라 서력 사용.
Calendar cal = Calendar.getInstance();
System.out.println("get() 으로 날짜/시간 받아오기");
System.out.println("현재:");
// get(int field)
printDate(cal);
System.out.println();
System.out.println("TimeZone");
TimeZone timezone = TimeZone.getTimeZone("America/Los_Angeles");
cal = Calendar.getInstance(timezone); // 매개변수 TimeZone!
printDate(cal);
System.out.println();
// 시간대 문자열들 획득
String[] availableIDs = TimeZone.getAvailableIDs();
for(String id : availableIDs) {
System.out.println(id);
}
System.out.println();
System.out.println("Date ↔ Calendar 변환");
// 상호간에 변환할 일이 생긴다..
// 1-1. Calendar -> Date
cal = Calendar.getInstance();
Date date = cal.getTime();
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
// 1-2 Calendar -> Date
date = new Date(cal.getTimeInMillis());
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
// 2. Date -> Calendar
cal.setTime(date);
printDate(cal);
// 오늘날 우리 대한민국이 쓰는 달력은 GregorianCalendar(국제표준시) 이며
// 이는 Calendar 를 상속받은 클래스입니다.
// 기본적으로 시스템 설정 시각 (서울)으로 되어 있으며
// Locale 값을 설정하면 특정 지역 시각을 알수 있습니다.
System.out.println();
System.out.println("GregorianCalendar 사용");
GregorianCalendar gregCal = new GregorianCalendar();
printDate(gregCal);
int year = 2020;
System.out.println(year + " 는 윤년? " + gregCal.isLeapYear(year));
} // end main()
public static void printDate(Calendar now) {
int year = now.get(Calendar.YEAR); // 연도 리턴
int month = now.get(Calendar.MONTH) + 1; // 월을 리턴 0 ~ 11
int day = now.get(Calendar.DAY_OF_MONTH); // 일을 리턴
int week = now.get(Calendar.DAY_OF_WEEK); // 요일을 리턴 일요일: 1 ~ 토요일: 7
int ampm = now.get(Calendar.AM_PM); // AM 0 PM 1
int hour = now.get(Calendar.HOUR);
int minute = now.get(Calendar.MINUTE);
int second = now.get(Calendar.SECOND);
String strWeek = null;
switch(week) {
case Calendar.MONDAY:
strWeek = "월";
break;
case Calendar.TUESDAY:
strWeek = "화";
break;
case Calendar.WEDNESDAY:
strWeek = "수";
break;
case Calendar.THURSDAY:
strWeek = "목";
break;
case Calendar.FRIDAY:
strWeek = "금";
break;
case Calendar.SATURDAY:
strWeek = "토";
break;
case Calendar.SUNDAY:
strWeek = "일";
break;
}
String strAmPm = null;
switch(ampm) {
case Calendar.AM:
strAmPm = "오전";
break;
case Calendar.PM:
strAmPm = "오후";
break;
}
System.out.println(year + "-" + month + "-" + day + " " + strWeek);
System.out.println(strAmPm + " " + hour + ":" + minute + ":" + second);
} // end printDate()
} // end class
3) com.lec.java.datetime03 패키지, DateTime03Main 클래스
package com.lec.java.datetime03;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/* Calendar 객체를 사용한 시간 및 날짜 연산
*
*/
public class DateTime03Main {
public static void main(String[] args) {
System.out.println("날짜, 시간 연산");
Calendar cal = Calendar.getInstance();
DateFormat df = null;
Date date = null;
//-------------------------------------------------------
System.out.println("현재 시간에서 날짜 더하고 빼기");
cal.setTime(new Date()); // 현재 시간
df = new SimpleDateFormat("yyyy-MM-dd");
System.out.println("현재 : " + df.format(cal.getTime()));
//cal.add(Calendar.MONTH, 2);
//cal.add(Calendar.MONTH, 11);
//cal.add(Calendar.MONTH, -4);
cal.add(Calendar.DATE, 3);
System.out.println("계산 후 : " + df.format(cal.getTime()));
//-------------------------------------------------------
System.out.println();
System.out.println("특정 날짜에 더하고 빼기");
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
date = df.parse("2020-03-16 09:00:00");
} catch (ParseException e) {
e.printStackTrace();
}
cal.setTime(date);
System.out.println("주어진 시간 : " + df.format(cal.getTime()));
cal.add(Calendar.HOUR_OF_DAY, 5);
cal.add(Calendar.MINUTE, 20);
cal.add(Calendar.SECOND, 10);
System.out.println("계산 후 시간 : " + df.format(cal.getTime()));
//-------------------------------------------------------
System.out.println();
System.out.println("날짜 두개 더하기");
// 두개의 Date를 더하려면 두개의 Calendar를 사용해야 합니다.
Calendar cal2 = Calendar.getInstance();
System.out.println("cal: " + df.format(cal.getTime()));
System.out.println("cal2: " + df.format(cal2.getTime()));
cal.add(Calendar.DATE, -cal2.get(Calendar.DATE));
System.out.println("날짜 두개 계산후");
System.out.println("cal: " + df.format(cal.getTime()));
System.out.println("cal2: " + df.format(cal2.getTime()));
System.out.println("\n프로그램 종료");
} // end main()
} // end class
4. Lec23_InnerClass
1) com.lec.java.inner01 패키지, Inner01Main, TestOuter 클래스
** Inner01Main 클래스
package com.lec.java.inner01;
/*
Inner Class(내부 클래스)
1. Member inner class(멤버 내부 클래스): 다른 클래스 내부에서 선언된 클래스
2. Static inner class(static 내부 클래스): 다른 클래스의 내부에서 static으로 선언된 클래스
3. Local class(지역 클래스)
1) Local inner class(지역 내부 클래스): 메소드 내부에서 선언된 클래스
2) Anonymous inner class(익명 내부 클래스): 이름이 없는 local class
*/
public class Inner01Main {
public static void main(String[] args) {
System.out.println("Member Inner Class(멤버 내부 클래스)");
// 외부 클래스의 인스턴스
TestOuter out = new TestOuter(100);
// 멤버 내부 클래스의 인스턴스 생성
// 멤버 내부 클래스의 이름: [외부클래스 이름].[멤버 내부클래스 이름]
// [외부클래스 이름].[내부클래스 이름] 참조변수 =
// [외부클래스 인스턴스].new 내부클래스 생성자();
TestOuter.TestInner in = out.new TestInner(111);
in.printOuterValue();
in.printInnerValue();
System.out.println();
// 하나의 외부 클래스 인스턴스를 이용해서
// 멤버 내부 클래스의 인스턴스는 여러개 생성 가능.
TestOuter.TestInner in2 = out.new TestInner(123);
in2.printOuterValue();
in2.printInnerValue();
// 새로운 외부 클래스 인스턴스 생성
// out2 외부 클래스 인스턴스 생성
// out2 로부터 in4, in5라는 이름으로 내부 클래스 객체 만드세요
TestOuter out2 = new TestOuter(200);
System.out.println();
TestOuter.TestInner in4 = out2.new TestInner(201);
in4.printOuterValue();
in4.printInnerValue();
System.out.println();
TestOuter.TestInner in5 = out2.new TestInner(202);
in5.printOuterValue();
in5.printInnerValue();
System.out.println();
TestOuter.TestInner in7 = new TestOuter(30).new TestInner(330);
in7.printOuterValue();
in7.printInnerValue();
} // end main()
} // end class Inner01Main
** TestOuter 클래스
package com.lec.java.inner01;
/*
Member inner class(멤버 내부 클래스)
TestOuter 클래스 내부에서 TestInner 클래스를 정의
TestOuter: 외부 클래스(Outer Class, Enclosing Class)
TestInner: 멤버 내부 클래스(Member Inner Class)
1) 멤버 내부 클래스는 외부 클래스의 인스턴스가 생성된 이후에야
인스턴스 생성이 가능함.
2) 멤버 내부 클래스는 외부 클래스의 모든 멤버들(private 포함)을 사용 가능
*/
// 클래스: 멤버 변수들 (+ 생성자들) + 멤버 메소드들 = 데이터 타입
public class TestOuter {
// 멤버 변수:
private int value;
// 생성자:
public TestOuter() {}
public TestOuter(int value) {
this.value = value;
}
// 메소드:
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
// Member Inner Class 정의
// (수식어) class 클래스 이름{ ... }
public class TestInner{
// 멤버변수
private int innervalue;
// 생성자
public TestInner() {}
public TestInner(int val) {
this.innervalue = val;
}
// 멤버메소드
public void printOuterValue() {
System.out.println("value = " + value);
// Member inner class 에서는
// 외부클래스(outer class) 의
// 멤버를 직접 접근 가능
}
public void printInnerValue() {
System.out.println("innerValue = " + innervalue);
}
} // end TestInner
} // end class TestOuter
2) com.lec.java.inner02 패키지, Inner02Main, Car 클래스
** Inner02Main 클래스
package com.lec.java.inner02;
/*
언제 내부 클래스로 설계?
상속 관계로 묶을 수는 없지만,
A라는 객체가 생성된 이후에야 존재할 수 있는 B라는 객체가 있다고 한다면,
B를 A의 멤버 '내부 클래스'로 선언한다.
(예) 컴퓨터-CPU/메모리, 자동차-타이어
반면
'햄버거 세트 메뉴' 객체의 경우
햄버거 객체와 콜라 객체는 별개의 객체로도 존재 가능하니까
'햄버거' 와 '콜라' 는 '세트메뉴' 객체의 '멤버변수'로 붙도록 하는게 낳다
is-a : 상속관계
has-a (종속) : 멤버내부클래스
has-a (독립) : 멤버변수
*/
public class Inner02Main {
public static void main(String[] args) {
System.out.println("멤버 내부 클래스 활용");
Car myCar = new Car("Hot Pink");
Car.Tire myTire1 = myCar.new Tire(17);
myTire1.displayInfo();
Car.Tire myTire2 = myCar.new Tire(27);
Car.Tire myTire3 = myCar.new Tire(41);
myTire2.displayInfo();
myTire3.displayInfo();
} // end main()
} // end class Inner02Main
** Car 클래스
package com.lec.java.inner02;
public class Car {
// 멤버 변수( outer )
private String color;
// 생성자
public Car(String color) {
this.color = color;
}
// 메소드
public void displayCarInfo() {
System.out.println("color: " + color);
}
// 멤버 내부 클래스
public class Tire {
private int radius;
public Tire(int radius) {
this.radius = radius;
}
public void displayInfo() {
System.out.println("--- 자동차 정보 ---");
System.out.println("color : " + color);
System.out.println("tire : " + radius);
}
}
} // end class Car
3) com.lec.java.inner03 패키지, Inner03Main, TestOuter 클래스
** Inner03Main 클래스
package com.lec.java.inner03;
public class Inner03Main {
public static void main(String[] args) {
System.out.println("외부/내부 클래스의 this");
TestOuter out = new TestOuter(100);
TestOuter.TestInner in1 = out.new TestInner(111);
in1.printValue();
} // end main()
} // end class Inner03Main
** TestOuter 클래스
package com.lec.java.inner03;
public class TestOuter {
private int value;
public TestOuter(int value) {
this.value = value; // 1. Outer value
}
public int getValue() {
return value;
}
// 멤버 내부 클래스
public class TestInner{
private int value; // 2. Inner value
public TestInner(int value) {
this.value = value;
}
public void printValue() {
int value = 10; // 3. 지역변수 value
System.out.println("value = " + value); // 3번
System.out.println("this.value = " + this.value); // 2번
System.out.println("TestOuter.this.value = " + TestOuter.this.value); // 1번
}
}
} // end class TestOuter
4) com.lec.java.inner04 패키지, Nested01Main, TestOuter 클래스
** Nested01Main 클래스
package com.lec.java.inner04;
/*
Nested Class(중첩 클래스):
다른 클래스의 내부에서 멤버로 정의된 클래스인데,
static 키워드가 사용된 내부 클래스 (static inner class)
static: 클래스의 인스턴스가 생성되지 않아도 사용될 수 있는 멤버(변수, 메소드)에 사용
따라서, nested class는 외부 클래스의 인스턴스를 생성하지 않고,
내부 클래스의 인스턴스를 생성할 수 있다.
nested(static) class는
(외부 클래스에서) static으로 선언된 변수와 메소드만 사용 가능
중첩 클래스의 인스턴스 생성:
타입 참조변수 = new 생성자()
중첩 클래스의 이름(타입): [외부클래스 이름].[내부클래스 이름]
중첩 클래스의 생성자: new [외부클래스 이름].생성자()
*/
public class Nested01Main {
public static void main(String[] args) {
System.out.println("Nested Class(중첩 클래스): static inner class");
TestOuter.TestNested nest1 = new TestOuter.TestNested();
nest1.displayInfo();
} // end main()
} // end class Nested01Main
** TestOuter 클래스
package com.lec.java.inner04;
public class TestOuter {
// 멤버변수
private int value; // 인스턴스 변수
private static int count = 100; // 클래스 변수 (static)
// 생성자
public TestOuter(int value) {
this.value = value;
}
// Nested class (static inner class)
// static 안에서는 static 밖에 못쓴다!
public static class TestNested {
public void displayInfo() {
// static 클래스에서는 외부클래스의
// non-static 멤버 사용 불가
// 그렇기 때문에 아래의 코드는 에러
//System.out.println("value = " + value);
System.out.println("count = " + count);
}
} // end TestNested
} // end class TestOuter
// TestOuter: 외부 클래스(outer class, enclosing class)
// TestNested: 중첩 클래스(nested class, static inner class)
5) com.lec.java.inner05 패키지, Local01Main, TestOuter 클래스
** Local01Main 클래스
package com.lec.java.inner05;
/*
Local Inner Class: 블록({ ... }) 내부에서 정의된 클래스
1. 정의가 된 블록(메소드) 내부에서만 사용 가능 - 참조변수 선언, 인스턴스 생성
2. 접근 수식어(public, protected, private)는 쓸 수 없다.
3. 외부 클래스의 멤버 변수(private 포함)는 모두 사용 가능
4. effectively final인 지역변수나 매개변수만 사용 가능
effectively final 변수란?
1) final로 선언된 변수, 또는
2) 한 번 초기화가 된 이후로 값이 변경되지 않은 변수(Java 8에서 도입)
*/
public class Local01Main {
public static void main(String[] args) {
System.out.println("Local Inner Class(지역 내부 클래스)");
TestOuter out = new TestOuter();
out.localMethod(600);
} // end main()
} // end class Local01Main
** TestOuter 클래스
package com.lec.java.inner05;
public class TestOuter {
// TestOuter 클래스의 멤버 변수
private int num1 = 100;
// TestOuter 클래스의 멤버 메소드
public void localMethod(final int num4) {
int num2 = 200; // localMethod() 의 지역변수
// Local inner class
class TestLocal {
// 멤버변수
private int num3 = 300;
int num5 = 500;
// 멤버메소드
public void showNumber() {
System.out.println("num1 = " + num1); // 외부클래스의 멤버
System.out.println("num2 = " + num2); // class와 같은 local 의 지역변수
System.out.println("num3 = " + num3); // 자기 자신 의 멤버변수
System.out.println("num4 = " + num4);
System.out.println("num5 = " + num5);
}
} // end class TestLocal
TestLocal local = new TestLocal();
//num2 = 400; // 에러 발생
// num2 값을 변경하면.. 아래 showNumbers()에선
// 200 이 찍혀야 하나? 400이 찍혀야 하나?
// 그래서 로컬내부클래스에서 사용 가능한 지역의 변수는
// 반드시 effectively final 이어야 한다
// 즉 한번 초기화 된후 값이 변경되지 않거나, final 이어야 한다.
local.showNumber();
} // end localMethod()
} // end class TestOuter
[추가] Local Inner Class는 지역변수와 매개변수는 effectively final 변수만 사용 가능
effectively final 변수란? final로 선언된 변수, 한 번 초기화가 된 이후로 값이 변경되지 않은 변수
6) com.lec.java.inner06 패키지, Local02Main, Person 클래스
** Local02Main 클래스
package com.lec.java.inner06;
public class Local02Main {
public static void main(String[] args) {
System.out.println("Local 내부 클래스의 활용");
Person person = new Person("ABC");
Readable r = person.createInstance(40);
r.readInfo();
} // end main()
} // end class Local02Main
** Person 클래스
package com.lec.java.inner06;
public class Person {
// Person 외부 클래스의 멤버 변수
private String name;
// Person 외부 클래스의 생성자
public Person(String name) {
this.name = name;
}
/*
// 지역 클래스는 메소드 실행이 끝나게 되면 정의 자체가 사라지게 되는 클래스이다!!
// 메소드 내부에 정의된 지역 클래스 타입을 리턴하는 메소드는 만들 수 없다
// 그렇기 때문에 아래의 코드는 불가능한 코드!!
// 가능하게 만드는 코드가 있는데 아래의 코드가 그러한 코드이면서 설명이 기재되어 있음!
public PersonAge createInstance(int age) {
// Local inner class
class PersonAge {
public void readInfo() {
System.out.println("이름 " + name);
System.out.println("나이 " + age);
}
}
PersonAge p = new PersonAge();
return p;
} // end createInstance()
*/
// 2. 메소드의 리턴타입은 정의한 인터페이스 타입으로 정의
public Readable createInstance(int age) {
// 3. 로컬 클래스는 인터페이스를 구현(implements)하도록 정의
class PersonAge implements Readable{
// 여기서 중요한 점...!!
// readInfo를 위해서 PersonAge 클래스 만들어서 잠깐 사용한거임...!!
// 잠깐 사용할 클래스에 이름 짓고 클래스 만들기 너무 귀찮아..!! 비효율적이야!!
// 이래서 생긴 것이 익명 클래스!!!!! -> Anonymous inner class
@Override
public void readInfo() {
System.out.println("이름 : " + name);
System.out.println("나이 : " + age);
}
} //end PersonAge
// 4. 로컬 클래스의 인스턴스를 생성하고 리턴해줌
Readable person = new PersonAge(); // 다형성!!
return person;
} // end createInstance()
/*
지역 클래스는 메소드 실행이 끝나게 되면 정의 자체가 사라지게 되는 클래스임.
메소드 내부에 정의된 지역 클래스 타입을 리턴하는 메소드는 만들 수 없다.
경우에 따라서는, 지역 클래스에 정의된 메소드를
외부에서 직접 사용하고자 하는 경우가 발생할 수도 있습니다.
그걸 가능하게 하는 방법이
인터페이스(interface) + 다형성(polymorphism):
1. 외부에서 사용하고 싶은 메소드를 선언한 인터페이스를 작성
2. 메소드의 리턴타입은 정의한 인터페이스 타입으로 정의
3. 로컬 클래스는 인터페이스를 구현(implements)하도록 정의
4. 로컬 클래스의 인스턴스를 생성하고 리턴해줌
*/
} // end class Person
// 1. 외부에서 사용하고 싶은 메소드를 선언한 인터페이스를 작성
interface Readable {
public abstract void readInfo();
}
7) com.lec.java.inner07 패키지, Anonymous01Main, Person 클래스
** Anonymous01Main 클래스
package com.lec.java.inner07;
/*
Anonymous inner class(익명 내부 클래스):
이름이 없는 local inner class
이름이 없기 때문에 생성자를 만들 수가 없습니다.
클래스의 정의와 동시에 인스턴스를 생성합니다.
*/
// 익명클래스는 : 인터페이스, 추상클래스, 일반클래스 모두 가능하다
public class Anonymous01Main {
public static void main(String[] args) {
System.out.println("Anonymous Inner Class(익명 내부 클래스)");
// 1)
Person p = new Person("헐크");
Readable r = p.createInstance(55);
r.readInfo();
// 2)
Readable r2 = new Readable() {
@Override
public void readInfo() {
System.out.println("r2 의 readInfo 입니다");
}
};
r2.readInfo();
// 3)
Readable r3 = new Readable() {
@Override
public void readInfo() {
System.out.println("r3 의 readfo 입니다");
}
};
r3.readInfo();
// 4)
new Readable() {
@Override
public void readInfo() {
System.out.println("따끈따끈한 readInfo");
}
}.readInfo();
System.out.println();
System.out.println("-- 추상클래스도 익명클래스 가능 --");
Moveble m1 = new Moveble() {
@Override
public void move(int times) {
System.out.println("move() " + times * speed);
}
};
m1.move(2);
m1.move(10);
System.out.println();
System.out.println("-- 일반클래스도 익명클래스 가능--");
MyClass my1 = new MyClass();
my1.aaa();
my1.bbb();
MyClass my2 = new MyClass() {
@Override
public void aaa() {
System.out.println("my2의 AAA");
}
};
my2.aaa();
MyClass my3 =new MyClass() {
// 오버라이딩 : Alt + Shift + S + V
@Override
public void aaa() {
System.out.println("my3의 AAA");
}
};
my3.aaa();
} // end main()
} // end class Anonymous01Main
// 추상 클래스
abstract class Moveble{
int speed = 100;
public abstract void move(int times);
}
// 일반 클래스
class MyClass{
public void aaa() {
System.out.println("aaa");
}
public void bbb() {
System.out.println("bbb");
}
}
** Person 클래스
package com.lec.java.inner07;
public class Person {
// Person 외부 클래스의 멤버 변수
private String name;
// Person 외부 클래스의 생성자
public Person(String name) {
this.name = name;
}
public Readable createInstance(int age) {
// 익명 내부 클래스:
// 인스턴스 생성과 동시에 클래스가 정의됨.
// new 인터페이스() { 익명 클래스 내부 작성 };
// new 부모클래스() { 익명 클래스 내부 작성 };
return new Readable() {
@Override
public void readInfo() {
System.out.println("이름 : " + name);
System.out.println("나이 : " + age);
}
};
} // end createInstance
} // end class Person
// 인터페이스
interface Readable {
public abstract void readInfo();
}
8) com.lec.java.inner08 패키지, Anonymous02Main 클래스
package com.lec.java.inner08;
public class Anonymous02Main {
public static void main(String[] args) {
System.out.println("익명 내부 클래스 활용");
System.out.println();
System.out.println("1. 익명클래스를 사용하지 않는 경우");
Calculable tc1 = new TestMyMath();
double result = tc1.operate(1, 2);
System.out.println("result = " + result);
System.out.println();
System.out.println("2. 익명클래스를 사용하는 경우");
// 1)
Calculable tc2 = new Calculable() {
@Override
public double operate(double x, double y) {
return Math.pow(x, y);
}
};
System.out.println(tc2.operate(2, 4));
// 2)
result = new Calculable() {
@Override
public double operate(double x, double y) {
return x * y;
}
}.operate(123, 3);
System.out.println("result = " + result);
// 3)
System.out.println("result = " + new Calculable() {
@Override
public double operate(double x, double y) {
return x % y;
}
}.operate(15, 4));
} // end main()
} // end class Anonymous02Main
interface Calculable{
public abstract double operate(double x, double y);
}
/*
위와 같이 특정 추상 메소드만 implement 하는 목적으로 설계되는 인터페이스의 이름은
보통 ~ able 로 작명 경우가 많다.
자바에서 제공하는 대표적으로 많이 사용하는 이러한 인터페이스들.
Serializable, Cloneable, Readable, Appendable, Closeable,
AutoCloseable, Observable, Iterable, Comparable, Runnable,
Callable, Repeatable,
*/
class TestMyMath implements Calculable {
@Override
public double operate(double x, double y) {
return x + y;
}
}
9) com.lec.java.inner09 패키지, Anonymous09Main, Button 클래스
** Anonymous09Main
package com.lec.java.inner09;
/*
* 리스너 (Listener)
* 이벤트 중심의 프로그래밍 (웹, 앱, GUI 환경 등..) 에선
* 특정 '객체' 에 특정 '이벤트' 가 발생하면 어떠한 '동작'을 수행하도록 프로그래밍 한다.
*
* 함수형 프로그래밍이 아닌 자바에서는
* 리스너는 내부클래스(익명클래스)로 제공합니다.
*
*/
public class Anonymous09Main {
public static void main(String[] args) {
System.out.println("익명 클래스 응용 : Listener");
Button btnOk = new Button("OK");
btnOk.actionClick();
// 리스너 장착
btnOk.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick() {
System.out.println("딸깍딸깍");
}
});
btnOk.actionClick();
btnOk.setOnDblClickListener(new Button.OnDblClickListener() {
@Override
public void onDblClick() {
System.out.println("달그락 달그락 따닥");
}
});
btnOk.actionDblClick();
System.out.println("\n 프로그램 종료");
} // end main()
} //end class
** Button 클래스
package com.lec.java.inner09;
public class Button {
String name;
public Button(String name) {
this.name = name;
}
// 클릭시 수행하는 리스너 제공
// 리스너 인터페이스 : OnClickListener
// - 를릭시 동작 메소드 : onClick();
// 장착 메소드 : setOnClickListener
//---------------------------------------------------
// 리스너 인터페이스
public static interface OnClickListener {
void onClick(); // 클릭했을때 동작, 추상메소드
}
// 장착 리스너
private OnClickListener clickListener = null;
// 리스너 장착 메소드
public Button setOnClickListener(OnClickListener clickListener) {
this.clickListener = clickListener;
return this;
}
//----------------------------------------------
public void actionClick() {
System.out.println(name + " 버튼 클릭! (시스템 기본동작 수행)");
if(clickListener != null)
clickListener.onClick(); // 장착된 리스너 수행
}
// 더블클릭시 수행하는 리스너를 제공해보세요
// 리스너 인터페이스 : OnDblClickListener
// - 더블를릭시 동작 메소드 : onDblClick();
// 장착 메소드 : setOnDblClickListener
//---------------------------------------------------
// 리스너 인터페이스
public static interface OnDblClickListener{
void onDblClick();
}
// 장착 리스너
private OnDblClickListener dblClickListener;
// 리스너 장착 메소드
public Button setOnDblClickListener(OnDblClickListener dblClickListener) {
this.dblClickListener = dblClickListener;
return this;
}
//----------------------------------------------
public void actionDblClick() {
System.out.println(name + " 버튼 더블 클릭! 기본 시스템 동작");
if(dblClickListener != null) {
dblClickListener.onDblClick(); // 장착된 리스너 수행!
}
}
} // end class
'웹_프론트_백엔드 > JAVA프레임윅기반_풀스택' 카테고리의 다른 글
2020.03.31 (0) | 2020.03.31 |
---|---|
2020.03.30 (0) | 2020.03.30 |
2020.03.26 (0) | 2020.03.26 |
2020.03.25 (0) | 2020.03.25 |
2020.03.24 (0) | 2020.03.24 |