좋은 코드를 쓰자!
코드를 볼 때는 어떤 문법을 쓰는가가 중요한게 아닌
얼마나 빠른가? 메모리는 얼마나 쓰였는가? 가독성이 좋은가?
항상 생각을 하자! 내 코드가 어떤 부분이 좋은지 어필 할 수 있어야 한다.
가장 편하고 쉽고 심플한 것부터 시작하고 얘기 할 수 있어야 한다. 선택에는 이유가 있어야한다.
수업을 하는 이유는 쓰든 안쓰든 쓸 수 있는 준비를 해야한다.
그 중에서 어떤게 더 생산성을 높일 수 있을까? 미래지향적일까? 효율적일까?
그래서 왜 내가 이걸 썻는지에 대한 어필을 할 수 있어야 한다.
수업중에 배우는 것들을 어따 써먹을까?를 생각해야한다.
추상클래스
// 추상클래스 - 추상메서드를 0개 이상 갖는 클래스
abstract class Lec06{
int su1 = 1111;
public abstract void func01(); // 추상메서드
// private abstract void func01(); 오류! 논리적으로 모순이다.
public void func02() {}
// 매개변수 생성자를 생성하는 경우
// 디폴트 생성자가 생성되지않기 때문에
// 상속 관계에 있는 클래스들이 오류가 발생된다.
public Lec06(int su1) {
this.su1 = su1;
};
}
public class Ex06 extends Lec06 {
// 추상클래스에 있는 생성자에 맞춰야한다.
public Ex06() {
super(1234);
}
public Ex06(int su1) {
super(su1);
}
// 추상메서드 구현 필수
@Override
public void func01() {
System.out.println("부모의 기능을 오버라이드...");
}
public static void main(String[] args) {
// Lec06 me = new Lec06(); 오류! 객체 생성 불가! 추상메서드가 없어도 객체는 생성 불가능!
// 추상클래스사용하려면 상속을 받아야한다 -> 목적은 상속의 강제화.
// 추상클래스를 사용하려면 내 스스로 추상클래스가 되든
// 추상클래스의 추상메서드를 오버라이딩해서 구현해야한다.
// 사용은 자식메서드로 생성해서 하든
Ex06 me = new Ex06();
me.func01();
// 부모클래스로 받아와서 해야한다.
Lec06 you = new Ex06();
you.func01();
}
}
객체의 다형성
관계형 데이터베이스를 쓸 때 해당 DB의 드라이버를 바꾸기면하면 같은 명령어를 이용해서 다른 DB를 쓸 수 있는 것
내부적으로는 완전히 다르게 돌아갈지 몰라도 같은 형태로 사용할 수 있게 통일해둔 것을 다형성을 사용한 것.
어떤 객체를 집어넣느냐에 따라 결과값이 달라진다. 즉, 새로운 객체를 추가하기 용이하다.
상속에서 다형성을 제공하기 위해 강제성을 부여하기 위한 것이 추상클래스.
그렇기 때문에 작은 제품관련에서는 추상 메서드를 거의 쓰지않는다. 그냥 문법적으로 있더라 정도만 익혀두면 된다.
// 부모의 타입으로 다양한 자식들의 객체를 받아 들일 수 있다.
// 객체의 다형성
abstract class Machine {
void on() {
System.out.println("켜다");
}
void off() {
System.out.println("끄다");
}
abstract void work(); // 추상메서드 work를 구현하지않으면 오류가 난다.
}
class Tv extends Machine {
@Override
void work() {
System.out.println("방송 주파수를 잡아 화면과 소리를 출력해");
}
}
class Radio extends Machine {
@Override
void work() {
System.out.println("주파수를 잡아 소리를 출력해");
}
}
class Audio extends Machine {
@Override
void work() {
System.out.println("소리만 출력");
}
}
public class Ex07 {
public static void main(String[] args) {
java.util.Scanner sc;
sc = new java.util.Scanner(System.in);
System.out.println("1.tv 2.radio 3.audio>");
int input = sc.nextInt();
Machine remote;
// 어떤 객체를 집어 넣어주느냐에 따라 실행결과가 달라진다.
if (input == 1) {
remote = new Tv();
} else if (input == 2) {
remote = new Radio();
} else {
remote = new Audio();
}
remote.on();
remote.work();
remote.off();
}
}
인터페이스
활용에 대한 결정이 없다. 무궁무진하다. 물론 만들어진 목적은 다중상속의 효과를 얻기 위해서
어디까지나 효과일 뿐. 완벽한 다중상속과는 차이가 있지만, 활용하기에 너무 좋다.
어떤 목적으로 쓴다라고 규정 짓는 것 자체가 어렵다.
대표적인 사용
규정 -> 인터페이스를 구현하도록 강제화, 명령어의 통일화
클래스의 성질 -> String 클래스에서 매개변수로 받는 CharSequance 인터페이스
문자열과 관련된 애들은 CharSequance를 상속받아 구현하였기 때문에 CharSequance하나로 정리되는 것
특정화 -> Serializable, Clonable -> 같은 인터페이스에는 아무런 내용이 없다.
단지 얘가 붙어있냐 안붙어있냐가 중요한 것. 직렬화가능한가? 클론가능한가? 특정화하기 위한 인터페이스
abstract와 다르게 모든 메서드를 다 구현해야한다.
// interface - 추상메서드만으로 되어있는 것
// interface라도 컴파일 했을 때 나오는 결과물은 .class다
interface Lec08 {
public abstract void func01(); // 오직 추상메서드만 가질 수 있다.
void func03(); // public abstract는 생략 가능하다. 무조건이기 때문
// public void fun03() {} 오류! 구현된 메서드는 가질 수 없다!
// public Lec08(); 오류! 생성자도 가질 수 없다!
public static final int su = 11; // 상수는 가질 수 있다.
int su2 =22; // public static final은 생략 가능하다. 무조건이기 때문
}
// 인터페이스 끼리의 상속
interface Lec088 extends Lec08{
public abstract void func02();
}
// 인터페이스 끼리는 다중 상속이 가능하다.
interface Lec0888 extends Lec08, Lec088{
public abstract void func04();
}
// 클래스 다중상속은 불가능하나 인터페이스는 얼마든지 구현 가능하다.
public class Ex08 extends Object implements Lec08, Lec088 {
@Override
public void func01() {
}
@Override
public void func02() {
}
@Override
public void func03() {
}
public static void main(String[] args) {
Lec08 me = new Ex08();
System.out.println(Lec08.su);
// Lec08.su2++; // final 이기때문에 변화불가 생략되어있을 뿐
me.func01();
}
}
퍼블릭한 코드를 짜야한다! 좋은 습관 좋은 패턴으로 코딩을 해야한다.
사고의 자유가 중요한 것이지 수업에서 하는 코드들은 가장 퍼블릭한 패턴이기 때문에 불편함을 감수하고 따라 가야한다.
당분간은 자신의 스타일을 버리고 이런 저런 패턴들을 몸에 익히고 바뀌어야한다는 것이 핵심.
리팩토링 하기 좋게 하는 스타일로 수업에서 코딩을 진행하기 때문에
나름의 스타일대로하는 것도 좋지만 최대한 100% 따라가보는게 학습의 효율성이 생길 것이다.
내일 아침 10시까지 출석부 사진 촬영 -> 동그라미 잘치기
출석 관련 카톡으로 메시지 남길 것
접근제한자 - protected
package com.bit;
class Lec02{
//public > protected >= default > private
// default 처럼 작동하되 상속은 허용한다.
protected int su1;
protected void func01() {
}
}
public class Ex02 extends com.bit2.Lec22{
// 접근제한자
public static void main(String[] args) {
Lec02 me = new Lec02();
System.out.println(me.su1);
me.func01();
// com.bit2.Lec22 you = new com.bit2.Lec22();
// System.out.println(you.su2); 오류! 접근을 허용하지않음
// you.func02();
Ex02 me2 = new Ex02();
System.out.println(me2.su2);
me2.func02();
// me2.func03(); default는 상속도 허용하지않음
}
}
package com.bit2;
public class Lec22 {
// 생성자에서 protected 로 지정하는 순간 class 에 붙는 접근제한자가 의미가 없기 때문에 생략 가능
protected Lec22() {}
protected int su2 = 1111;
protected void func02() {
System.out.println("protected func02");
}
void func03() {}
}
final
package com.bit;
// 클래스에 final 달 경우 상속 불가능
final class Lec03{
final static int su2 = 2222;
final int su3 = 3333;
public static void func01(final int su) {
}
// 메서드에 final 달 경우 override 불가능
public final void func02() {}
}
public class Ex03 {/*extends Lec03 오류! The type Ex03 cannot subclass the final class Lec03*/
// public void func02() {} 오류! Cannot override the final method from Lec03
// final - 상수형 변수
public static void main(String[] args) {
final int su1 = 1111;
Lec03.func01(su1);
}
}
자바에서 기본적으로 제공하는 클래스들
Object 클래스
hashcode() - 레퍼런스끼리의 비교 방식 중 하나 hashcode가 같다는 것은 같은 객체를 의미한다.
해시함수
암호화를 하기 위해 보안으로써 사용하는 해시함수.
동일한 파일을 집어 넣었을 때 같은 아웃풋이 나오는지 확인하기 위한 즉 같은 파일인지 확인하기 위해 짧은 해시함수.
결과값을 가져다가 역으로 디컴파일하기 위한 해시함
toString() - @를 기준으로 클래스에 대한 정보 출력
getClass().getName() + '@' + Integer.toHexString(hashCode())
clone() - 객체 복사
// clone을 사용하기 위해선 Cloneable 인터페이스를 구현해야함
// 그래야 클론 가능한 클래스로 구분이 되어서 clone()을 사용 할 수 있게됨
public class Ex04 implements Cloneable{
public static void main(String[] args) throws CloneNotSupportedException {
Object obj = new Object();
// 해시 코드 - 객체가 서로 같은지 해시코드로 비교해 볼 수 있다. equals()의 원리
System.out.println(obj.hashCode());
// 클론
// Object obj2 = obj.clone(); 오류 invisible
Ex04 me = new Ex04();
Object you = me;
Ex04 you2 = (Ex04)you;
System.out.println(me == you); // false
Ex04 you3 = (Ex04) me.clone();
System.out.println(me == you3); // false
int[] arr = {1,3,5,7,9};
int[] arr2 = arr.clone(); // clone하여 깊은 복사
System.out.println(arr==arr2); // false 리턴 => 서로 다른 객체임
for(int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]); // 깊은 복사된 것 확인
}
}
}
System 클래스
arraycopy() - 배열복사
currentTimeMillis() - 밀리초 리턴 (1970년기준으로 흘러간 시간)
long before = System.currentTimeMillis();
String msg = "";
for(int i = 0; i < 10000; i++) {
msg += i;
}
long after = System.currentTimeMillis();
System.out.println(after - before);
Math 클래스
생성자가 없다(사실 없을 순 없기 때문에 private 시켜둠)
객체를 생성 할 수 없기 때문에 모든 메서드는 static 메서드
// Math 클래스
int su1 = 2;
int su2 = 5;
int su3 = -34;
// 절대값
System.out.println(Math.abs(su2));
System.out.println(Math.abs(su3));
double su4 = 3.14;
double su5 = 3.54;
double su6 = 3.94;
// 소숫점올림
System.out.println(Math.ceil(su4));
System.out.println(Math.ceil(su5));
System.out.println(Math.ceil(su6));
System.out.println("---");
// 소숫점내림
System.out.println(Math.floor(su4));
System.out.println(Math.floor(su5));
System.out.println(Math.floor(su6));
System.out.println("---");
// 소숫점반올림
System.out.println(Math.round(su4));
System.out.println(Math.round(su5));
System.out.println(Math.round(su6));
// 두 수의 최솟값 최댓값
System.out.println(Math.min(su1, su2));
System.out.println(Math.max(su1, su2));
// 랜덤 - 0.0 <= x < 1.0의 값 return
System.out.println(Math.random());
Class 클래스
void func() {
System.out.println("func run...");
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
// Class 클래스
// 클래스에 대한 정보를 담고 있는 클래스
Object obj = new Object();
Class cls1 = obj.getClass();
Class cls2 = Object.class;
Ex07 me = new Ex07();
Class cls3 = me.getClass();
Class cls4 = Ex07.class;
Class cls5 = Class.forName("com.bit.Ex07"); // 입력 잘못될 경우 ClassNotFoundException 발생
Ex07 obj2 = (Ex07)cls5.newInstance(); // 객체가 생성됨
System.out.println(obj2);
obj2.func();
Wrapper 클래스
func(10);
기본 자료형이 Object 매개변수로 들어가게 할 수 있는 이유가
해당하는 Wrapper클래스로 자동으로 boxing 되어서 매개변수로 주어지게 됨
이처럼 Wrapper 클래스가 있기 때문 필요에 따라 알아서 boxing, unboxing 됨 오토캐스팅 처럼
func(new Integer(10)); // 실제 수행되는 형태
객체끼리 연산은 되지않기 떄문에 Wrapper클래스로 연산을 수행한다고한다면
불필요한 unboxing boxing이 이루어지기 때문에 비효율적
그렇기 때문에 꼭 필요한 때만 가져다 쓰는 것이 제일 효율적이다.
Integer 클래스
int su1 = 1111;
Integer su2 = new Integer(2222);
Integer su3 = 3333;
Integer su4 = new Integer("3333");
System.out.println(su3==su4); // 객체비교가 우선되어서 false
System.out.println(su3.equals(su4)); // 값 비교해야 true
System.out.println(su3.intValue()==su4.intValue()); // 언박싱해서 비교해서 true
System.out.println(Integer.BYTES);
System.out.println(Integer.SIZE);
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
System.out.println(Integer.parseInt("1234") + 1); // 문자열 숫자변환 사용성 높다.
int su0 = 3;
System.out.println(Integer.reverse(su0)); // 바이너리값을 뒤집는다. 1101 -> 0010
int convertNum = 255;
System.out.println(Integer.toBinaryString(convertNum)); // 2진수
System.out.println(Integer.toOctalString(convertNum)); // 8진수
System.out.println(Integer.toHexString(convertNum)); // 16진수
System.out.println(Integer.compare(su2, su3)); // 차이 정도 리턴-> 같으면 0 작으면 -1 크면 1
System.out.println(su2.compareTo(2222)); // 위는 static으로 쓴 것 이거는 non-static
Double 클래스
double su1 = 3.14;
Double su2 = new Double(3.14);
Double su3 = new Double("3.14");
System.out.println(su2.intValue()); // 소숫점 날라감
System.out.println(Double.parseDouble("3.14"));
System.out.println(Double.toHexString(3.14));
System.out.println(1.0 / 0.0); // Infinity
System.out.println(Double.isInfinite(1.0 / 0.0)); // true
System.out.println(Double.isNaN(0.0 / 0.0)); // true
로또번호 생성하면서 중복제거, 숫자 올림차순 정렬은 사실 별 역삼각형 그리기랑 같다!
원하는 결과값을 폭넓게 생각을 해서 for문을 구성할 생각을 하면 더욱 좋을 것 같다.
예외 Exception
try - catch 구문을 어디 범위까지를 둘러 싸는가에 따라서 퍼포먼스가 다르다!
어떻게 돌아갈지를 생각하고, 필요에 따라서 싸야한다.
RuntimeException - 실행했을 때 발생하는 오류들을 대표하는 Exception(ArithmeticException, ArrayOutOfBoundException, ...)
Error -> 메모리가 부족해서 프로그램을 종료시켜야되거나, 강제종료되거나 등 오류들에 대한 최후의 조치를 취하기 위함 그 때 통신을 종료시키고, 오류 메세지 보고하는 등
int[] arr1 = { -2, -1, 0, 1, 2 };
for (int i = 0; i < 6; i++) {
try {
System.out.println(3 / arr1[i]);
} catch (ArithmeticException e) {
System.out.println(e);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e);
} catch (Exception e) { // 상속관계에 따라 순서 구분이 반드시 필요하다.
System.out.println(e);
}
}
// 커스텀 Exception
class MyErr extends Exception {
MyErr(){
super("MyErr 에러 발생!");
}
}
public class Ex13 {
public static void main(String[] args) {
try {
func(4, 4);
} catch (ArithmeticException e) {
System.out.println("에러받아서 처리");
} catch (ClassNotFoundException e) {
System.out.println("던진 에러 받아서 처리");
} catch (MyErr e) {
e.printStackTrace();
}
}
// RuntimeException은 강제성을 부여할 수 없다 => 실행해야만 알 수 있기 때문
// 그 외의 예외는 강제성을 부여할 수 있다.
public static void func(int a, int b) throws ClassNotFoundException, MyErr{
if (a / b == 1) {
Class.forName("com.bit.Ex04"); // throws 를 하지 않으면 try-catch 해야함
// 직접 객체를 생성해서 에러를 던질 수 있다.
// ClassNotFoundException err = new ClassNotFoundException();
// throw err;
// 커스텀 객체 던지기
MyErr err = new MyErr();
throw err;
}
int su = a / b;
}
Wrapper 클래스
기본자료형을 필요에 따라 내부에서 객체화(박싱,언박싱)시켜서 돌아가는 용도기 때문에 사실 우리가 직접 사용하는 경우는 거의 없다.
Character
char ch1 = ' ';
Character ch2 = new Character('A');
Character ch3 = new Character((char)65);
System.out.println(Character.isLetter(ch1)); // 영어, 한글, 한자 등 문자 - true 숫자, 특문 - false
System.out.println(Character.isAlphabetic(ch1)); // letter보단 alphabetic 쓰기
System.out.println(Character.isDigit(ch1)); // 숫자
System.out.println(Character.isWhitespace(ch1)); // 띄워쓰기 공백
System.out.println(Character.toUpperCase(ch1)); // 대문자
System.out.println(Character.toLowerCase(ch1)); // 소문자
// alphabetic & upper | lower => 영문
// !alphabetic & !digit => 특수문자
StringBuffer & StringBuilder 클래스
일반적인 문자열을 다룰 때 에는 String 클래스를 사용하는게 좋다.
다만, 자원이 한정적인 경우를 대비해서 항상 자기 자신이기 때문에 객체를 새로찍어내지 않아 메모리적인 이득이 있다.
StringBuffer sb = new StringBuffer(5); // 공간 지정 안주면 16
StringBuffer sb2 = new StringBuffer("java"); // 4 + 16 공간
StringBuffer sb3 = new StringBuffer("Web");
sb2.append(sb3);
sb2.append("Framework");
System.out.println(sb2);
for(int i = 0; i < 5; i++) {
sb.append('a');
}
sb.trimToSize(); // capacity 중 비어있는 공간을 날림 자주 호출할 수 록 비효율적
// 보통은 변동 추이를 보고 trimToSize를 호출할 때를 봐야한다.그래야 더 좋은 메모리 효율을 낼 수 있다.
System.out.println(sb+":"+sb.capacity());
System.out.println(sb2+":"+sb2.capacity()); // 생성된 값 + 16
System.out.println(sb3+":"+sb3.capacity());
StringBuffer st1 = new StringBuffer("java");
st1.append(1111);
st1.insert(4, "Web");
st1.insert(0, 2222);
st1.replace(4, 8, "JAVA");
st1.delete(4, 8);
System.out.println(st1);
st1.reverse();
System.out.println(st1);
StringBuffer 와 StringBuilder의 차이는 실사용에선 아예 없다.
동시 사용할 때 안전하냐 그렇지 않냐의 차이만 있다.
package - import
다른 패키지에 있는 자바 파일을 불러와서 소스코드 작성할 때 중복되는 코드를 줄이기 위해서 만들어짐
와일드카드 문자를 쓸 경우 해당 클래스를 모를 경우 확인하는 곳이기 때문에 우선순위가 떨어진다.
즉, 같은 패키지에 같은 이름의 클래스가 있다면 그 클래스가 가장 우선순위고 그 이후 와일드카드를 통해 확인해서 클래스를 가져온다.
package com.bit;
//import com.bit2.Ex01; // 직접 명시할 경우 제일 우선순위가 됨
import com.bit2.*; // 같은 패키지 Ex01을 우선순위로 찾고 이후 com.bit2에서 Ex01을 찾는다.
import static java.lang.Math.PI; // 이건 있더라 정도만..
public class Ex02 {
public static void main(String[] args) {
com.bit.Ex01 ex01 = new com.bit.Ex01();
Ex01 ex11 = new Ex01();
System.out.println(ex11.su); // 1111출력
System.out.println(PI);
}
}
자료구조 - Collection 프레임워크
LinkedList
// LinkedList 를 이용한 동적할당 배열 구현
// 입력 수정 삭제가 뛰어난 반면 조회할땐 불리하다.
class Arr2 {
Node first;
int cnt = 0;
int size() {
return cnt;
}
int get(int idx) {
Node temp = first;
for (int i = 0; i < idx; i++) {
temp = temp.nxt;
}
return temp.val;
}
void add(int su) {
cnt++;
Node node = new Node();
node.val = su;
if (cnt == 1) {
first = node;
} else {
Node temp = first;
while (true) {
if (temp.nxt == null)
break;
temp = temp.nxt;
}
temp.nxt = node;
}
}
}
장단점이 분명한 LinkedList 같은 것보다 자바에서 배열이 제일 성능좋고 제일 잘만들었기 때문에
특수한 목적을 가지고 사용하지 않는 이상 장점을 유지하고 단점은 극복한 ArrayList를 사용하는게 제일 좋다.
ArrayList
ArrayList list = new ArrayList();
list.add("item1");
list.add(2222);
list.add(3333);
ArrayList list2 = new ArrayList(list); // 깊은 복사
list2.add("item2");
list2.remove("item2"); // 정수 입력 시 인덱스 번호가 우선순위가 됨
list2.addAll(0, list);
list2.removeAll(list); // 겹치는 부분 전체 삭제
list2.add("item1");
list2.add(4545);
list2.set(1, 5555); // 특정 인덱스 값 수정
Object[] arr3 = list2.toArray();
for(int i = 0; i < arr3.length; i++) {
System.out.println(arr3[i]);
}
//list2.isEmpty();
//list2.clear();
for(int i = 0; i < list2.size(); i++) {
System.out.println(list2.get(i));
}
System.out.println(list2.contains("item1"));
System.out.println(list2.contains("item2"));
선형 자료 구조
Queue
Queue - 선입선출 LinkedList로 만든 자료구조
LinkedList는 구현상의 특징일뿐 사용상의 특징은 인터페이스가 정한다.
Queue que;
//que = new ArrayList(); 오류!
que = new LinkedList();
que.offer(1111);
que.offer(2222);
que.offer(3333);
que.offer(4444);
//que.get(1); 오류! 객체는 가지고 있지만 인터페이스로 제약을 주었기 때문
System.out.println(que.peek()); // 제일먼저 들어간 값 1111
que.poll(); // 값 빼내기(뺀 값 return)
System.out.println(que.peek()); // 다음 들어간 값 2222
// que의 모든 값 보고 끄집어내기
while(que.peek() != null) {
System.out.println(que.peek());
que.poll();
}
Stack
선입후출 자바에선 태초부터 만들어져 클래스로 존재함
Stack stack;
stack = new Stack();
stack.push(1111);
stack.push(2222);
stack.push(3333);
stack.push(4444);
System.out.println(stack.pop()); // 값 빼내기 (뺀 값 return)
System.out.println(stack.peek()); // 값 보기
Deque
사용하다는 측면에서 자료구조를 정함에 있어선
클래스를 고려하는 것이 아닌 인터페이스를 고려야해야한다.
Deque = Queue + Stack
// 앞뒤로 값을 넣고 뺄 수 있음
Deque que;
que = new LinkedList();
que = new ArrayDeque();
// 넣은 방향과 반대로 빼면 queue
// 넣은 방향과 같은 방향으로 빼면 stack
// 앞으로 넣고 뒤로 빼기
que.offerFirst(1111);
que.offerFirst(2222);
que.offerFirst(3333);
System.out.println(que.pollLast());
System.out.println(que.pollLast());
System.out.println(que.pollLast());
// 뒤로 넣고 앞으로 빼기
que.offerLast(1111);
que.offerLast(2222);
que.offerLast(3333);
System.out.println(que.pollFirst());
System.out.println(que.pollFirst());
System.out.println(que.pollFirst());
Vector
Collection 프레임워크가 없던 1.2 버젼 이전에서는
동적할당을 Vector를 사용했었다.
이후되서 List 인터페이스를 상속받아 현재는 List와 같은 명령어 사용가능
Vector를 이용해서 Queue 형태든 Stack 형태든 만들어서 사용했었다.
Vector vec;
vec = new Vector();
vec.addElement(1111);
vec.addElement(2222);
vec.addElement(3333);
vec.addElement(4444);
System.out.println(vec.elementAt(0));
비선형 자료구조
순서가 없는 자료 구조 - 집합
- 중복을 허용하지 않는다.
- 순서는 있다. 있어야 중복검출을 할테니까
- 데이터를 출력할 때 for으로 하는게 아닌 iterator 객체로 받아 출력가능Set
Set set1; set1 = new HashSet(); // 왠만하면 HashSet 쓰기 set1 = new TreeSet(); System.out.println(set1.add("첫번째")); // true set1.add("두번째"); System.out.println(set1.add("첫번째")); // false set1.add("세번째"); set1.add("네번째"); set1.add("다섯번째");
HashSet
// 출력
Iterator ite;
ite = set1.iterator();
while(ite.hasNext()) {
System.out.println(ite.next());
}
System.out.println("----");
Object[] arr = set1.toArray();
for(int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
TreeSet
package com.bit;
import java.util.*;
//class Lec12{}
class Lec12 implements Comparable {
int val = 1;
@Override
public int compareTo(Object o) {
return ((Lec12)o).val - this.val; // 값 비교 내림차순 정렬
// return this.val - ((Lec12)o).val; // 값 비교 오름차순 정렬
// return this.hashCode() - o.hashCode();// 레퍼런스 비교
}
Lec12(){}
Lec12(int val){
this.val = val;
}
@Override
public String toString() {
return this.val + "";
}
}
public class Ex12 {
public static void main(String[] args) {
// HashXXX 들은 Hash코드값으로 정렬을 한 것(레퍼런스비교)
Set set = new TreeSet(); // 이진탐색
Lec12 me = new Lec12();
// Comparable을 구현하지 않으면 ClassCastException 발생
set.add(new Lec12());
set.add(me);
set.add(me);
Iterator ite = set.iterator();
while (ite.hasNext()) {
System.out.println(ite.next());
}
System.out.println("----");
Set set2 = new TreeSet(); // 순서가 있게 나온다.자동정렬 오름차순
set2.add(3333);
set2.add(1111);
set2.add(2222);
Iterator ite2 = set2.iterator();
while (ite2.hasNext()) {
System.out.println(ite2.next());
}
System.out.println("----");
Set set3 = new TreeSet(); // 순서가 있게 나온다.
set3.add(new Lec12(1111));
set3.add(new Lec12(2222));
set3.add(new Lec12(3333));
set3.add(new Lec12(1111));
Iterator ite3 = set3.iterator();
while (ite3.hasNext()) {
System.out.println(ite3.next());
}
}
Map
key:val 쌍으로 이루어진 자료구조
Map map = new HashMap();
map.put("key1", "value1");
map.put("key2", 1234);
map.put("key3", 1234); // 값은 중복 O
map.put("key4", true);
map.put("key5", null); // 덮어씌워짐 키는 중복 X
map.put("key5", "dup");
System.out.println(map.get("key1"));
System.out.println(map.get("key2"));
System.out.println(map.get("key3"));
System.out.println(map.get("key4"));
System.out.println(map.get("key5"));
Map map2 = new TreeMap();
map2.put("key1", "value1");
map2.put("key2", 1234);
map2.put("key3", 1234); // 값은 중복 O
map2.put("key4", true);
map2.put("key5", null); // 덮어씌워짐 키는 중복 X
map2.put("key5", "dup");
// Map전체 출력
// Map에서 key만 가져와서 출력
Set keys = map2.keySet();
Iterator ite = keys.iterator();
while (ite.hasNext()) {
Object key = ite.next();
System.out.print(key + ":");
System.out.println(map2.get(key));
// Map에서 key와 value를 쌍으로 entry로 가져와서 출력
// Entry는 java.util.Map.Entry;
Set entrys = map2.entrySet();
Iterator ite2 = entrys.iterator();
while (ite2.hasNext()) {
Entry entry = (Entry) ite2.next();
System.out.println(entry.getKey()+":"+entry.getValue());
제네릭타입
제네릭 타입 - 사용하는 시점 때 타입을 고를 수 있기 때문에
모든 클래스에 대해서 대처가 유연하다.
E - element
T - type
K - key
V - value
package com.bit;
interface Ball {
void play();
}
class BaseBall implements Ball{
String msg;
public BaseBall() {
msg = "거친 실밥이 박혀있는";
}
public void play() {
System.out.println(msg + "공을 던지고 놉니다.");
}
}
class Lotto implements Ball{
String msg;
Lotto(int su) {
msg = su + "번";
}
public void play() {
System.out.println(msg + "입니다.");
}
}
// 제네릭 타입을 이용하여 클래스 선언
class Box<T> {
T su;
public T getSu() {
return su;
}
public void setSu(T su) {
this.su = su;
}
}
public class Ex05 {
public static void main(String[] args) {
BaseBall ball2 = new BaseBall();
Lotto ball = new Lotto(45);
Box<Lotto> box = new Box<Lotto>();
box.setSu(ball);
Box<BaseBall> box2 = new Box<BaseBall>();
box2.setSu(ball2);
Box<Ball> box3 = new Box<Ball>();
box3.setSu(ball2);
box3.setSu(ball);
// box3.setSu("ball"); 오류!
Box<String> box4 = new Box<String>();
box4.setSu("ball");
}
}
제네릭 메소드 - return 타입이랑 파라미터 타입에 적용 시킴으로써 다양한 타입의 클래스에 대항 할 수 있다.
class Lec06 {
// singleton pattern
// private Lec06() {}; // 객체 생성 불가
// private static Lec06 ins = new Lec06();
//
// public static Lec06 getInstance() {
// return ins;
// }
private Lec06() {
};
public static <T> T newInstance(T t) {
T ins = t;
return ins;
}
}
class Lec66 {
public static <T> Box<T> newInstance(T t) {
Box<T> box = new Box<T>();
box.setSu(t);
return box;
}
}
public class Ex06 {
public static void main(String[] args) {
Box<String> box = Lec66.<String>newInstance("abcd");
String msg = box.getSu();
System.out.println(msg);
}
}
추론타입 <? super | extends T>
super 나 포함 내 위로 클래스들
extends 나 포함 내 아래 클래스들
public class Ex07 {
// public static Box<? super Integer> func(int su) { // super는 내 위로
public static Box<? extends Number> func(int su) { // extends는 내 아래로
if(su > 0)
// return new Box<String>(); Number클래스를 상속받지 않기 떄문에 오류!
return new Box<Integer>();
else
return new Box<Number>();
// return new Box<Double>(); Integer랑 같은 선상 이기 때문에 오류!
}
public static void main(String[] args) {
Box<String> box = new Box<String>();
Box<String> box2 = new Box();
// box2.setSu(1234); 오류!
Box box3 = new Box<String>();
box3.setSu(1234); // 오류 X - 무의미해지니 주의!
Box<String> box4 = new Box<>(); // 우변을 빈칸으로 두면 추론타입 (컴파일러JDK1.7이후부터)
Box<?> box5 = new Box<String>(); // 사용하기전에 제네릭을 결정해줘야한다.
((Box<String>)box5).setSu("1234");
}
}
'회고록(TIL&WIL)' 카테고리의 다른 글
WIL 2022.12.26 ~ 2022.12.30 java 공부 (0) | 2023.01.02 |
---|---|
TIL 2022.12.28 내가 쓰는 단축키 모음집 (0) | 2022.12.28 |
WIL 2022.12.12 ~ 2022.12.16 java 공부 (1) | 2022.12.20 |
WIL 2022.12.06 ~ 2022.12.08 java 공부 (0) | 2022.12.20 |
MIL 2022.12~ 알고리즘 공부(java) (0) | 2022.12.14 |