JAVA API
: application programming interface
- 미리 만들어진 기능인 라이브러리
- API안에 많은 패키지들이 존재 (lang, util, IO 등)
메서드 모형 읽는 법
접근제어자 + (매개변수) + ;(결과) 반환 유형 - 클래스가 선언된 위치
접근제어자 구분
public private default protected
java.util 패키지
- 자바 프로그램 개발에 보조 역할을 하는 클래스들을 담은 패키지
- 컬렉션 관련 클래스들
★ Data 분류 ★
Generic
기본형을 사용할 수 없음
Templete Programming(일반화 프로그래밍)
- 동일한 알고리즘을 사용하는 메서드나 자료구조의 구현 때문에 등장
- 작업은 함수나 메서드가 수행하게 되는데 함수나 메서드는 매개변수에 자료형을 지정해야함
알고리즘은 같은데 사용하는 데이터의 자료형이 달라서 별도의 메서드나 함수를 구현하는 번거로움이 발생
Generics
- 자바에서 템플릿 프로그래밍을 구현하기 위한 문법
- 컴파일 시 타입을 체크해주는 기능
- 클래스 이름 뒤에 <>을 추가하고 미지정 자료형 이름을 나열
- 형 안정성을 위해 사용
- 타입 체크와 형변환을 생략할 수 있으므로 코드가 간결해짐
- 클래스 내부에서 미지정 자료형을 사용해서 메서드를 구현
- 인스턴스를 생성할 때 실제 자료형을 기재해서 생성
실제 자료형을 기재하지 않으면 Object 타입으로 간주
변수에 실제 데이터타입을 기재하면 생성자를 호출할때는 기재하지 않고 <>만 설정해도 됨
실습
package _api.util.arrays;
//어떤 종류의 데이터든지 생성자에서 개수에 상관없이 받아서 처리하는 제네릭스
class Generics <T> { //미지정 자료형 대부분 한글자를 대문자로 씀
private T [] data;
//...은 varialbe args로 개수에 상관없이 매개변수를 받고자 할 때 사용
//받은 매개변수들은 배열로 만들어짐
public Generics(T ... n) {
this.data = n;
}
//배열의 데이터를 순차적으로 접근해서 출력하는 메서드
public void display() {
for(T temp : data) {
System.out.println(temp);
}
}
}
public class TempleteProgramming02 {
public static void main(String[] args) {
//제네릭이 적용된 클래스의 인스턴스 만들기 - 자료형 결정 필수!!!
Generics <String> g1 = new Generics<String>("Karina", "Suzi", "IU");
g1.display();
Generics <Integer> g2 = new Generics<>(100, 200, 300, 400);
g2.display();
}
}
//1. 제네릭 클래스 Box<T> 선언
class Box<T> {
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();}
}
//2. 참조변수와 생성자에 대입된 타입이 일치해야 함
Box<Apple> appleBox = new Box<Apple>();
Box<Apple> appleBox = new Box<Grape>(); //에러, 대입된 타입이 다름
Box<Fruit> appleBox = new Box<Apple>(); //에러, 대입된 타입이 다름
//3. 상속관계이고, 대입된 타입이 일치하는 것은 OK
Box<Apple> appleBox = new FruitBox<Apple>(); //다형성
Box<Apple> appleBox = new Box<>(); //가능- JDK1.7부터 생략 가능
//4. 대입된 타입과 다른 타입의 객체는 추가할 수 없음
Box<Apple> appleBox = new Box<Apple>();
appleBox.add(new Apple());
appleBox.add(new Grape()); //에러, Box<Apple>에는 Apple객체만 추가 가능
용도
- 자료구조 클래스를 만들 때 모든 자료형의 데이터를 저장할 수 있도록 하기 위해서 사용
- 특정 자료형의 데이터만 대입받기 위한 용도로도 사용. 이경우는 대부분 템플릿에 인터페이스를 설정
- 처음 공부를 할때는 제네릭이 적용된 클래스의 인스턴스를 만드는 방법을 먼저 학습을 하고 제네릭을 적용하는 클래스를 만들어가는 형태로 하는 것이 좋음
제약 사항
- static 멤버에는 타입 변수 T 사용 불가
- 제네릭 타입의 배열 T[]를 생성하는 것은 허용되지 않음
class Box<T> {
static T item; //에러
static int compare(T t1, T t2) { ... }; //에러
}
class Box<T> {
T[] itemArr; //OK, T타입의 배열을 위한 참조변수
...
T[] toArray() {
T[] tmpArr = new T[itemArr.length]; //에러, 제네릭 배열 생성 불가
return tmpArr;
}
}
- 메소드를 static으로 선언해도 제네릭 사용 불가
static이면 Box가 인스턴스화 되기 전에 메모리에 올라가는데 이 때 타입 T가 결정되지 않았기 때문에 사용 할 수 없음
그러나 지역적으로 제네릭 타입을 사용하고 싶다면 제네릭 메소드 사용 가능
출처: https://devlog-wjdrbs96.tistory.com/338
제한된 제네릭 클래스
- extends를 사용하면 특정 타입의 자손들만 대입 가능
- add()의 매개변수의 타입 T도 Fruit와 그 자손타입이 될 수 있음
- 인터페이스의 경우 - extends 사용
//1. 특정 타입의 자손들만 대입
class FruitBox<T extends Fruit> { //Fruits의 자손만 타입으로 지정 가능
ArrayList<T> list = new ArrayList<T>();
void add(T item) { list.add(item); }
...
}
//2. add()의 매개변수 타입
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
fruitBox.add(new Apple()); //Apple이 Fruit의 자손
fruitBox.add(new Grape()); //Grape이 Fruit의 자손
//3. 인터페이스의 경우 extends
interface Eatable {}
class FruitBox<T extends Eatable> {...}
class FruitBox<T extends Fruit & Eatable> {...}
와일드 카드 - ?
- 와일드 카드를 쓰면 여러 타입을 대입 가능
- 단, & 사용 불가
< ? extends T > 상한 제한, T와 그 자손들만 가능
< ? super T> 하한 제한, T와 그 조상들만 가능
< ? > 제한 없음, 모든 타입 가능
제네릭 메서드
- 반환 타입 앞에 제네릭 타입이 선언된 메서드
- 클래스의 타입 매개변수<T>와 메서드의 타입 매개변수 <T>는 별개
- 제네릭 메서드를 호출할 때, 타입 변수에 타입을 대입해야 함 (대부분 추정이 가능하므로 생략)
class FruitBoc<T> {
...
static <T> void sort(List<T> list, Comparator(? super T) c) {
...
}
}
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();
...
System.out.println(Juicer.<Fruit>makeJuice(fruitBox));
System.out.println(Juicer.makeJuice(appleBox)); //대입된 타입 생략 가능
형변환
- 제네릭 타입과 원시 타입간의 형변환 불가
- 와잍드 카드가 사용된 제네릭 타입으로는 형변환 가능
- <? extends Object> == <?>
Collection Framework 들어가기 전
List 구조
데이터를 입력한 순서대로 연속해서 저장하는 자료구조
List(배열)
- 크기가 고정인 List
- 한 번 만들면 크기를 변경할 수 없음
- 저장된 데이터를 변경하는 것은 가능하지만 데이터를 추가하거나 삭제하는 것은 안 됨
데이터를 추가하거나 삭제 하고자 하는 경우 배열을 복사해서 작업을 수행해야 함 - 불필요한 공간이 없기 때문에 메모리 효율을 높음
- 데이터의 크기 변경이 없을 가능이 높을 때 사용
package _api.util.arrays;
import java.util.Arrays;
public class CollectionTest1 { // 추가 & 삭제, 중간부분 삭제 해보자!
public static void main(String[] args) {
String[] arr = {"List", "Set", "Map"};
//배열의 데이터를 수정하는 것은 가능
arr[2] = "HashTable";
System.out.println(Arrays.toString(arr));
//arr 배열에 데이터를 추가
//arr 배열보다 1개 더 큰 공간을 갖는 배열을 생성
String[] arr2 = new String[arr.length + 1];
//arr의 내용을 복사
for(int i = 0; i < arr.length; i++) {
arr2[i] = arr[i];
}
//arr2의 마지막에 데이터 추가
arr2[arr2.length - 1] = "Properties";
//arr2가 가리키는 곳을 arr이 가리키도록 함
arr = arr2;
System.out.println(Arrays.toString(arr));
}
}
java.util.List 인터페이스
boolean add(E e)
void add(int index, E element)
void set(int index, E element)
E get(int index)
E remove(int index 또는 E element)
void sort(Comparator comparator)
- List 인터페이스는 제너릭이 구현되어 있어서 인스턴스를 생성할 때 저장하고자 하는 데이터의 자료형을 설정해야 함
java.util.ArrayList
예전에는 Vector 라는 클래스를 이용했음
- List인터페이스를 구현한 클래스로 데이터를 연속해서 순서대로 저장하는 자료구조 클래스
- 배열과 달리 크기가 가변이라서 데이터를 추가하거나 삭제하는 것이 가능
- 장점: 데이터만 저장하기 때문에 LinkedList보다는 메모리 효율이 좋을 수 있음
전체 데이터를 순회하는 속도가 LinkedList보다는 빠름
- 단점: 중간에 데이터를 삽입하거나 삭제할 때 데이터의 복사 작업이 필요하기 때문에 속도가 느림
연속된 빈 공간이 없으면 생성이 불가능
java.util.LinkedList
예전에는 Vector 라는 클래스를 이용했음
- List인터페이스를 구현한 클래스로 데이터를 논리적인 순서(실제 연속해서 저장되는 것이 아니고 앞의 데이터가 뒤의 데이터를 가리키는 구조)대로 연속해서 순서대로 저장하는 자료구조 클래스
- 링크가 1개이면 Single Linked List 라고 하고, 2개(앞과 뒤 모두를 가리키거나 트리 구조에서는 부모나 앞의 형제를 가리키고 다른 하나는 자식이나 형제를 가리킴)이면 Double Linked List라고 함
- 장점: 중간에 데이터를 삽입하거나 삭제할 때 데이터의 이동없이 포인터만 이동하기 때문에 빠르게 작업이 가능
포인터를 이용해서 다음 데이터를 가리키는 구조이므로 연속된 빈 공간이 없어도 생성이 가능
- 단점: 데이터 이외에 포인터도 저장해야 하므로 메모리 효율이 ArrayList 에 비해서 떨어질 수 있음
포인터를 따라다니므로 조회 속도가 느림
- 조회를 주로 하는 작업에서는(게시판) ArrayList를 이용하고 삽입과 삭제가 많은 게임 같은 분야에서는 Linked List를 많이 사용함
실습
CollectionTest2
public class CollectionTest2 {
public static void main(String[] args) {
//문자열을 저장하는 ArrayList 생성
ArrayList <String> al = new ArrayList<>();
//샘플 데이터 추가
al.add("One");
al.add("Three");
//1970년 1월 1일 자정부터 지나온 시간을 밀리초 단위의 정수로 가져오기
long start = System.currentTimeMillis();
//두번째에 데이터를 100000 개 추가
for(int i=0; i<1000000; i++) {
al.add(1, "Two");
}
//1970년 1월 1일 자정부터 지나온 시간을 밀리초 단위의 정수로 가져오기
long end = System.currentTimeMillis();
//걸린 시간 확인
System.out.println(end - start);
---------------------------------------------------------
//문자열을 저장하는 ArrayList 생성
LinkedList <String> li = new LinkedList<>();
//샘플 데이터 추가
li.add("One");
li.add("Three");
start = System.currentTimeMillis();
for(int i=0; i<1000000; i++) {
li.add(1, "Two");
}
end = System.currentTimeMillis();
System.out.println(end - start);
}
}
CollectionTest3 - 조회 작업
public class CollectionTest3 {
public static void main(String[] args) {
//100000 개의 데이터를 가진 ArrayList 와 LinkedList 생성
ArrayList<Integer> al = new ArrayList<>();
for(int i=0; i<100000; i++) {
al.add(i);
}
LinkedList<Integer> li = new LinkedList<>();
for(int i=0; i<100000; i++) {
li.add(i);
}
//ArrayList에서 100000 개의 데이터를 읽는데 걸리는 시간
//데이터를 가져오는 메서드는 get(인덱스)
//실행해서 가장 마지막에 나오는 숫자를 확인을 한 후 al을 li로 변경해서 실행하고 숫자는 확인
long start = System.currentTimeMillis();
for(int i=0; i<100000; i++) {
System.out.println(al.get(i));
}
long end = System.currentTimeMillis();
System.out.println(end-start);
System.out.println(al);
}
}
오늘 하루
기억에 남는 부분
-
-
어려운 부분
-
-
문제 해결 부분
-
-
'프로그래밍 언어 > Java' 카테고리의 다른 글
[Java] API_ java.io (file, stream, buffer) / Input & Output (0) | 2022.10.27 |
---|---|
[Java] API_ Collection Framework (List, Set, Map) (0) | 2022.10.26 |
[Java] API_ java.util (Arrays 클래스 - search, date, calendar, random) (0) | 2022.10.25 |
[Java] API_ java.lang (문자열, Math 등) (0) | 2022.10.18 |
[Java] 예외 처리 (try ~ catch ~ finally), throws & throw (0) | 2022.10.17 |