Search

반응형

'자바'에 해당되는 글 51건

  1. 2020.05.10 [자바/java]제너릭과 와일드카드 - <? Extends E> (generic/wildcards) 1
  2. 2020.05.08 [자바]Random 클래스로 난수를 만들어 보기 - long seed, java.util.Random;
반응형

[자바/java]제너릭과 와일드카드 - <? Extends E> (generic/wildcards)

안녕하세요. 신기한 연구소 개발자 티보이입니다.

자바 개발을 하다 보면 배열, Collection 등을 사용하게 됩니다.

다양한 타입을 지원하기 위해 제너릭(generic)을 사용하는데요.

그중 와일드카드(wildcards)를 사용하는데 처음 사용하거나 또는 확실히 이해가 필요한 개발자를 위해 한 번 포스팅해봅니다.

확실히 이해하고 사용한다면 많은 도움이 될 거예요.

렛츠 고~

제너릭을 사용하는 이유는

타입을 미리 지정해서 캐스팅을 사용하지 않아 좀 더 명확하게 사용할 수 있도록 해줍니다.

제너릭(generic)을 사용한 코드를 확인해보겠습니다.

1
2
3
4
5
6
7
8
9
void printCollection(Collection<Object> c) {
 
    for (Object e : c) {
 
        System.out.println(e);
 
    }
 
}
cs

코드는 <Object>라는 타입을 지정하고 있습니다.

이렇게 <Object>로 타입을 지정하는 것을 제너릭이라고 합니다.

그런데 여기서 문제가 있습니다.

혹시 해당 코드를 모든 Collection 타입을 받기 위해 만든 거라면 오류가 발생합니다.

제너릭(generic)은 지정한 타입만 받기 때문입니다.

Object 최상위 클래스이기에 받을 있다고 잘못 이해한 코드입니다.

Collection<Object>선언하면 모든 Collection 타입 모두를 허용할 수 있다는 것이 아니라 겁니다.

와일드카드 “?” 사용해서 아직 알려지지 않은 혹은 미정의 Collection 타입이라는 의미에서 Collection<?>를 사용하면 해결됩니다.

 

1
2
3
4
5
6
7
8
9
void printCollection(Collection<?> c) {
 
    for (Object e : c) {
 
        System.out.println(e);
 
    }
 
}
cs

이렇게 사용하면 Collection 다양한 타입을 사용할 있게 됩니다.

하지만 코드도 다른 문제가 있습니다.

말했듯이 Collection<?>로 와일드카드를 사용하면 Collection 타입은 안전하게 사용할 있지만 임의의 객체를 받을 수는 없습니다.

아래의 예제를 보세요.

1
2
3
4
5
Collection<?> c = new ArrayList<String>();
 
c.add(new Object()); //임의의 객체
 
 
cs

첫 번째줄은 문제가 없습니다.

아마 객체 c를 Collection<?>로 해서 다양한 타입을 지원하고 싶은 마음에 지정한 보이는데 막상 인스턴스화 하는 부분은 ArrayList<String>으로 지정했습니다.

그래서 ArrayList 아니거나 또는 ArrayList라도 String 타입이 아니면 오류 납니다.

두 번째라인을 보면 c 타입을 Collection<?>로 했기에 new Object() 객체를 add 하면 받을 있어 보이지만 사실은 오류가 발생합니다.

오류는 String 타입으로 캐스팅하라고 나올 겁니다.

 

확실히 타입을 정해서 사용한다면 와일드카드 “?” 사용해도 무방하겠지요?

 

<? extends E>

혹시 이것을 ? 어떻게 사용하는지 궁금하시나요?

제너릭(generic)은 개발의 다양성을 위한 기능이지 않을까 생각해봅니다.

 

와일드카드 “?” 설명 했으니 아시겠죠? 지정되지 않은 객체를 받을 있다는 의미입니다.

그럼 extends E 있을까요?

E elements 약자로 보시면 됩니다. E 그대로 사용하는게 아닙니다.

Extends는 상속 의미 그대로입니다. 지정되지 않은 객체 "?" 가 E를 상속받았다는 의미예요.

 

예를 들어볼께요.

게임 개발을 하는데 유닛 추상클래스(abstract clsss Units) 있습니다.

그리고 인간(class Human extends Units),

요정(class Fairy),

오크(class Oak) 구성된 유닛들이 있습니다.

세개의 클래스는 유닛 추상클래스를 상속받습니다.

유닛들은 게임판에 객체를 생성해서 이미지로 표현해야 합니다.

게임판이라는 클래스가 있고 안에는 객체를 이미지로 만드는 메서드가 있습니다.

유닛들 인간, 요정, 오크를 모두 그려야 하는 경우 각각 메서드를 구성하고 호출하게 되면 소스도 중복되고 비효율적인 소스가 됩니다.

이런 경우 객체들을 List 담은 List 객체로 넘겨주면 되는데

문제는 List 내에 인간, 요정, 오크 다양한 타입이 존재하게 됩니다.

위에서 사용한 제너릭(generic)과 와일드카드(wildcards)로 메서드를 만들어 봤습니다.

 

1
2
3
4
5
6
7
8
9
Public void showAllUnit(List<Units> units){
 
       For (Units u: units) {
 
               u.makeImg(this);
 
          }
 
}
cs

 

이렇게 되면 위에서 말했듯 List내에서 <Units> 타입만 찾게 됩니다.

, Human, Fairy, Oak 찾을 없습니다.

이런 경우 사용할 있는 제너릭(generic)이 <? Extends E> 입니다.

 

1
2
3
4
5
Public void showAllUnit(List<extends Units> units){
 
 
 
}
cs

 

이렇게 되면 List에서 와일드카드(wildcards) ? 의 타입을 찾아야 하는데 바로 Units 클래스를 상속받은 Human, Fairy, Oak를 받을 수 있게 됩니다.

이해가 되셨나요?

이제 제너릭(generic)과 와일드카드(wildcards) 그리고 <? Extends E>사용법을 알게 되었으니 개발에 활용하시길 바랍니다.

즐 코딩하세요~

반응형
반응형

안녕하세요. 신기한 연구소의 티보이입니다.

이번은 자바 프로그램을 개발하다 보면 가끔 사용하는 Random(난수) 클래스에 대해 알아볼게요.

개발에 잘 활용하세요~

Random클래스란?

순서가 없는 연속적인 임의의 수를 난수라고 합니다.

난수를 만들어 주는 클래스가 Random클래스이며 java.util 패키지에 포함되어 있습니다.

import java.util.Random; 

 

생성자.

Random r = new Random(); //기본 생성자기본생성자 

Random r = new Random(long seed); //seed 설정 생성자 

 

메서드.

Next, nextBoolean, nextDouble, nextFloat, nextGaussian, nextInt, nextLong, setSeed 

 

사용 예.

우선 기본 생성자를 사용해서 객체를 인스턴스화 하고 자주 사용하는 nextInt() 메서드를 이용하면 난수를 얻을 수 있습니다.

1
2
3
Random r101 = new Random();
                
System.out.println(r101.nextInt());
cs

 

결과 

-2057661722
1761664520

이때 만들어지는 난수는 양수, 음수 상관없이 숫자의 크기도 맘대로 불규칙적으로 만들어집니다.

로또 숫자처럼 원하는 범위 내에서 만들고 싶다면 nextInt메서드에 범위 값을 넘겨주면 됩니다.

1
2
3
4
5
6
7
8
9
        Random r0 = new Random(); 
        
        System.out.println(r0.nextInt(1000));
        System.out.println(r0.nextInt(1000));
        
        Random r1 = new Random(); 
        
        System.out.println(r1.nextInt(1000));
        System.out.println(r1.nextInt(1000));    
cs

 

결과.
950
148
888
607

r0 객체로 random 난수를 만드는데 "1000"이라는 범위를 설정했습니다. nextInt(1000);

이 범위 안의 정수값이 임의로 표출됩니다.

또한 r0객체에서 연속으로 nextInt 를 사용하거나 또는 새로 r1객체를 사용해서 만들거나 항상 새로운 난수를 주어진 범위 내에서 만들게 됩니다.

보통 이 정도면 기본적인 난수를 만들어 사용하는데 문제가 없습니다.

 

두 번째 seed를 사용하는 생성자를 보겠습니다..

특징은.

Seed값을 넣으면 이 초기값을 가지고 난수를 만듭니다.

기본 생성자와 다른 점은,

기본 생성자는 객체를 인스턴스화 할 때나 또는 nextInt() 메서드를 실행할 때마다 위 예제처럼 중복될 가능성이 거의 없는 새로운 난수를 만듭니다.

Seed값을 받는 생성자는 객체를 인스턴스화 할 때는 계속 같은 값을 만듭니다.

1
2
3
4
5
6
7
8
9
        Random r2 = new Random(8); 
            
        System.out.println(r2.nextInt(1000));
        System.out.println(r2.nextInt(1000));
        
        Random r3 = new Random(8); 
        
        System.out.println(r3.nextInt(1000));
        System.out.println(r3.nextInt(1000));    
cs
결과.
364
956
364
956

결과를 확인해 보면 r2와 r3의 seed 값이 "8"로 같습니다.

다른 Random클래스 객체로 인스턴스화 했지만,

1000 범위값의 난수는

364로 같습니다.

하지만 한 번 인스턴스화 한 상태에서 nextInt()만 호출 시 다른 값을 만듭니다.

중요한 것은 이렇게 만들었다고 해도 다시 객체를 인스턴스화 하면 또 같은 순서대로 난수가 나옵니다. 규칙적 난수라고 하면 될까요?

위 예제를 보면 r2나 r3로 다시 종료하고 실행해도 같은 값이 순서대로 나옵니다.

seed값을 다르게 넣거나 범위값이 다르게 넣으면 다른 난수가 규칙적으로 나옵니다.

위 메서드 목록에 보면 setSeed가 있는데,

일반 생성자로 생성한 Random 클래스 객체를 해당 메서드를 통해 중간에 seed값을 설정할 수 있게 해줍니다.

정리해 보면,

일반 생성자로 만든 난수는 로또 번호 자동 생성기 같이 수시로 그때마다 다르게 조건에 맞는 난수가 필요한 경우에 사용하면 됩니다.

Seed를 받는 생성자의 경우는 난수를 만든다는 것은 같지만 seed값에 의해 객체가 인스턴스화 될 때마다 같은 난수를 만들어 주기에 그에 맞는 용도로 사용하면 됩니다.

예를 들어 데이터베이스에 보안상의 이유로 직원의 인증번호를 그대로 입력하면 안 되는 상황이 있다고 가정합니다. 직원이 인증번호를 저장할 때 seed값에 인증번호를 넣고 난수를 받아서 저장하면 데이터베이스에는 직원의 인증번호가 저장되지 않고 생성된 난수가 저장 됩니다.

이후 인증 시도 시 직원이 인증번호를 seed로 해서 난수로 만든 수와 데이터베이스의 난수와 비교했을 때 같으면 인증이 되도록 할 수 있겠네요.

이런 방식을 응용해서 잘 활용하면 될 듯합니다.

마치겠습니다. 즐코딩 하세요~

반응형