ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 21-11-10 DecimalFomat#2, interface, Collection
    학원/Java 2021. 11. 10. 16:04

     

    DecimalFomat

     

     

    천단위 구분 기호 표시 패턴 "0,000"

     

    number = 123456789;
    df = new DecimalFormat("0,000");
    System.out.printf("%19s: %f -> %s\n", "0,0000", number, df.format(number));

     

     

     

    이 방법을 사용할 때는 천 미만의 숫자가 나올 때 자리수가 모자란 만큼 0과 함께 콤마가 출력된다는 단점이 있다.

     

    number = 89.0;
    df = new DecimalFormat("0,000");
    System.out.printf("%19s: %f -> %s\n", "0,0000", number, df.format(number));

     

     

    "0.000"대신 "#,###" 을 사용하면 위와 같은 현상을 해결 할 수 있다.

     

    df = new DecimalFormat("#,###");
    System.out.printf("%19s: %f -> %s\n", "#,###", number, df.format(number));
    number = 123456.0;
    System.out.printf("%19s: %f -> %s\n", "#,###", number, df.format(number));

     

     

    #을 이용한 소수점 표시 : #의 갯수보다 표시할 숫자가 많으면 # 갯수만큼 표시, #의 갯수보다 표시할 숫자가 적으면 숫자가 있는 만큼만 표시한다. (0을 채워넣지 않음)

     

    number = 123456.7128;
    df = new DecimalFormat("#,###.###");
    System.out.printf("%19s: %f -> %s\n", "#,###.###", number, df.format(number));
    number = 123456.7;
    System.out.printf("%19s: %f -> %s\n", "#,###.###", number, df.format(number));

     

     

    # 수가 모자라다면 반올림 하여 표시하며 숫자가 #의 갯수보다 적다면 0으로 채워넣지않고 있는 만큼만 표시한다.

     

    숫자 외에 기호나 문자도 표시할 수 있다.

     

    number = 1234;
    df = new DecimalFormat("₩#,###.###원"); //단어 또는 기호 표시
    System.out.printf("%19s: %f -> %s\n", "₩#,###.###원", number, df.format(number));

     

     

    음수와 양수의 양식을 별도로 표시 : "#,###.### +; #,###.##-"

     

    number = -1234.2;
    df = new DecimalFormat("#,###.### +; #,###.##-");
    //;을 기준으로 왼쪽은 양수 양식, 오른쪽은 음수 양식
    System.out.printf("%19s: %f -> %s\n", "#,###.### +; #,###.##-", number, df.format(number));

     

     

    %표시 : "#.#%"

     

    number = 0.8539;
    df = new DecimalFormat("#.#%");	// 자동으로 100을 곱해서 %로 표시
    System.out.printf("%19s: %f -> %s\n", "#.#%", number, df.format(number));

     

    Print와 fomat의 차이

     

    number = 123.172839;
    //소수점 첫째자리까지 표시
    System.out.println("123.172839 -> " + (int)(number*10)/10.0); //버림
    System.out.printf("123.172839 -> %.1f\n", number);
    df = new DecimalFormat("0.0");
    System.out.println("123.172839 -> " + df.format(number)); //반올림

     

    format을 이용하면 간단하게 양식에 맞춰 출력할 수 있다. printf와 DesimalFormat은 반올림, println은 버림하여 출력한다.

     

     

     

    Abstract

    추상 클래스 : 추상메소드를 하나 이상 포함한 클래스

    (추상메소드 : 메소드의 원형만 존재하고 실제 내용이 없는 메소드)

    상속을 통한 다형성의 구현에 강제성을 부여하기 위한 클래스. 상속을 통해 다형성(부모클래스를 상속받아 여러형태의 자식 클래스를 생성하고 활용함)을 구현하고자 하여도, 하위클래스에서 메소드 오버라이딩을 구현하지 않으면 다형성을 완벽히 구현할 수 없다. 이때 오버라이딩을 구현하지 않아도 오류가 발생하지 않는 점을 강제성의 부재라 한다. 이 강제성의 부재를 해결하기 위한 클래스가 추상클래스이다.

     

    //추상 클래스 
    class Animal {
    	public void sound() { System.out.println("을음소리");}
    }
    
    class Dog extends Animal { //sound메소드 오버라이딩 O
    	public void sound() {System.out.println("멍멍");}
    }
    
    class Cat extends Animal {}	//sound메소드 오버라이딩 X
    
    public class Extend10_Abstract10 {
    	public static void main(String[] args) {
    		Dog dog = new Dog();
    		Cat cat = new Cat();
    		System.out.println("강아지 소리");
    		dog.sound();
    		System.out.println("고양이 소리");
    		cat.sound();
    	}
    }

     

    Dog 클래스에서는 sound()메서드를 오버라이딩 하고 Cat클래스에서는 오버라이딩 하지 않았다.

    출력 결과를 보면 

     

     

    cat.sound(); 에서는 부모 클래스인 Animal의 sound()가 출력되고 있다.

    이렇게 자식 클래스에서 부모클래스의 메소드를 오버라이딩 하지 않아도 오류가 발생하지 않는다 = 강제성의 부재

     

     

    추상클래스는 어떻게 만들까?

     

    abstract class AbstractAnmaal {
    	public abstract void sound();
        //메소드의 정의만 존재하고 body가 없다
    }

     

    형식 : 접근 지정자 abstract 리턴값의 타입 메소드명 (매개변수);

    추상 클래스는 일반 클래스와 동일하게 일반 멤버변수 일반 메소드, 생성자등을 가질 수 있으며 추상 메서드를 반드시 한개 이상 포함해야한다.  

    ※ 추상클래스는 상속 전용이므로 메인영역에서 AbstractAnimal a = new AbstractAnimal();와 같이 추상클래스 객체를 생성할 경우 에러가 발생한다. (생성자 없음)

     

    이렇게 만든 추상클래스를 상속을 통해 다형성을 구현한다.

     

    상속받을 자식 클래스를 생성하면 아래와 같이 클래스 이름에 에러가 발생하며 추상클래스의 추상메서드를 오버라이딩 하면 에러가 사라진다.

     

     

    추상메소드를 오버라이딩한 자식클래스는 일반 클래스로 사용될 수 있다.

    = 추상클래스로는 추상클래스 객체를 만들 수 없지만 추상클래스(부모)의 레퍼런스 변수로 자식 클래스의 인스턴스 주소를 저장할 수 있다. 

     

    AbstractAnimal a = new AbstractAnimal();	//err
    AbstractAnimal b = new DogA();			//ok
    AbstractAnimal c = new CatA();			//ok

     

    추상 클래스는 내부에 완전하지 못한 추상메서드가 있으므로 객체 생성이 불가능하지만 자식들의 인스턴스를 저장할 레퍼런스 변수로는 사용이 가능하다. (다형성의 구현)

     

    abstract class AbstractAnimal {
    	public abstract void sound(); //정의만 존재
    }
    
    class DogA extends AbstractAnimal{
    	
    	@Override
    	public void sound() {System.out.println("멍멍");}
    }
    
    class CatA extends AbstractAnimal {
    	
    	@Override
    	public void sound() {System.out.println("냐옹");}
    }
    public class Extend10_Abstract02 {
    	public static void main(String[] args) {
    		DogA dog = new DogA();
    		CatA cat = new CatA();
    		System.out.println("강아지 소리");
    		dog.sound();
    		System.out.println("고양이 소리");
    		cat.sound();
    	}
    }

     

     

    추상클래스의 단점 

    추상 메소드 구현의 강제성이 아래의 경우 단점이 될 수 있다.

    1. 추상 메소드의 갯수가 많아지면 상속에 부담

    2. 자식 클래스에서 사용하지 않을 추상메소드임에도 객체 생성을 위해 반드시 구현해야한다.

     

     

    해결 방법 

    -> 모든 추상 클래스가 구현(오버라이드)된 클래스를 생성하고 이 클래스를 상속받아 사용하면 필요없는 메소드를 강제로 구현하지 않고 필요한 것만 사용할 수 있다.

     

    package days18;
    
    abstract class AbstractA {
    	public abstract void test1();
    	public abstract void test2();
    	public abstract void test3();
    	public abstract void test4();
    	public abstract void test5();
    	public abstract void test6();
    	public abstract void test7();
    }
    
    class Abstract_Adapter extends AbstractA {
    
    	public void test1() {}
    	public void test2() {}
    	public void test3() {}
    	public void test4() {}
    	public void test5() {}
    	public void test6() {}
    	public void test7() {}
    	
    }
    
    class Abstract_Sub1 extends Abstract_Adapter {
    	public void test1() {System.out.println("test1 오버라이딩!");}
    }
    
    public class Extend10_Abstract03 {
    	public static void main(String[] args) {
    		
    		AbstractA a = new Abstract_Sub1();
    		a.test1();	// test1 오버라이딩!
    	}
    }

     

    어댑터 클래스를 상속받은 클래스도 추상클래스의 자식(손자) 클래스가 된다. -> 다형성 구현가능

    (AbstractA a = new Abstract_Sub1(); 가능)

     

     

    interface

    extends를 이용하면 단일상속( 한 클래스만 상속받을 수 있음)만 가능하나 interface를 이용하면 다중상속이 가능하다. 

    Interface는 public static final 멤버필드와 public abstract 메서드만 가질 수 있다. (추상 클래스처럼 일반 멤버변수와 멤버 메소드를 가질 수 없다.)

     

    interface InterA {
    //	int n1;  -> err : 일반 변수 생성 불가
    //	InterA(){} : 생성자 생성 불가
    //	public void print() {}  -> err : 일반 메서드 선언 불가
    	
    	public static final int num =10;
    	int n1 = 0;	// final static 생략 가능
    	public abstract void test();
    }

     

    interface는 일반변수, 메서드를 생성하지 못하므로 생성자 역시 생성이 불가능하다.

    interface를 상속하는 클래스는 extends 대신 implements를 사용한다.

     

    class SubA implements InterA{
    	@Override
    	public void test() {System.out.println("SubA의 test 메소드 실행");}
    }

     

     

    interface의 메서드를 오버라이드 하지 않으면 추상클래스와 같은 오류가 발생한다.

     

    interface는 객체를 생성할 수 없다. (InterA a = new InterA(); // err)

    1. 생성자가 없으므로 객체 생성불가

    2. 추상 메소드를 포함하고 있기 때문에

     

    상속을 통한 다형성 구현에만 인터페이스가 활용되며 부모 인터페이스의 레퍼런스를 사용하여 자식클래스의 객체를 참조하는 것은 가능하다.

     

    public class Extend10_Interface01 {
    	public static void main(String[] args) {
    		
    		InterA a1 = new SubA();
    		a1.test();
            
    	}
    }

     

     

    interface InterB{
    	public static final int n1 = 1;
    	public static final int n2 = 2;
    	int n3 = 3; // public static final 생략 가능
    	
    	public abstract void test1();
    	public abstract void test2();
    	void test3();	// public abstract 생략가능
    		
    }

     

    public static final이 생략된 변수와 일반 멤버 변수의 구분은 초기값의 유무에 따라 구분되고

    public abstract가 생략된 메서드와 일반 메서드의 구분은 { }의 유무로 구분한다.

    (= interface 내부에서는 멤버변수를 반드시 초기화해야하고 메서드는 {}를 사용하지 않는다.)

     

    interface는 interface끼리 상속(extends)가 가능하다.  (다중 상속 가능)

     

    interface InterC_Super1 {
    	void interC_Super1Test();
    }
    
    interface InterC_Super2 {
    	void interC_Super2Test();
    }
    
    interface InterC_Sub extends InterC_Super1, InterC_Super2{
    	void interC_SubTest();
    }

     

    InterC_Sub는 InterC_Super1과 InterC_Super2를 상속받았다. 이는 interface끼리의 상속으로 부모클래스의 메소드 오버라이딩이 필수는 아니다. 

     

    -> InterC_Sub를 상속받는 클래스는 interC_Super1Test(), interC_Super2Test(), interC_SubTest() 세 개의 메소드를 상속받아 구현해야한다.

     

    class SubC1 implements InterC_Super1, InterC_Super2 {
    
    	@Override
    	public void interC_Super2Test() {}
    	@Override
    	public void interC_Super1Test() {}
    	
    }
    
    class SubC2 implements InterC_Sub{
    
    	@Override
    	public void interC_Super1Test() {}
    	@Override
    	public void interC_Super2Test() {}
    	@Override
    	public void interC_SubTest() {}
    	
    }

     

    일반 클래스가 인터페이스를 다수개 implement했다면 그 인터페이스들이 보유한 추상 메서드들을 모두 구현 해야한다.

     

    public class Extend11_Interface03 {
    	public static void main(String[] args) {
    		SubC2 c1 = new SubC2();
    		InterC_Super1 s1 = new SubC2();
    		InterC_Super2 s2 = new SubC2();
    		InterC_Sub s3 = new SubC2();
    		
    		s1.interC_Super1Test();
    		s2.interC_Super2Test();
    		//s1.interC_Super2Test(); //err
    		//s2.interC_Super1Test(); //err
            s3.interC_Super1Test();
    		s3.interC_Super2Test();
            s3.interC_SubTest();
    	}
    }

     

    SubC2 는 부모를 3개 가지고 있는 것과 같으므로 상위 클래스를 모두 레퍼런스 변수의 클래스으로 사용할 수 있다.

     

    ※인터페이스를 다중 상속한 경우 부모 인터페이스는 자신의 추상메소드만을 접근할 수 있다.

    interC_Super1은 interC_Super2Test() 메소드를, interC_Super2은 interC_Super1Test() 메소드를 가지고 있지 않으므로 호출 시 에러가 발생한다.  interC_Sub는 interC_Super1과 interC_Super2를 상속받아 두 메소드를 모두 가지고 있는 것과 같으므로 오류가 발생하지 않는다. 

     

    일반 클래스는 extends로 상속할때 다중상속이 불가능하지만 extends와 implement를 동시에 사용하는 것은 가능하므로 간접적인 방식으로 다중상속을 구현할 수있다.

    class 자식클래스명 extends 부모클래스명 implements 부모인터페이스명(복수개 가능) 의 형식을 따른다.

     

     

    추상메서드를 이용한 상속 예시

     

    interface Repairable { }
    
    abstract class Unit{
    	int hp;		//현재 체력
    	int max_hp;	//최대 체력
    	
    	Unit(){}
    	Unit(int p){
    		max_hp = p;
    		hp = (int)(p*0.8);
    	}
    	
    	//HP 출력 메소드
    	public void prnHP() { System.out.printf("hp : %d/%d\n", hp, max_hp); }
    	
    	//위치 출력 메소드 (abstract)
    	public abstract void move(int x, int y);
    	
    }
    
    class GroundUnit extends Unit {
    	
    	//super클래스의 생성자 형식에 맞춰 생성자 생성
    	GroundUnit(int p) { super(p); }
    
    	//추상클래스 오버라이딩 (필수)
    	@Override
    	public void move(int x, int y) {
    		System.out.printf("x : %d, y : %d로 뛰어갑니다\n\n", x,y);
    	}
    }
    
    class AirUnit extends Unit {
    	
    	AirUnit(int p) { super(p); }
    
    	@Override
    	public void move(int x, int y) {
    		System.out.printf("x : %d, y : %d로 날아갑니다\n\n", x,y);
    	}
    }
    
    class Tank extends GroundUnit implements Repairable {
    	//Tank -> GroundUnit -> Unit으로 super를 타고 올라간다
    	Tank() { super(150);}
    	//toString 오버라이딩
    	public String toString() {return "Tank"; } 
    }
    
    class Marine extends GroundUnit {
    	Marine() { super(40);}
    	public String toString() {return "Marine"; } 
    }
    
    class SCV extends GroundUnit implements Repairable{
    	SCV() { super(40);}
    	public String toString() {return "SCV"; } 
    	public void repair(Repairable r) {
    		if(r instanceof Unit) {	//Unit을 상속받은 타입인지 확인
    			Unit u = (Unit) r;
    			//Tank나 DropShip, SCV로 형변환하지 않고 
    			//hp와 max_hp를 다룰 수 있는 부모클래스 Unit으로 형변환
    			if(u.hp != u.max_hp) System.out.println(u + "의 수리를 시작합니다");
    			else { System.out.println(u + "는 수리할 필요가 없습니다.");
    			return; }
    			while(u.hp != u.max_hp) {
    				u.hp+=2;
    				System.out.println("hp + 2, 현재 hp : " + u.hp);
    			}
    			System.out.println(u + "의 수리를 완료했습니다.\n");
    		}
    		
    	}
    }
    
    class Dropship extends AirUnit implements Repairable{
    	Dropship() { super(150);}
    	public String toString() {return "Dropship"; } 
    }
    
    
    public class Extend11_Interface04 {
    	public static void main(String[] args) {
    		
    		Tank t = new Tank();
    		Dropship d = new Dropship();
    		Marine m = new Marine();
    		SCV s1 = new SCV();
    		SCV s2 = new SCV();
    		System.out.print(t + " ");
    		t.prnHP();
    		t.move(10, 20);
    		System.out.print(d + " ");
    		d.prnHP();
    		d.move(10, 20);
    		System.out.print(m + " ");
    		m.prnHP();
    		m.move(10, 20);
    		System.out.print(s1 + " ");
    		s1.prnHP();
    		s1.move(10, 20);
    		System.out.print(s2 + " ");
    		s2.prnHP();
    		s2.move(10, 20);
    		
    		s1.repair(t);
    		s1.repair(d);
    //		s1.repair(m);	// Repairable을 implements하지 않아 err
    		s1.repair(s2);
    		s1.repair(s2);
    		
    	}
    }

     

    출력 결과

     

    SCV 는 marine의 수리가 불가능 하므로 수리가 가능한 Tank, Dropship, SCV 만 interface Repairable 을 implements하도록 만들어 repair의 매개변수를 (Repairable r)로 지정하면 수리가 불가능한 marine은 이 메서드의 매개변수로 들어갈 수 없게된다. (에러발생) 이때 interface Reairable은 기능은 없고 원하는 클래스만 고를 수 있게 해주는 역할을 한다.

     

    Unit의 멤버변수를 private 설정한다면 getter와 setter을 이용하여 hp와 max_hp를 불러와야한다다.

    move를 abstract로 지정한 것은 실습을 위한 것이지 굳이 abstract여야할 필요는 없다.

     

    Unit a = new Tank(); / Unit a = new Dropship(); / Unit a = new SCV(); / Unit a = new Marine(); 전부 가능

     

     

    Collection 

    컬랙션 클래스 : 자료구조를 구현하는 클래스

    자료구조 : 각각의 데이터들을 효율적으로 저장하고 운용하기 위한 방법론 

     

    1. 배열 

    다수개의 요소를 저장할 수 있음, 번호(인덱스)에 의한 손쉬운 접근 방법을 제공한다.

    크기가 고정되어 있으며 데이터의 중간 삽입과 중간 삭제에 비효율적이다.

     

    2. 리스트

    크기 제약없이 데이터를 저장할 수 있다. 데이터의 삽입과 삭제에 최적화되어 있으나 실제 데이터가 아닌 참조값을 저장하기 때문에 검색에 취약하다. -> 이를 보안하기 위해 double linked List를 사용하기도 함

    데이터 저장 시 불필요한 메모리를 사용한다 (크기의 제약이 없기 때문)

    자바의 모든 자료구조 클래스(컬렉션 클래스)들은 java.util 패키지를 통해 제공받을 수 있다.

    동적 배열을 구현하고 있는 클래스들 - Vector, ArrayList(가장많이사용)

    linked List를 구현하고 있는 클래스 - LinkedList

     

    3. Set 타입의 저장방법을 구현하고 있는 클래스들 : HashSet, TreeSet

    데이터를 저장할 때, 중복을 허용하지 않는 방법 : 검색을 위해 사용, 중복된 값을 제거하기 위해 사용한다.

     

    4. Map 타입 저장 방법을 구현하고 있는 클래스들 : Hashtable, HashMap(가장많이사용)

    데이터를 Key와 Value의 형태로 저장하는 방법 : 검색을 위해 사용, Key값은 중복을 허용하지 않고 Value의 값은 중복을 허용한다.

     

    5. Vecter, ArrayList 클래스

    두 개의 클래스는 동일한 기능을 제공 : 스레드 동기화의 지원 여부, 크기의 제약 없이 데이터를 저장(동적으로 크기 확장), 배열과 같은 인덱스를 기반으로 데이터에 접근하며 데이터의 입력 순서를 유지한다. 데이터의 중복을 허용한다.

     

    동적 배열의 객체 생성 초기값으로 크기를 지정할 수 있지만 통상적으로 크기 지정없이 사용한다.

     

    import java.util.ArrayList;
    import java.util.Vector;
    
    public class Collection01 {
    	public static void main(String[] args) {
    		
    		Vector v= new Vector();
    		ArrayList a = new ArrayList();
    		
    		v.add(10);
    		v.add(20);
    		v.add(30);
    
    		a.add(10);
    		a.add(20);
    		a.add(30);
    		
    		for(int i=0; i<v.size(); i++) System.out.printf("v[%d] = %d\t\t", i, v.get(i));
    		System.out.println();
    		for(int i=0; i<a.size(); i++) System.out.printf("a[%d] = %d\t\t", i, a.get(i));
    	}
    }

     

     

    데이터의 입력은 add()메소드를 이용하고 메소드를 통해 저장된 값은 실제 데이터가 아닌 레퍼런스값이다.

    자료를 출력할 때는 반복문 + get()메소드를 이용한다. 

    ※반복문을 이용할 때 2번째 조건문에는 a.length가 아닌 a.size();를 사용해야한다.

     

    데이터의 대체, 삽입

    set()과 add()

     

    set(인덱스, 값)은 해당 인덱스에 존재하던 데이터를 지우고 새로운 데이터로 대체하고 add(인덱스, 값)은 해당 인덱스에 데이터를 집어넣고 나머지 데이터들을 한칸씩 뒤로 민다.

     

    a.set(2, 100);	//인덱스 매개변수를 추가하여 데이터 삽입가능
    for(int i=0; i<a.size(); i++) System.out.printf("a[%d] = %d\t\t", i, a.get(i));
    System.out.println();
    		
    a.add(2, 300); 
    for(int i=0; i<a.size(); i++) System.out.printf("a[%d] = %d\t\t", i, a.get(i));

     

     

    set()을 이용한 첫번째 결과는 30이 100으로 대체되었고 add()를 이용한 두번째 결과는 a[2]에 300이 들어가고 원래 a[2]에 있던 100은 a[3]으로 밀려난 것을 볼 수 있다.

     

     

    컬랙션 클래스의 저장방식

    -> 모든 컬렉션 클래스들은 기본적으로 Object타입을 저장/반환할 수 있다.

    Object타입을 매개변수로 사용하는 모든 컬렉션클래스들은 타입에 상관없이 저장할 수 있지만 저장된 데이터를 반환 받는 과정에서 런타임에러가 발생할 수있다. 

     

    public class Collection02 {
    	public static void main(String[] args) {
    		ArrayList a = new ArrayList();
    		//다양한 타입을 저장할 수 있는 컬랙션 클래스의 객체 
    		a.add(10);
    		a.add(1.1);
    		a.add("Hello");
    		Integer i0 = (Integer)a.get(0);
    		Integer i1 = (Integer)a.get(1); //err
    		Double i2 = (Double)a.get(1);
    		String i3 = a.get(2); //err
    		String i3 = (String) a.get(2);
            
    		System.out.printf("i0 -> %d\n", i0);
    		System.out.printf("i0 -> %.1f\n", i2);
    		System.out.printf("i0 -> %s\n", i4);
    		
    	}
    }

     

    ArrayList는(참조값을 저장하므로 Wrapper 클래스를 사용 )Interger, Double, String을 모두 한 ArrayList에 담을 수 있다. 단, Object타입을 반환하므로 저장된 값을 변수에 저장할 때 알맞은 타입으로 형변환 해주어야 변수에 저장될 수 있다.

     

     

    i1은 Double 타입 참조변수를 Integer타입 변수에 저장하고 있지만 컴파일상에 오류가 일어나지 않는다. 하지만 실행 시키면 에러(java.lang.ClassCastException)를 확인할 수 있다. (런타임에러)

    i3는 형변환을 하지 않아 오류가 발생하고 있다.

     

    오류가 발생하는 두 라인을 주석처리하고 실행하면 아래와 같이 출력된다.

     

     

    위의 예시와 같이 하나의 ArrayList에 여러 자료형을 섞어서 저장하고 사용할 경우 형변환 시 에러 발생 확률이 높아지기 때문에 보통 하나의 자료형으로 통일하여 사용하게 된다. -> get()으로 자료를 꺼낼때 강제 형변환이 필요없다.

     

    이런 방식을 Generic이라고 한다.

     

    Generic

    객체 생성시점에 자료형을 지정하여 서로 다른 자료형을 지원하는 클래스를 생성할 수 있는 문법

    (메서드 오버로딩과 유사)

     

    보통 컬렉션 프레임워크는 여러타입이 혼용되어 저장은 가능하지만 실제로 혼용하는 경우는 거의 없다.

    컬렉션 클래스의 입력, 반환에 관련한 모든 메서드들은 Object타입을 기반으로 하기 때문에 컬렉션에서 데이터 인출(.get()) 시에 강제 형변환을 해야하는 불편함이 있다. 이러한 문제점을 해결하기 위해 JDK 1.5버전 이후에 사용 가능 하게 된 것이 제네릭 문법이다.

     

    ArrayList<데이터타입> list명 = new ArrayList<데이터타입>();

    ArrayList<데이터타입> list명 = new ArrayList<>(); 

    (두번째 나오는 데이터타입은 생략이 가능하다)

     

    ArrayList<Integer> list = new ArrayList<Integer>();
    
    list.add(100);
    Integer i = list.get(0);
    System.out.println(i);	//100

     

     

    LinkedList 클래스

    데이터를 참조값을로 연결하여 저장할 수 있는 클래스.

    갯수에 상관없이 저장할 수 있으며 데이터의 삽입과 삭제에 최적화되어있는 클래스이다. ArrayList와 같이 데이터의 중복을 허용하며 데이터 입력 순서를 유지한다. 

    데이터 저장시 참조값도 같이 저장되기 때문에 메모리 낭비가 발생하며 검색에 취약한 단점이 있다.

     

    import java.util.LinkedList;
    
    public class Collection03 {
    
    	public static void main(String[] args) {
    		
    		LinkedList<Integer> a = new LinkedList<>();
    		a.add(10); a.add(20); a.add(30); a.add(40); a.add(50);
    		for(int i=0; i<a.size(); i++) System.out.printf("a.get(%d) -> %d\n", i, a.get(i));
    	}
    }

     

     

    HashSet 클래스

    데이터의 중복을 허용하지 않는 클래스로 검색을 위해 사용되는 클래스이다. 

    hash 연산 : 클래스 내에서 유일한 값을 얻어 낼 수 있는 고유한 알고리즘 연산 

    -> 저장 시 hash 연산의 결과를 저장하므로 hash 연산 결과로 검색하여 빠른 검색이 가능하다.

     

    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.LinkedList;
    import java.util.Vector;
    
    public class Collection04 {
    
    	public static void main(String[] args) {
    		Vector<Integer> v = new Vector<>();
    		v.add(1); v.add(2); v.add(2);
    		System.out.println(v.size());	//3
    		
    		ArrayList<Integer> a = new ArrayList<>();
    		a.add(1); a.add(2); a.add(2);
    		System.out.println(a.size());	//3
    		
    		LinkedList<Integer> l = new LinkedList<>();
    		l.add(1); l.add(2); l.add(2);	
    		System.out.println(l.size());	//3
    		
    		HashSet<Integer> h = new HashSet<>();
    		h.add(1); h.add(2); h.add(2);	
    		System.out.println(h.size());	//2
    	}
    
    }

     

    위의 다른 배열들과 다르게 HashSet은 중복값이 들어오면 무시한다.

     

     

    예시 

     

    로또 번호 출력을 HashSet으로 구현하기

     

    import java.util.HashSet;
    import java.util.LinkedList;
    import java.util.Vector;
    
    public class Collection04 {
    	public static void main(String[] args) {
    		
    		HashSet<Integer> lotto = new HashSet();
    		while(lotto.size()<6) {
    			lotto.add((int)(Math.random()*45) + 1);
    		}
    		
    		List list = new LinkedList(lotto);
    		Collections.sort(list);
    		System.out.println(list);
    	}
    }

     

     

    일반 배열로 만들었던 것 보다 훨씬 간단하게 6개의 번호를 중복없이 출력할 수 있다

     

    ※해쉬세트 콜렉션에는 sort 메서드가 없으므로 링크드 리스트의 부모클래스인 List 클래스에 전달 하여 리스트 변환 과정을 거치고 Collections.sort로 정렬을 수행해야한다.

    향상된 for문으로 서식과 함께 출력하고 샆다면 리스트를 List<데이터타입>list이름 = new LinkedList<>(전달받을HashSet이름); 와 같이 생성하여 for(데이터타입 k : list이름) 출력문 형식으로 출력하면 된다

     

    List<Integer>list = new LinkedList<Integer>(lotto);
    Collections.sort(list);
    for(Integer i : list) {
    	System.out.print(i + "번 ");
    }

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    '학원 > Java' 카테고리의 다른 글

    21-11-15 Swing  (0) 2021.11.15
    21-11-11 Collection#2, Exception  (0) 2021.11.11
    21-11-09 클래스와 메소드 (String, Wapper, Calendar, DateFormat)  (0) 2021.11.09
    21-11-08 test, 상속#2, object 클래스  (0) 2021.11.08
    21-11-05 상속#1  (0) 2021.11.05

    댓글

Designed by Tistory.