package ex0730;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/*
  ArrayList
    : List 인터페이스 구현 클래스
    : 검색시 속도가 빠름
    : 동기화 되지 않음(멀티 스레드에서 안전하지 않음)
  LinkedList
    : List 인터페이스 구현 클래스
    : 검색은 느림
    : 앞에서 추가하고 뒤에서 삭제가 빈번한 경우 빠름
    : 앞뒤 아무데서나 추가 삭제 가 빈번한 경우 
    : 중간에 삽입 삭제시에는 속도가 현저히 떨어짐. LinkedList 사용하지 말 것.
    : 동기화 되지 않음(멀티 스레드에서 안전하지 않음)
 */
public class Ex01_List {
	public static void main(String[] args) {
		List<String> list1 = new ArrayList<>();
		list1.add("자바");
		list1.add("오라클");
		list1.add("서블릿");
		System.out.println("ArrayList...");
		print(list1);
		
		List<String> list2 = new LinkedList<String>();
		list2.add("서울");
		list2.add("부산");
		list2.add("대구");
		System.out.println("\nLinkedList...");
		print(list2);
		
	}
	
	public static void print(List<String> list) {
		for(String s : list) {
			System.out.print(s +"  ");
		}
		System.out.println();
	}
}

2021.07.30 - [쌍용강북교육센터/7월] - Q 0729_Ex001~Ex002_List

 

Q 0729_Ex001~Ex002_List

package ex0729; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; /* - List 인터페이스 : 순서가 있다. : 배열과 유사한 구조 : 가변 길이(저장..

development-writing.tistory.com

내가 여기에서 왜 업캐스팅을 하지? 하고 오늘 수업할 때 선생님께 질문했더니, 예제를 통해 그 이유를 알려주셨다.

업캐스팅을 안했으면 ArrayList 와 LinkedList 두 개를 선언하고 print() 메소드를 정의할 때,  매개변수에 

public static void print(ArrayList<String> list1)

public static void print(LinkedList<String> list2) 이렇게 해야 되서, 업캐스팅해서 한 번만 적으면 코드가 짧아진다.


package ex0730;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Ex02_List {
	public static void main(String[] args) {
		ArrayList<String> list1 = new ArrayList<>();
		LinkedList<String> list2 = new LinkedList<>();
		
		timeTest1("LinkedList", list2);
		timeTest1("ArrayList", list1); // 앞줄과 순서를 바꿔보면 시간 차이가 보임
		System.out.println("-------------------------------");
		
		timeTest2("LinkedList", list2);
		timeTest2("ArrayList", list1);
	}
	
	public static void timeTest1(String cls, List<String> list) {
		long s, e;
		
		s = System.nanoTime();
		for(int i=0; i<20000; i++) {
			list.add( String.valueOf(i) );
				// 가장 뒤에 추가하는 경우 실행 순서에 따라 차이가 있으나 ArrayList가 빠름
		}
		e = System.nanoTime();
		
		System.out.printf("%s, 시간:%,d\n", cls, (e-s));
		
		list.clear();
	}

	public static void timeTest2(String cls, List<String> list) {
		long s, e;
		
		s = System.nanoTime();
		for(int i=0; i<20000; i++) {
			list.add( 0, String.valueOf(i) ); // 앞 추가 삭제시 LinkedList 가 빠름
		}
		e = System.nanoTime();
		
		System.out.printf("%s, 시간:%,d\n", cls, (e-s));
		
		list.clear();
	}
}

이것은 ArrayList와 LinkedList 검색 시 걸리는 시간을 비교해본 것이다. 

'쌍용강북교육센터 > 7월' 카테고리의 다른 글

Q 0729_Ex001~Ex002_List  (0) 2021.07.30
0729_Ex06~Ex09_system : Java API  (0) 2021.07.29
0729_ConsoleEx_콘솔 입력  (0) 2021.07.29
0729_Ex01~Ex05_Generic  (0) 2021.07.29
0728_Ex11~Ex17_generic : 제네릭  (0) 2021.07.29
package ex0729;

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

/*
 - List 인터페이스
 	: 순서가 있다.
 	: 배열과 유사한 구조
 	: 가변 길이(저장 공간이 부족하면 자동으로 공간이 늘어남)
 	: 중복적인 요소도 추가 가능
 	: 중간에 데이터를 추가하거나 삭제도 가능
 	: 주요 구현 클래스 - ArrayList, Vector, LinkedList, Stack 등..
 	: 동기화 지원 : Vector - 다중 스레드 환경에서 안전
 	: 동기화 지원 안함 : AraayList, LinkedList - 다중 스레드 환경에서 안전하지 않음(속도 빠름)
 */
public class Ex001_List {
	public static void main(String[] args) {

		List<String> list = new ArrayList<String>(); // up casting
		String s;

		// 마지막에 요소 추가
		list.add("서울");
		list.add("부산");
		list.add("인천");
		list.add("광주");
		list.add("서울"); // 요소의 중복 가능
		list.add("대전");

		System.out.println(list);

		// 2인덱스에 데이터 추가
		list.add(2, "대구");
		System.out.println(list);

		// 데이터 개수 ?
		System.out.println("개수 : " + list.size());

		// 처음 데이터
		s = list.get(0);
		System.out.println("처음 : " + s);

		// 두번째
		s = list.get(1);
		System.out.println("두번째 : " + s);

		// 마지막
		s = list.get(list.size() - 1);
		System.out.println("마지막 : " + s);

		// 처음에 한국 추가
		list.add(0, "한국");
		System.out.println(list);

		// 처음의 데이터를 대한민국으로 수정
		list.set(0, "대한민국");
		System.out.println(list);

		int idx;
		// 인천은 몇 번째 인덱스에 ?
		idx = list.indexOf("인천");
		System.out.println("인천 인덱스 : " + idx);

		idx = list.indexOf("세종"); // 없으면 -1
		System.out.println("세종 인덱스 : " + idx);

		idx = list.indexOf("서울");
		System.out.println("서울(처음부터 검색) : " + idx);

		idx = list.lastIndexOf("서울");
		System.out.println("서울(뒤부터 검색) : " + idx);

		// 부산 존재 여부
		System.out.println("부산이 존재합니까 ? " + list.contains("부산"));

		// 대한민국 삭제
		// list.remove("대한민국");
		list.remove(0);
		System.out.println(list);

		System.out.println("전체 출력 - 1");
		for (int i = 0; i < list.size(); i++) {
			System.out.print(list.get(i) + "  ");
		}
		System.out.println();

		System.out.println("전체 출력 - 2");
		for (String str : list) {
			System.out.print(str + "  ");
		}
		System.out.println();

		System.out.println("전체 출력 - 3");
		// 반복자. 순방향만 가능
		Iterator<String> it = list.iterator(); // 하나씩 데이터를 꺼낸다.
		while (it.hasNext()) { // 데이터가 존재하면 true, 없으면 false
			String str = it.next(); // 있는 곳의 데이터를 돌려주고 다음으로 간다.
			System.out.print(str + "  ");
		}
		System.out.println();

		System.out.println("역순 - 1");
		for (int i = list.size() - 1; i >= 0; i--) {
			System.out.print(list.get(i) + "  ");
		}
		System.out.println();

		System.out.println("역순 - 2");
		// ListIterator : 순방향과 역방향 모두 이동 가능
		// 반복자의 위치를 가장 마지막으로 이동
		ListIterator<String> it2 = list.listIterator(list.size());
		while (it2.hasPrevious()) {
			String str = it2.previous();
			System.out.print(str + "  ");
		}
		System.out.println();

		// 모두 지우기
		list.clear();
		System.out.println("모두 삭제 후 개수 : " + list.size());

	}
}

List 인터페이스

  • 순서가 있는 컬렉션
  • 목록에서 각 요소가 삽입되는 위치를 제어 할 수 있다.
  • 요소를 인덱스로 관리하며, 인덱스로 요소를 검색하거나 삭제 할 수 있다.
  • 동일한 요소(객체)를 중복해서 저장할 수 있다.
  • List 컬렉션은 객체 자체가 저장되는 것이 아니라 객체의 번지를 참조한다.
  • null도 저장이 가능하며, null을 저장한 경우에는 해당 인덱스는 객체를 참조하지 않는다.
  • 배열과 유사한 구조
  • 가변 길이로 저장 공간이 부족하면 자동으로 공간이 늘어난다.

 

List를 하기 위해서 제네릭을 배운 것!

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

String인 자료형을 저장할 리스트를 생성

add 메소드로 요소를 추가 할 수 있다.

size 메소드로 리스트의 크기를 알 수 있다.

set 메소드로 원하는 위치에 리스트를 변경 할 수 있다.

contains 메소드로 리스트에서 검색 후 boolean으로 반환해준다.

package ex0729;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Ex002_List {

	public static void main(String[] args) {
		List<String> list1 = new ArrayList<String>();
		list1.add("서울");
		list1.add("부산");
		list1.add("대구");

		List<String> list2 = new ArrayList<String>();
		list2.add("강원");
		list2.add("경기");
		list2.add("경상");

		// list2에 list1의 모든 데이터를 추가
		list2.addAll(list1);
		System.out.println(list2);

		// List<String> => String[]
		String[] ss = list2.toArray(new String[list2.size()]);
		System.out.println("리스트를 배열로 복사...");
		for (String s : ss) {
			System.out.print(s + "  ");
		}
		System.out.println();

		// String[] => List<String>
		List<String> list3 = Arrays.asList(ss);
		System.out.println("배열을 리스트로 복사 후 : " + list3);

		// subList(a, b) : a인덱스에서 b-1인덱스까지의 부분 List
		List<String> list4 = list3.subList(1, 4);
		System.out.println(list4); // [경기, 경상, 서울]

		// 전체 삭제
		list1.clear();
		System.out.println("전체 삭제 후 : " + list1.size());

		// list2의 데이터중 [경상, 서울, 부산] 삭제
		System.out.println("삭제 전 : " + list2);
		list2.subList(2, 5).clear();
		
		System.out.println("삭제 후 : " + list2);
		
		
	}

}

list의 메소드를 익히고 적절하게 사용해보도록 하자!

 

배열과 ArrayList

  • 배열은 한 번 크기가 결정되면 배열의 크기를 변경할 수 없다.
  • 배열의 처음이나 중간에 데이터를 삽입하는 경우, 기존 데이터가 존재하면 데이터를 덮어쓰기 때문에 기존 데이터는 사라진다.
  • ArrayList는 가변 길이의 자료구조로 데이터의 검색에 유리하며, 추가 또는 삭제에는 성능을 고려해야 한다.
  • 리스트의 처음, 끝, 중간에 자료를 추가 또는 삭제하는 기능을 제공한다.

근데 왜 

List<String> list = new Arraylist<>(); 이렇게 업 캐스팅 하는 건쥐..?

'쌍용강북교육센터 > 7월' 카테고리의 다른 글

0730_Ex01~Ex02_List  (0) 2021.07.30
0729_Ex06~Ex09_system : Java API  (0) 2021.07.29
0729_ConsoleEx_콘솔 입력  (0) 2021.07.29
0729_Ex01~Ex05_Generic  (0) 2021.07.29
0728_Ex11~Ex17_generic : 제네릭  (0) 2021.07.29
package ex0729;

public class Ex06_system {

	public static void main(String[] args) {
		String s;

		s = System.getProperty("os.name");
		System.out.println("운영체제 : " + s);

		s = System.getProperty("file.encoding");
		System.out.println("character set : " + s); // MS949(euc-kr 유사)

		s = System.getProperty("java.version");
		System.out.println("자바 버전 : " + s);

		s = System.getProperty("user.dir");
		System.out.println("현재 작업 경로 : " + s);

		
	}

}

package ex0729;

import java.util.Enumeration;
import java.util.Properties;

public class Ex07_system {

	public static void main(String[] args) {
		// 시스템 환경 설정 정보(운영체제, 인코딩, 작업 경로 등...)
		Properties p = System.getProperties();
		Enumeration<?> e = p.propertyNames();

		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			String value = p.getProperty(key);
			System.out.println(key + "->" + value);
		}

	}

}

이런저런것들 볼 수 있음...

package ex0729;

import java.util.Scanner;

public class Ex08_system {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n;

		try {
			while (true) {
				System.out.print("정수 ? ");
				n = sc.nextInt();

				if (n == 0) {
					System.exit(0); // 프로그램 강제 종료. finally 블록은 실행 안됨.
					// return; // finally 블럭은 실행됨.
					// return 은 main() 메소드를 빠져 나가는 것으로
					// main()이 종료된다고 프로그램이 종료되는 것은 아니다.
					// main()은 프로그램의 진입점이지만 종료점은 아니다.
				}

				System.out.println("입력 값 : " + n);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println("final block ...");
			sc.close();
		}
		System.out.println("end...");
		
	}

}

'쌍용강북교육센터 > 7월' 카테고리의 다른 글

0730_Ex01~Ex02_List  (0) 2021.07.30
Q 0729_Ex001~Ex002_List  (0) 2021.07.30
0729_ConsoleEx_콘솔 입력  (0) 2021.07.29
0729_Ex01~Ex05_Generic  (0) 2021.07.29
0728_Ex11~Ex17_generic : 제네릭  (0) 2021.07.29
package ex0729;

import java.io.Console;

public class ConsoleEx {

	public static void main(String[] args) {
		// 콘솔 입력을 지원하는 클래스로 JDK 6이상 부터 가능. 이클립스에서는 테스트 불가.
		Console c = System.console();
		if( c==null) {
			System.out.println("Console을 지원하지 않습니다.");
			System.exit(0);
		}
		
		String id = c.readLine("%s", "ID : ");
		char[] pwd = c.readPassword("%s", "Password : ");
		
		String s = new String(pwd); // char[]을 String으로
		
		System.out.println("아이디 : " + id);
		System.out.println("패스워드 : " + s);

	}

}

위 소스는 이클립스로 실행이 안되기 때문에 cmd 창에서 확인해보았다.

패스워드를 입력할 때 보이지 않게끔 해주는 거 보려고 한 코드!

'쌍용강북교육센터 > 7월' 카테고리의 다른 글

Q 0729_Ex001~Ex002_List  (0) 2021.07.30
0729_Ex06~Ex09_system : Java API  (0) 2021.07.29
0729_Ex01~Ex05_Generic  (0) 2021.07.29
0728_Ex11~Ex17_generic : 제네릭  (0) 2021.07.29
0728_Ex01~Ex03_exception : 예외처리  (0) 2021.07.29
package ex0729;

public class Ex01 {
	public static void main(String[] args) {
		Test1<Integer> t = new Test1<>();
		
		t.append(10);
		t.append(20);
		t.append(30);
		
		// t.append("자바"); // 컴파일 오류
		
		Integer i = t.get(2);
		System.out.println(i);
	}
}

class Test1<E> {
	private Object[] data;
	private int count;

	public Test1() {
		data = new Object[10];
	}

	public void append(E e) {
		if(count >= data.length) {
			// ArrayIndexOutOfBoundsException() : unchecked 예외. 배열의 첨자가 초과한 경우 발생
			throw new ArrayIndexOutOfBoundsException("요소의 개수를 초과 했습니다.");
		}
		
		data[count++] = e;
	}
	
	@SuppressWarnings("unchecked") // 부적절한 컴파일러의 경고를 제거하기 위해 사용
	public E get(int index) {
		if(index >= count) {
			throw new ArrayIndexOutOfBoundsException(index);
		}
		
		// 제네릭으로 casting 하면 경고가 발생
		return (E) data[index];
	}
	
	public int getCount() {
		return count;
	}
	
}

@SuppressWarnings("unchecked") // 부적절한 컴파일러의 경고를 제거하기 위해 사용

하지만 정확하게 알 때만 사용. 거의 사용하지 않는다!!

<위 코드는 아래와 비교해서 이해할 것!>

package ex0729;

public class Ex02 {
	public static void main(String[] args) {
		Test2<Integer> t = new Test2<>();
		t.append(10);
		t.append(20);
		t.append(30);

		// Integer[] i = t.get(); // 런타임 오류. ClassCastException. 배열은 강제 형변환이 안됨.

		// Cast가 필요
		Object[] oo = t.get();
		for (Object o : oo) {
			Integer i = (Integer) o;
			System.out.println(i);
		}
		// 제네릭배열은 의미가 없다.
	}
}

class Test2<E> {
	private E[] data;
	private int count;

	@SuppressWarnings("unchecked")
	public Test2() {
		// 제네릭 배열 메모리 할당
		// data = new E[10]; // 컴파일 오류
		data = (E[]) new Object[10]; // 제네릭은 Object로 메모리할당을 해야 함.
	}

	public void append(E e) {
		if (count >= data.length) {
			throw new ArrayIndexOutOfBoundsException("배열 요소의 개수를 초과 했습니다.");
		}

		data[count++] = e;
	}

	public E[] get() {
		return data;
	}

	public int getCount() {
		return count;
	}
}

위에서는 Object로 배열을 만들어서 생성자에서 배열의 메모리 할당을 해주었는데,

밑에서는 제네릭클래스에서 제네릭 배열을 만들었다. 

배열의 선언을 위해 생성자에서 할당하려고 했을 때 

data = new E[10]; 은 컴파일 오류가 발생했다. 메모리 할당을 위해서는 Object로 해야 했다. 그래서 배열 메모리 할당 후에 data에 다시 제네릭타입으로 캐스팅하고 넣었다. 여기서 느낌표가 발생해서 다시 

@SuppressWarnings("unchecked") 를 넣어줬다.

 

메인 클래스에서 제네릭타입을 Integer로 해서 객체를 생성한 후 Integer 값들을 3개를 넣었는데 그 배열을 다시 만들으려 했으나

Integer[] i = t.get(); // 런타임 오류. ClassCastException. 배열은 강제 형변환이 안된다.

결국 이 배열을 받기 위해서는 Object로 배열을 생성해서 받아야 했다.

 

package ex0729;

public class Ex03 {
	public static void main(String[] args) {
		Test3<Integer> t = new Test3<>();
		
		Integer[] i = {10,20,30};
		
		t.set(i);
		
		Integer[] i2 = t.get();
		System.out.println(i2[1]);
		
	}
}

class Test3<E> {
	private E[] data;
	
	public void set(E[] data) {
		this.data = data;
	}
	
	public E[] get() {
		return data;
	}
}

 

 

package ex0729;

public class Ex04 {
	public static void main(String[] args) {
		Test4<Number> ob1 = new Test4<>();	
		ob1.set(new Integer(30)); // 타입 매개변수의 상속 관계는 성립
		System.out.println(ob1.get());
		
		// Number n = ob1.get();
		// Integer i = ob1.get(); // 컴파일 오류
		// Integer i = (Integer)ob1.get();
		
		// Number n = new Integer(30); // 업 캐스팅
		Test4<Integer> ob2 = new Test4<>();
		ob2.set(new Integer(30));
		// Test4<Number> ob3 = ob2; // 컴파일 오류. 제네릭은 업캐스팅 불가.
		
		
	}
}

class Test4<T> {
	private T t;
	
	public void set(T t) {
		this.t=t;
	}
	
	public T get() {
		return t;
	}
}

제네릭 타입을 Number로 주었기 때문에 

Integer i = ob1.get(); 은 컴파일 오류이고 강제적으로 캐스팅을 한 후에는 가능하다.

Integer i = (Integer)ob1.get();

Test4<Number> ob3 = ob2; 제네릭은 업캐스팅이 불가해서 컴파일 오류이다.

 

제네릭은 컴파일 단계에서 타입 안정성을 위해 지원하므로 기본적으로 다형성을 갖지 않는다. 

package ex0729;

public class Ex05 {
	public static void main(String[] args) {
		Test5<Integer> ob = new Test5<>();
		ob.set(30);
		
		// Test5<Number> ob2 = ob; // 컴파일 오류. 상속관계가 아님.
		// 제네릭은 같은 데이터 타입만 가능. 훨씬 안정적이다.
		
		// 제네릭 - 와일드 카드
		// ? : 모든 클래스나 인터페이스가 가능
		// 제네릭 타입에 의존적이지 않는 메소드등을 호출
		Test5<?> ob2 = ob;
		ob2.print();
		
		// ob2.set(new Integer(30) ); // 컴파일 오류. 자료형이 결정되지 않은 상태이므로
	}
}

class Test5<T> {
	private T t;
	
	public void set(T t) {
		this.t=t;
	}
	
	public T get() {
		return t;
	}
	
	public void print() {
		System.out.println(t);
	}
}

제네릭에 다형성을 갖도록 만들기 위해 와일드 카드를 사용한다.

제네릭 타입의 클래스를 파라미터로 사용할 때 구체적인 타입이 정해지지 않는 경우에 사용한다.

 

제네릭타입<?> 

  • 제한 없다.
  • 타입 파라미터를 대치하는 구체적인 타입으로 ?에는 모든 클래스나 인터페이스 타입이 올 수 있다.

Test5<?> ob2 = ob;
ob2.print(); // 제네릭 타입에 의존적이지 않은 메소드는 호출할 수 있지만 

ob2.set(); // 이것과 같은 제네릭 타입이 들어가는 메소드는 호출할 수 없다. 컴파일 오류,

'쌍용강북교육센터 > 7월' 카테고리의 다른 글

0729_Ex06~Ex09_system : Java API  (0) 2021.07.29
0729_ConsoleEx_콘솔 입력  (0) 2021.07.29
0728_Ex11~Ex17_generic : 제네릭  (0) 2021.07.29
0728_Ex01~Ex03_exception : 예외처리  (0) 2021.07.29
0727_패키지  (0) 2021.07.27
package ex0728;

// import java.util.Arrays;

public class Ex11_generic {
	public static void main(String[] args) {
		Object[] obj = new Object[5];

		// Object는 모든 클래스 객체를 참조할 수 있다. (up casting)
		obj[0] = new String("서울");
		obj[1] = new String("부산");
		obj[2] = new Integer(30);
		obj[3] = new Integer(50);
		obj[4] = new String("인천");

		// Arrays.sort(obj); // ClassCastException 런타임 오류

		// String s = (String)obj[2]; // ClassCastException 런타임 오류
		if (obj[1] instanceof String) { // obj[2] 너 String 형이니?
			String s = (String) obj[1]; // 스트링 형이면 다운캐스팅하고
			System.out.println(s + ":" + s.length()); // 출력하고 : 길이도 출력해
		}

		for (Object o : obj) {
			System.out.println(o);
		}

	}
}

Object는 모든 클래스들의 조상이므로 (시조라고 해야하나 ㅋㅋ)

자식들은 Object클래스로 up casting이 가능하다. 지금 이 코드는 숫자나 문자열 모두 그냥 Object에 넣었다.

이럴 경우 데이터타입에 관계없이 모든 것을 넣을 수 있다.

하지만 자료형이 다 제각각이므로 Arrays.sort(obj); 과 같은 메소드를 사용하면 런타임 오류가 발생한다. 

 

Integer 30을 강제로 캐스팅 하면 ClassCastException 이라는 런타임 오류가 발생한다. 그래서 A instanceof B 를 써서 배열A에 들어가 있는 데이터타입이 B 이면 강제로 다운캐스팅(다운캐스팅은 업캐스팅한 것만 가능)하고 출력하라고 밑에서 if문을 쓴 것이다.


package ex0728;

public class Ex12_generic {
	public static void main(String[] args) {
		Test2 t1 = new Test2();
		// t1.set(new String("서울"));
		t1.set("서울");
		String s = (String)t1.get();
		System.out.println(s);
		
		// Integer i1 = (Integer) t1.get(); // ClassCastException 런타임 오류.
		
		Test2 t2 = new Test2();
		t2.set(30);
		Integer i2 = (Integer)t2.get();
		System.out.println(i2);
	}
}

class Test2 {
	private Object ob;
	
	public void set(Object ob) {
		this.ob = ob;
	}
	
	public Object get() {
		return ob;
	}
}

t1의 객체는 String형을 저장하고

t2의 객체는 Integer형을 저장했다.

그냥

System.out.println(t1.get());
System.out.println(t2.get());

이면 상관없지만

s, i2에 넣을 때는 s의 데이터타입인 String으로 다운캐스팅 i2의 데이터타입인 Integer로 다운캐스팅을 해야 한다.

 


본격적으로 Generic에 대해 알아보자.

 

다양한 타입의 객체를 다루는 클래스나 인터페이스에서 사용할 데이터 타입을 인스턴스를 생성할 때 결정하는 것으로 JDK 5.0부터 지원한다.

  • 성능 저하를 유발하는 강제 캐스팅을 줄일 수 있다.
  • 컴파일 할 때 타입 오류를 체크하므로 객체 타입의 안정성을 높인다.
  • 반복적인 코드를 줄일 수 있으며, 재사용성 증가로 유지보수가 편리하다.

 

package ex0728;

public class Ex13_generic {
	public static void main(String[] args) {
		Test3<String> t1 = new Test3<String>();
		t1.set("서울");
		// t1.set(50); // 컴파일 오류
		String s = t1.get();
		System.out.println(s);
		
		// Integer i1 = (Integer)t1.get(); // 컴파일 오류. 미연에 방지 할 수 있다!
		
		Test3<Integer> t2 = new Test3<>(); // new 뒤에 <>에서는 자료형 생략가능. new Test3<Integer> 에서 Integer생략
		t2.set(30);
		Integer n = t2.get();
		System.out.println(n);
		
/*		
		Test3 t3 = new Test3(); // 가능하지만 경고 발생. 제너릭은 Object로 처리.
		t3.set("서울");
		t3.set(50);
*/
		
		
	}
}

class Test3<T> { // <> 안에는 마음대로 이름을 줄 수 있다. 
	private T t; // T에 자료형은 String, Integer, Long ...등이 올 수 있음. 아직 정해지지 않았다.
	public void set(T t) {
		this.t = t;
	}
	
	public T get() {
		System.out.println(t.getClass()); // 무슨 클래스인지 볼 수 있다.
		return t;
	}
}

객체를 생성할때 <> 안에 어떤 데이터타입만 저장할 것인지 설정을 해서 생성할 수 있다.

Test3<String> t1 = new Test3<String>();

 

t1.set(50); 으로 주면 컴파일 오류가 생기기 때문에 안정적으로 코딩할 수 있다.

 

제네릭을 설정하지 않고 그냥 

Test3 t3 = new Test3(); 으로 객체를 생성하면 경고가 발생한다. 이때 제네릭은 Object로 처리되기 때문에 

t3.set("서울");

t3.set(50); 

모두 넣을 수 있다. 하지만 비추천.

 

제네릭을 만들 때 <> 안에 마음대로 이름을 줄 수 있으나 관습적으로 대문자 알파벳 한 문자를 사용하고

E : Element

K : Key

N : Number

T : Type

V : Value

S, U, V : 2nd, 3rd, 4th types..

으로 사용한다.

 

마지막에 확인해보면 t1의 클래스는 <String>으로 줬기 때문에 String으로 뜨고, t2는 Integer로 준 것을 확인 할 수 있다.


package ex0728;

public class Ex14_generic {
	public static void main(String[] args) {
		Test4<String, Integer> ob = new Test4<>();
		
		ob.set("자바", 100);
		ob.print();
		
		ob.set("스프링", 200);
		ob.print();
	}
}

class Test4<T, U> {
	private T t;
	private U u;
	
	public void set(T t, U u) {
		this.t = t;
		this.u = u;
	}
	
	public void print() {
		System.out.println("T : "+t.getClass().getName()+", "+t);
		System.out.println("U : "+u.getClass().getName()+", "+u);
	}
	
	
}

제네릭 클래스에 멀티 타입 파라미터를 준 경우이다. 만들때 <String, Integer>라고 했으니 T의 자료형은 String형이되고 U의 자료형은 Integer형이 된다.


package ex0728;

public class Ex15_generic {
	public static void main(String[] args) {
		Test5<Integer> ob = new Test5<>();
		ob.set(30);
		Integer i = ob.get();
		System.out.println(i);
		
		// Test5<String> ob2 = new Test5<>(); // 컴파일 오류 발생.
		// Number를 상속받은 class가 아니기 때문이다.
		
	}
}

// 제한된(한정된) 타입 파라미터(bounded type parameter)
// Number를 상속받은 클래스만 가능 (Integer, Long, Double ...)
class Test5<T extends Number> {
	private T t;
	public void set(T t) {
		this.t=t;
	}
	
	public T get() {
		return t;
	}
}

제한된 타입 파라미터만을 받도록 설정한 제네릭 클래스.

T extends Number를 통해 Number를 상속받았기 때문에 그 클래스에 포함되는 것들만 파라미터로 받을 수 있다.

package ex0728;

public class Ex16_genericMethod {
	public static void main(String[] args) {
		Test6 t = new Test6();
		
		t.print("자바");
		t.print(20);
		
		t.disp(30);
		// t.disp("자바"); // 컴파일 오류
	}
}

// generic Method 
class Test6 {
	public <U> void print(U u) {
		System.out.println(u.getClass().getName() + ", " + u);
	}

	public <U extends Number> void disp(U u) {
		System.out.println(u.getClass().getName() + ", " + u);
	}
}

제네릭 메소드 타입 파라미터를 하나 이상 갖는 메소드를 말한다.

선언 방법은 리턴 타입 앞에 <> 기호를 추가하고 <> 기호 안에 타입 파라미터를 기술 한 후 리턴 타입과 매개 변수타입에서 타입 파라미터를 사용한다.

disp(U u) 메소드의 경우 받는 자료형을 Number를 상속받은 것들만 가능하게 설정했으므로 

t.disp("자바"); 의 경우 컴파일 오류이다.

package ex0728;

public class Ex17_generic {
	public static void main(String[] args) {
		TestImpl7<Integer> ob1 = new TestImpl7<>();
		ob1.print(10);
		
		DemoImpl7 ob2 = new DemoImpl7();
		ob2.print("자바");
		
	}
}

// 제네릭 인터페이스
interface Test7<T> {
	public void print(T t);
}

// 구현 클래스-1
class TestImpl7<T> implements Test7<T> {
	@Override
	public void print(T t) {
		System.out.println(t);
		
	}
	
}

// 구현 클래스-2
class DemoImpl7 implements Test7<String> {
	@Override
	public void print(String t) {
		System.out.println(t);
	}
	
}​

제네릭 인터페이스를 구현할 때 위의 2가지 방법으로 구현할 수 있다.

1의 경우 자료형을 객체를 생성할 때 결정한 방법이고

2의 경우 구현 클래스에서 자료형을 결정한 방법이다.

 

'쌍용강북교육센터 > 7월' 카테고리의 다른 글

0729_ConsoleEx_콘솔 입력  (0) 2021.07.29
0729_Ex01~Ex05_Generic  (0) 2021.07.29
0728_Ex01~Ex03_exception : 예외처리  (0) 2021.07.29
0727_패키지  (0) 2021.07.27
0727_Ex06~Ex08_enum : 열거형  (0) 2021.07.27
package ex0728;

public class Ex01_exception {
	public static void main(String[] args) {
		User1 ob = new User1();
		
		try {
			ob.set("김자바", -5);
			// ob.set(null, 10);
			System.out.println(ob.getName() + ":" + ob.getAge());
		} catch (Exception e) {
			System.out.println(e.toString());
		}

		
	}
}

class User1 {
	private String name;
	private int age;

	public void set(String name, int age) throws Exception{
		try {
			setName(name);
			setAge(age);
		} catch (Exception e) {
			// System.out.println(e.toString());
			// throw new Exception("값을 설정하지 못했습니다."); // 새로운 예외를 발생
			
			throw e; // 예외를 다시 던짐
		}
		
	}

	public String getName() {
		return name;
	}

	public void setName(String name) throws Exception {
		if(name == null)
			throw new Exception("이름은 null이 될 수 없습니다.");
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) throws Exception {

		if (age < 0)
			throw new Exception("나이는 0이상입니다.");

		this.age = age;
	}

}

package ex0728;

import java.util.Scanner;

public class Ex02_exception {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		User2 ob = new User2();

		try {
			System.out.print("이름 ? ");
			ob.setName(sc.next());
			System.out.print("나이 ? ");
			ob.setAge(sc.nextInt());
			
			System.out.println(ob.getName()+"+"+ob.getAge());
		} catch (Exception e) {
			System.out.println("입력 오류 입니다.");
		} finally { // finally 에서 자원을 닫아주어야 한다.
			sc.close();
		}
		System.out.println("end...");
	}
}

class User2 {
	private String name;
	private int age;

	public String getName() {
		return name;
	}

	public void setName(String name) throws Exception {
		if(name.length()<2)
			throw new Exception("이름은 두자 이상입니다.");
		
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) throws Exception {

		if (age < 0)
			throw new Exception("나이는 0이상만 가능 합니다.");

		this.age = age;
	}

}

 

여기서는 예외가 발생하면 "입력 오류 입니다."를 출력한다. 

예외가 발생했을 때 만들었던 예외를 출력하려면

System.out.println(e.toString()); 이거를 추가해야지 왜 예외가 발생했는지 알려줌.

package ex0728;

import java.util.InputMismatchException;
import java.util.Scanner;

public class Ex03_exception {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		User3 ob = new User3();

		try {
			System.out.print("이름 ? ");
			ob.setName(sc.next());
			System.out.print("나이 ? ");
			ob.setAge(sc.nextInt());
			
			System.out.println(ob.getName()+"+"+ob.getAge());
		} catch (InputMismatchException e) {
			System.out.println("숫자만 입력 가능합니다...");
		} catch (NameValidException e) {
			System.out.println("이름은 두자 이상이어야 합니다...");
		} catch (AgeValidException e2) {
			System.out.println("나이는 0이상 입니다...");
		} catch (Exception e) {
			e.printStackTrace();
		} finally { // finally 에서 자원을 닫아주어야 한다.
			sc.close();
		}
		System.out.println("end...");
	}
}

// 사용자 정의 예외 클래스(checked exception)
class NameValidException extends Exception {
	private static final long serialVersionUID = 1L; // 직렬화

	public NameValidException(String msg) {
		super(msg);
	}
}

class AgeValidException extends Exception {
	private static final long serialVersionUID = 1L;

	public AgeValidException(String msg) {
		super(msg);
	}
}

class User3 {
	private String name;
	private int age;

	public String getName() {
		return name;
	}

	public void setName(String name) throws NameValidException {
		if(name.length()<2)
			throw new NameValidException("이름은 두자 이상입니다.");
		
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) throws AgeValidException {

		if (age < 0)
			throw new AgeValidException("나이는 0이상만 가능 합니다.");

		this.age = age;
	}

}

checked exception은 exception의 자식 클래스 이므로 사용자 정의 예외 클래스를 만드려면 Exception을 상속받아서 만들어야 한다. 직렬화의 경우 아직 배우지 않았으나 사용자 정의 예외 클래스를 만들 때는 옆에 느낌표를 눌러서 해결해줘야한다. 

굳이 catch 블록에

System.out.println("이름은 두자 이상이어야 합니다..."); 를 쓰지 않고

System.out.println(e.toString()); 를 넣어서 해도 될 것 같다.

throws
 : 메소드 시그니처(선언부분)에 선언
 : 메소드를 호출하는 곳에서 예외처리를 하도록 설정
 
throw
 : 예외를 강제로 발생 시킴

'쌍용강북교육센터 > 7월' 카테고리의 다른 글

0729_Ex01~Ex05_Generic  (0) 2021.07.29
0728_Ex11~Ex17_generic : 제네릭  (0) 2021.07.29
0727_패키지  (0) 2021.07.27
0727_Ex06~Ex08_enum : 열거형  (0) 2021.07.27
0727_Ex05_중첩 인터페이스  (0) 2021.07.27

==========================패키지
커맨드창에
-- 자바 컴파일(모든 자바 파일 컴파일. 자동으로 패키지를 폴더로 생성)
javac -d  .    *.java
하면
패키지에 써져있는 순서대로 폴더가 생기고 그 안에 컴파일된 class파일이 생김.

-- 자바 class 파일 압축 => jar
jar  cvf  my.jar  com
새로운 아카이브 파일을 만들겠다.c 압축하면서 화면상에 보여줘 v. 압축화일 이름설정f.

-- 클래스가 존재하는 파일을 설정하여 컴파일 및 실행
javac -classpath  my.jar  UserApp.java 

java -classpath   .;my.jar   UserApp

// 이클립스에서는 클릭만하면 되는데 cmd에서는 어떻게 이루어지는지 확인함!

+ Recent posts