Study Web Development

11월 12일

이전으로

자바

7. 객체의 활용

7-6 추상 클래스

추상 클래스의 상속 관계
  1. ch06-object2 프로젝트의 kr.s09.abstracttest 패키지에 새 클래스 AbstractMain03 생성
package kr.s09.abstracttest;
// 추상 클래스
abstract class AbsEx1 {
	// 필드
	int a = 100;
	int b = 200;
	final String STR = "abstract test"; // 문자열 상수
	// 일반 메서드
	public String getStr() {
		return STR;
	}
	// 추상 메서드
	abstract public int getA();
	public abstract int getB();
}
// 추상 클래스에 추상 클래스를 상속한 경우, 상속받은 추상 메서드를 구현하지 않아도 오류가 발생하지 않음
abstract class AbsEx2 extends AbsEx1 {
	// 필드
	String msg = "신세계";
	// 추상 메서드
	public abstract String getMsg();
	// 추상 메서드 구현
	@Override public int getA() {
		return a;
	}
}
// 일반 클래스에 추상 클래스를 상속한 경우, 상속받은 추상 메서드를 모두 구현해야 함
public class AbstractMain03 extends AbsEx2 {
	// 추상 메서드 구현
	@Override public int getB() {
		return b;
	}
	@Override public String getMsg() {
		return msg;
	}
	
	public static void main(String[] args) {
		AbstractMain03 ab = new AbstractMain03();
		System.out.println(ab.getA());
		System.out.println(ab.getB());
		System.out.println(ab.getStr());
		System.out.println(ab.getMsg());
	}
}

12. Collection

Iterator

12-1 List

ArrayList
  1. ch09-collections 프로젝트의 kr.s01.list 패키지에 새 클래스 Product 생성
package kr.s01.list;

public class Product {
	private String name; // 상품명
	private int price; // 상품 가격
	private String num; // 상품 번호
	private String maker; // 제조사
	private int stock; // 재고
	// Getters and Setters
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public String getNum() {
		return num;
	}
	public void setNum(String num) {
		this.num = num;
	}
	public String getMaker() {
		return maker;
	}
	public void setMaker(String maker) {
		this.maker = maker;
	}
	public int getStock() {
		return stock;
	}
	public void setStock(int stock) {
		this.stock = stock;
	}
}
  1. 새 클래스 ProductMain 생성
package kr.s01.list;

import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class ProductMain {
	// 멤버 변수; list와 br을 생성자뿐만 아니라 멤버 메서드들에서 사용할 것이므로 멤버 변수로 선언해야 함
	ArrayList<Product> list;
	BufferedReader br;
	
	// 생성자
	public ProductMain() {
		list = new ArrayList<Product>();
		try {
			// 메뉴 메서드 호출 전에 입력 받을 수 있어야 함
			br = new BufferedReader(new InputStreamReader(System.in));
			// 객체가 생성되면 바로 메뉴 메서드 호출
			callMenu();
		}
		catch(Exception e) {
			// 콘솔에 예외 문구 표시
			e.printStackTrace();
		}
		finally {
			// 자원 정리; try~catch를 한 줄로 인식하므로 if문 블럭을 만들지 않아도 됨
			if(br!=null) try {br.close();} catch(IOException e) {}
		}
	}

	// 메뉴
	public void callMenu() throws IOException { // 입력 자체가 불가능한 경우는 종료
		while(true) {
			try {
				System.out.println("메뉴 : 1. 상품 입력, 2. 상품 목록 보기, 3. 종료");
				System.out.print("메뉴 > ");
				int num = Integer.parseInt(br.readLine());
				if(num == 1) {
					// 상품 입력 메서드 호출
					input();
				}
				else if(num == 2) {
					// 상품 목록 보기 메서드 호출
					output();
				}
				else if(num == 3) {
					System.out.println("프로그램 종료");
					break;
				}
				else {
					System.out.println("메뉴 번호를 잘못 입력하셨습니다.");
				}
			}
			catch(NumberFormatException e) { // 숫자를 입력하지 않은 경우는 while문을 반복하여 다시 입력하게 함
				System.out.println("숫자만 허용됩니다.");
			}
		}
	}
	
	// 상품 입력
	public void input() throws IOException {
		Product p = new Product();
		System.out.print("상품명 > ");
		p.setName(br.readLine());
		System.out.print("상품 번호 > ");
		p.setNum(br.readLine());
		System.out.print("상품 가격 > ");
		p.setPrice(Integer.parseInt(br.readLine())); // 가격의 경우 연산 가능성이 있으므로 String이 아니라 int로 입력받음
		System.out.print("제조사 > ");
		p.setMaker(br.readLine());
		System.out.print("재고 > ");
		p.setStock(Integer.parseInt(br.readLine()));
		
		// Product를 ArrayList에 저장
		list.add(p);
	}
	
	// 상품 목록 보기
	public void output() {
		System.out.println("상품명\t번호\t가격\t제조사\t재고");
		// ArrayList를 2차원 배열처럼 활용
		for(Product p : list) {
			System.out.printf("%s\t%s\t%,d원\t%s\t%,d개\n", p.getName(), p.getNum(), p.getPrice(), p.getMaker(), p.getStock());
		}
	}
	
	public static void main(String[] args) {
		// 객체가 생성되면 메뉴 메서드에서 작업을 수행하므로, main에서 작업을 진행하지 않으니 변수 선언할 필요도 없음
		new ProductMain();
	}
}
  1. 새 클래스 Member 생성
    • 이클립스에서 변수명을 일괄 변경하고 싶을 경우, 변수명을 선택하고 ctrl+2, r을 입력 후 변경하면 됨
package kr.s01.list;

public class Member {
	/* [실습]
	 * 멤버 변수 : 이름(name), 나이(age), 직업(job), 주소(address), 전화번호(phone)
	 */
	private String name;
	private int age;
	private String job;
	private String address;
	private String phone;
	// Getters and Setters
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getPhone() {
		return phone;
	}
	public void setPhone(String phone) {
		this.phone = phone;
	}
}
  1. 새 클래스 MemberMain 생성
package kr.s01.list;

import java.util.ArrayList;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class MemberMain {
	/*
	 * [실습]
	 * ArrayList, BufferedReader 생성
	 * 메뉴 : 1. 회원 정보 입력, 2. 회원 정보 출력, 3. 종료
	 */
	ArrayList<Member> ml;
	BufferedReader br;
	
	public MemberMain() {
		ml=new ArrayList<Member>();
		try {
			br=new BufferedReader(new InputStreamReader(System.in));
			callMenu();			
		}
		catch(IOException e) {
			e.printStackTrace();
		}
		finally {
			if(br!=null) try {br.close();} catch(IOException e) {}
		}
	}
	
	public void callMenu() throws IOException {
		while(true) {
			System.out.println("메뉴 : 1. 회원 정보 입력, 2. 회원 정보 출력, 3. 종료");
			System.out.print("메뉴 > ");
			String menu=br.readLine();
			if(menu.equals("1")) {
				setInfo();
			}
			else if(menu.equals("2")) {
				getInfo();
			}
			else if(menu.equals("3")) {
				System.out.println("프로그램이 종료되었습니다.");
				break;
			}
			else {
				System.out.println("번호를 잘못 입력하셨습니다.");
			}
		}
	}
	
	public void setInfo() throws IOException {
		Member m=new Member();
		System.out.print("이름 > ");
		m.setName(br.readLine());
		m.setAge(parseInputData("나이 > ")); // 나이 검증 메서드를 별도로 분리하여 호출
		System.out.print("직업 > ");
		m.setJob(br.readLine());
		System.out.print("주소 > ");
		m.setAddress(br.readLine());
		System.out.print("전화번호 > ");
		m.setPhone(br.readLine());
		ml.add(m);
	}
	
	// 입력값이 숫자인지 확인하고, 1 이상의 값만 입력받는 메서드
	public int parseInputData(String title) throws IOException {
		int a;
		while(true) {
			System.out.print(title);
			try {
				a=Integer.parseInt(br.readLine());
				if(a>=1) {
					break;
				}
				else {
					System.out.println("나이는 0 이하일 수 없습니다.");
				}
			}
			catch(NumberFormatException e) {
				System.out.println("나이는 숫자만 입력할 수 있습니다.");
			}
		}
		return a;
	}
	
	public void getInfo() {
		System.out.println("총 회원 수 : "+ml.size());
		if(ml.size()!=0) System.out.println("이름\t나이\t직업\t주소\t전화번호");
		for(Member m:ml) {
			System.out.println(m.getName()+"\t"+m.getAge()+"세\t"+m.getJob()+"\t"+m.getAddress()+"\t"+m.getPhone());
		}
	}
	
	public static void main(String[] args) {
		new MemberMain();
	}
}

12-3 Queue

LinkedList
  1. 새 패키지 kr.s03.queue 생성하고 새 클래스 QueueMain 생성
package kr.s03.queue;

import java.util.LinkedList;

public class QueueMain {
	public static void main(String[] args) {
		String[] array = {"서울", "인천", "광주", "부산", "대구"};
		LinkedList<String> ll = new LinkedList<String>();
		
		// ll에 offer() 메서드로 데이터 저장
		for(int i=0;i<array.length;i++) {
			ll.offer(array[i]);
		}
		System.out.println(ll);
		
		// ll에서 poll() 메서드로 데이터 꺼냄(=ll 안의 데이터는 지워짐)
		while(ll.peek()!=null) { // ll에 저장된 첫 번째 요소를 검색
			System.out.print(ll.poll() + "\t"); // ll에 저장된 첫 번째 요소를 반환하고 제거
		}
		System.out.println("\n"+ll);
	}
}

12-4 Set

HashSet
  1. 새 패키지 kr.s04.set 생성하고 새 클래스 HashSetMain01 생성
package kr.s04.set;

import java.util.HashSet;
import java.util.Iterator;

public class HashSetMain01 {
	public static void main(String[] args) {
		String[] array = {"Java", "Oracle", "JSP", "Java", "HTML"};
		HashSet<String> hs = new HashSet<String>();
		
		// 데이터 저장
		for(String n : array) {
			hs.add(n); // 중복 불허; add() 메서드에서 걸러냄
		}
		System.out.println(hs); // 정렬을 보장하지 않음

		// 데이터 읽기; HashSet에서 바로 읽는 것이 아니라, Iterator로 복사해서 읽는 것이 원칙
		Iterator<String> ir = hs.iterator(); // iterator() 메서드로 HashSet의 데이터를 Iterator에 복사
		while(ir.hasNext()) { // hasNext() 메서드로 저장된 데이터가 있는지 확인
			System.out.println(ir.next()); // next() 메서드로 데이터를 꺼냄
		}
		
		System.out.println();
		
		// 확장 for문을 이용한 데이터 읽기
		for(String s : hs) {
			System.out.println(s);
		}		
	}
}
  1. 새 클래스 HashSetMain02 생성
package kr.s04.set;

import java.util.HashSet;
import java.util.Random;
import java.util.Collections;
import java.util.ArrayList;

public class HashSetMain02 {
	public static void main(String[] args) {
		HashSet<Integer> set = new HashSet<Integer>();
		Random r = new Random();
		while(set.size()<6) {
			set.add(r.nextInt(45)+1); // 1~45 범위의 난수, 중복값 불허
		}
		System.out.println(set);
		
		ArrayList<Integer> list = new ArrayList<Integer>(set); // Collections.sort() 메서드는 List 인터페이스 자료형만 인자로 받기 때문에, ArrayList의 생성자를 통해 set의 데이터를 복사한 list를 생성
		Collections.sort(list);
		for(int num : list) {
			System.out.print(num + "\t");
		}
	}
}

12-5 Map

HashMap
  1. 새 패키지 kr.s05.map 생성하고 새 클래스 HashMapMain01 생성
package kr.s05.map;

import java.util.HashMap;

public class HashMapMain01 {
	public static void main(String[] args) {
		HashMap<String, Integer> mp = new HashMap<String, Integer>();
		
		// mp에 put() 메서드로 데이터 저장
		mp.put("너굴", 95);
		mp.put("콩돌", 100);
		mp.put("밤돌", 85);
		mp.put("링크", 93);
		mp.put("젤다", 70);
		mp.put("콩돌", 0); // Map 인터페이스는 식별자의 중복을 불허하며, 식별자가 중복되었을 경우 마지막에 등록한 값을 저장
		mp.put("가논", null); // 값으로 null 인정
		mp.put(null, 100); // 식별자로 null 인정
		System.out.println(mp);
		
		// get() 메서드에 식별자를 인자로 입력하여 연결된 값을 반환받음
		int num = mp.get("콩돌"); // Integer에서 int로 자동 변환 발생
		System.out.println("콩돌의 성적은 " + num);
		int nullnum = mp.get(null);
		Integer nullnum2 = mp.get("가논"); // int로 변수 선언시 Integer를 int로 변환하는 과정에서 예외 발생; 저장시에는 문제가 없어도 호출시 문제될 수 있으므로 조건문으로 null 제외하도록 검증하는 것이 안전
		System.out.println("식별자 null : " + nullnum + ", 값 null : " + nullnum2);
	}
}
  1. 새 클래스 HashMapMain02 생성
package kr.s05.map;

import java.util.HashMap;
// import java.util.Set;
import java.util.Iterator;

public class HashMapMain02 {
	public static void main(String[] args) {
		String[] msg = {"Berlin", "Paris", "Seoul", "New York", "London"};
		HashMap<Integer, String> mp = new HashMap<Integer, String>();

		// 반복문을 통해 데이터 저장
		for(int i=0;i<msg.length;i++) {
			mp.put(i, msg[i]);
		}
		System.out.println(mp);
		
		// 식별자를 모두 추출하고, 식별자를 통해 값을 읽기; keySet() 메서드를 통해 Set 인터페이스를 구현한 객체로 복사 후, iterator() 메서드를 통해 Iterator 객체로 복사해야 함
		Iterator<Integer> keys = mp.keySet().iterator(); // mp.keySet()은 Set 인터페이스 자료형
		while(keys.hasNext()) {
			Integer key = keys.next();
			System.out.println(key + ", " + mp.get(key));
		}
	}
}
Hashtable
  1. 새 클래스 HashtableMain 생성
package kr.s05.map;

import java.util.Hashtable;
import java.util.Enumeration;

public class HashtableMain {
	public static void main(String[] args) {
		Hashtable<String, String> h = new Hashtable<String, String>();
		
		// h에 put() 메서드로 데이터 저장
		h.put("name", "홍길동");
		h.put("age", "20"); // 값의 자료형을 String으로 지정했기 때문에 10 입력시 예외 발생
		h.put("tel", "010-1234-5678");
		h.put("job", "탐정");
		h.put("address", "서울시");
		h.put("name", "너굴"); // 식별자의 중복을 불허하며, 식별자가 중복되는 경우 마지막에 등록한 값을 저장
		// h.put("zipcode", null); // 실행시 NullPointerException; 값에 null을 인정하지 않음
		// h.put(null, "마포구"); // 실행시 NullPointerException; 식별자에 null을 인정하지 않음
		System.out.println(h);
		
		// get() 메서드에 식별자를 인자로 입력하여 연결된 값을 반환받음
		String name = h.get("name");
		System.out.println("name = " + name);

		System.out.println();
		
		// h에 저장된 식별자 구하기; keys() 메서드를 통해 Enumeration 객체로 복사해야 함
		Enumeration<String> en = h.keys();
		while(en.hasMoreElements()) {
			String key = en.nextElement();
			System.out.println(key + " = " + h.get(key));
		}
	}		
}

8. 내부 클래스

인스턴스

  1. 새 자바 프로젝트 ch10-inner 생성하고 새 패키지 kr.s01.member 생성 후 새 클래스 MemberMain01 생성
package kr.s01.member;

class Outer {
	// 멤버 변수
	int x = 100;
	// 인스턴스 내부 클래스
	class Inner {
		int y = 200;
	}
}

public class MemberMain01 {
	public static void main(String[] args) {
		Outer ot = new Outer();
		System.out.println(ot);
		System.out.println("x = " + ot.x);
		
		System.out.println();
		
		// 인스턴스 내부 클래스의 자료형은 .으로 외부 클래스명을 함께 명시해야 하며, 객체 생성은 외부 클래스의 객체에 .으로 접근 후 new와 생성자 사용
		Outer.Inner oi = ot.new Inner();
		System.out.println(oi);
		System.out.println("y = " + oi.y);	
	}
}
  1. 새 클래스 MemberMain02 생성
package kr.s01.member;

class Outer2 {
	// 멤버 변수
	private int x = 100;
	// 인스턴스 내부 클래스
	class Inner2 {
		private int y = 200;
		public void make() {
			System.out.println("x = " + x); // x와 Inner2가 모두 Outer2의 멤버로 인식되기 때문에 Outer2의 private 변수를 Inner2에서 바로 접근 가능
			System.out.println("y = " + y);
		}
	}
}

public class MemberMain02 {
	public static void main(String[] args) {
		Outer2 ot = new Outer2();
		Outer2.Inner2 oi = ot.new Inner2();
		oi.make();
	}
}
  1. 새 클래스 MemberMain03 생성
package kr.s01.member;

class Outer3 {
	// 멤버 변수
	int value = 10;
	// 인스턴스 내부 클래스
	class Inner3 {
		int value = 20;
		public void method1() {
			int value = 30;
			System.out.println("지역 변수 value : " + value);
			System.out.println("Inner3의 멤버 변수 value : " + this.value);
			System.out.println("Outer3의 멤버 변수 value : " + Outer3.this.value);
		}
	}
}

public class MemberMain03 {
	public static void main(String[] args) {
		Outer3.Inner3 oi = new Outer3().new Inner3(); // 외부 클래스의 객체를 호출할 일이 없다면 참조 변수를 따로 만들지 않아도 됨
		oi.method1();
	}
}

다음으로