제네릭 개념 알기

JAVA/JAVA 2017. 5. 16. 15:29 |

java 재네릭


재네릭은 클래스 내부에서 사용할 데이터타입을 외부에서 지정하는 기법을 의미한다.

데이터타입을 외부에서 지정하면 장점뭘까?

메소드 선언에 사용되는 파라미터 형식처럼, 타입 파라미터는 다른 입력값을 같은 코드를 재사용 할 수 있는 방법을 제시한다.

다른점은 형식 파라미터는 값이 아니라 입력이다.

타입파라미터는 타입이 입력!


제네릭 없이 캐스팅이 필요한 코드

List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0);


제네릭을 사용하여 코드 작성시,캐스팅이 필요 없어진다.

List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); // no cast


제네릭을 사용함으로써 일반적인 알고리즘을 구현하도록 지원한다.

generics를 사용하면서 다양한 타입들의 콜렉션을 사용할 수 있고 더 안정적이고 읽기 쉬운 코드를 일반적인 알고리즘으로 구현할 수 있다.


좀더 자세히 알아보자.

아래의 코드를 살펴보자.

class Person<T>{
 public T info; 
}
 public class GenericDemo{
  
  public static void main(String[] arge){
    Person<String> p1 = new Person<String>();
    Person<StringBuilder> p2 = new Person<StringBuilder>();
  } 
}



데이터 타입 결과는 

p1.info = String

p2.info = StringBuilder


각각의 인스턴스를 생성할 때 사용한 <> 사이에 어떤 데이터 타입을 사용했느냐에 달려있다.


클래스 선언부

public T info;


클래스 필드 info의 데이터 타입은 T로 되어있다. 실제로 T라는 데티어 타입은 존재하지 않는다.

이값은 아래 코드의 T에서 정해진다.


제너릭 클래스 선언부

class Person<T>{


제네릭 클래스의 인스턴스 생성부

Person<String> p1 = new Person<String>();

제네릭 클래스의 인스턴스 생성시 <String> 으로 지정하면서 제네릭 T info는 String info 가 된다.


재네릭 사용하는 이유


class StudentInfo{
    public int grade;
    StudentInfo(int grade){ this.grade = grade; }
}

class StudentPerson{
    public StudentInfo info;
    StudentPerson(StudentInfo info){ this.info = info; }
}

class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class EmployeePerson{
    public EmployeeInfo info;
    EmployeePerson(EmployeeInfo info){ this.info = info; }
}
public class GenericDemo {
    public static void main(String[] args) {
        StudentInfo si = new StudentInfo(2);
        StudentPerson sp = new StudentPerson(si);
        System.out.println(sp.info.grade); // 2
        EmployeeInfo ei = new EmployeeInfo(1);
        EmployeePerson ep = new EmployeePerson(ei);
        System.out.println(ep.info.rank); // 1
    }
}


위 코드를 보면 StudentPerson와 EmployeePerson가 중복되는 클래스이다.

f(x) = x 함수 클래스로 x 매개변수를 제네릭 클래스로 구현하여 StudentPerson와 EmployeePerson 클래스중복을 제거해보자.


class StudentInfo{
    public int grade;
    StudentInfo(int grade){ this.grade = grade; }
}
class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class Person<T>{
    public T info;
    Person(T info){ this.info = info; }
}
public class GenericDemo {
    public static void main(String[] args) {
        Person<EmployeeInfo> p1 = new Person<EmployeeInfo>(new EmployeeInfo(1));
        EmployeeInfo ei1 = p1.info;
        System.out.println(ei1.rank); // 성공
         
        Person<String> p2 = new Person<String>("부장");
        String ei2 = p2.info;
        System.out.println(ei2.rank); // 컴파일 실패
    }
}

 

기본 데이터 타입과 제네릭

제네릭은 참조 데이터 타입에 대해서만 사용할 수 있다. 기본 데이터 타입에서는 사용할 수 없다. 따라서 아래 코드의 int는 오류난다.

int . char, double ..등등 은 기본데이터로 사용할 수 없다. int 대신 integer 로 대신하여 사용할 수 있다.

class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class Person<T, S>{
    public T info;
    public S id;
    Person(T info, S id){ 
        this.info = info; 
        this.id = id;
    }
}
public class GenericDemo {
    public static void main(String[] args) {
        Person<EmployeeInfo, int> p1 = new Person<EmployeeInfo, int>(new EmployeeInfo(1), 1);
    }
}
 

복수 제네릭

클래스 내에서 여러개의 제네릭을 필요로 하는 경우 아래의 코드를 참조하자.

class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class Person<T, S>{
    public T info;
    public S id;
    Person(T info, S id){ 
        this.info = info;
        this.id = id;
    }
}
public class GenericDemo {
    public static void main(String[] args) {
        EmployeeInfo e = new EmployeeInfo(1);
        Integer i = new Integer(10);
        Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
        System.out.println(p1.id.intValue());
    }
}
 

재네릭 메소드 사용

class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class Person<T, S>{
    public T info;
    public S id;
    Person(T info, S id){ 
        this.info = info;
        this.id = id;
    }
    public <U> void printInfo(U info){
        System.out.println(info);
    }
}
public class GenericDemo {
    public static void main(String[] args) {
        EmployeeInfo e = new EmployeeInfo(1);
        Integer i = new Integer(10);
        Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
        p1.<EmployeeInfo>printInfo(e);
        p1.printInfo(e);
    }
}
 
재네릭 인스턴스 생략 가능하다. 아래와 같이 p1,p2 모두 정상적으로 생성된다.
Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
Person p2 = new Person(e, i);


extends 로 재네릭으로 올 수 있는 데이터 타입을 특정 클래스의 자식으로 제한할 수 있다.

extends는 상속 관계인 클래스 뿐만 아니라 구현(implements)의 관계에서도 사용할 수 있다.

interface Info{
    int getLevel();
}
class EmployeeInfo implements Info{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
    public int getLevel(){
        return this.rank;
    }
}
class Person<T extends Info>{
    public T info;
    Person(T info){ this.info = info; }
}
public class GenericDemo {
    public static void main(String[] args) {
        Person p1 = new Person(new EmployeeInfo(1));
        Person<String> p2 = new Person<String>("부장");
    }
}



제네릭에 대해 기본적인 개념만 살펴보았다.


'JAVA > JAVA' 카테고리의 다른 글

[객체지향] JAVA SOLID 원칙  (0) 2019.02.23
제네릭 메소드  (0) 2017.05.17
다형성  (0) 2015.08.28
클라이언트 ip 구하기  (0) 2015.08.13
java foreach 반복문  (0) 2015.08.13
Posted by 양승아
:

java StringTokenizer

JAVA 2015. 12. 29. 18:22 |
StringTokenizer
token 단위로 String을 끊어 주는 StringTokenizer 클래스

( StringTokenizer )


print the following output :  

this is a test  


print the following output :  

this is a test  



( split )




print the following output :  

this is a test



'JAVA' 카테고리의 다른 글

[java]Mockito 기본 설명  (0) 2017.05.24
Posted by 양승아
:

Decorator Pattern (데코레이터 패턴)


데코레이터 패턴

- 데코레이터는 서브 클래스를 만드는 것을 통해서 기능을 유현하게 확장할 수 있는 방법을 제공한다.

- 한 객체를 여러 개의 테코레이터로 감쌀수 있다.

- 기존 코들르 수정하지 않고도 기능을 확장할 수 있다.  


단점 

- 데코레이터 패턴을 이용해 디자인을 하다 보면 답다한 클래스가 많아질 수 있음

- 겹겹이 애워싼 객체의 정체를 알기가 힘들다

- 상속을 통해 확장할 수도 있지만, 디자인 유연성 면에서는 별로 좋지 않다.


그럼 이제부터 데이레이터 패턴 사용 하지 않은 예를 들면 !!

카페에서 음료를 주문할때 음료하나에 시럽,우유,휘핑 등을 추가하는 경우가 있다.

이 행동을 구현하면 



- 음료를 나타내는 추상 메소드 Beverage 는 카페에서 판매되는 모든 음료는 이 클래스의 서브 클래스가 된다. 즉 Beverage 가 부모클래스 , 슈퍼클래스 이다. 

- beverage 라는 음료 클래스에 우유,두유,모카,휘핑 크림을 나타내는 인스턴스 변수를 추가한다.

- 첨가물에 첨부 여부와 첨가물을 설정한다

- cost() 에서 추가된 첨가물의 가격을 계산한다. 서브클래스에서 cost()메소드를 재구현한다.


자 근데 이런식으로 하면 문제점이 무엇인가 ?

첨가물 가격이 바뀔때 마다 기존 코드를 수정해야된다.

첨가물의 종류가 많아지면 새로운 메소드를 추가해야한다.

새로운 음료가 출시될 수도 있다. 그 중에는 첨가물이 들어가면 안되는 음료도 있다. !! (필요없는 첨가물 메소드 상속 받게됨)

손님이 모카를 두번 추가하면 어떻게 할것인가 ????


부모클래스와 자식클래스

- 자식클래스를 만드는 방식으로 행동을 상속 받으면 그 행동은 컴파일시! 완전히 결정되고 모든 서브 클래스에서 똑같은 행동을 상속 받아야한다.

- 하지만 구성을 통해 객체의 행동을 확장하면 실행 중에 동적으로 행동을 설정할 수 있다.



Decorator pattern 적용







- Beverage 는 가장 기본이 되는  Component 클래스이다. 

- 음료 종류마다 Beverage에 대한 구상 클래스를 하나씩 만든다. (DripCoffee,DripCoffee)

- 각각의 첨가물을 나타내는 데코레이터를 추가(Mocha, Milk )하고  cost(), getDescription() 를 구현해야한다.

- 각 데코레이터 안에는 Beverage 클래스가 들어있다.

- 데코레이터에는 구성요소에 대한 레퍼런스가 들어있는 인스턴스 변수가 있다!!! (private Beverage beverage)        




Beverage.java


DripCoffee.java

Espresso.java

CondimentDecorator.java

Milk.java

Mocha.java

StarbuckCafe.java


결과 


에스프레소, 우유$2.29

제목없음$3.21




'JAVA > Design patten' 카테고리의 다른 글

factory method pattern  (0) 2019.04.27
singleton-pattern  (0) 2019.04.27
옵저버 패턴의 정의  (0) 2015.08.21
Posted by 양승아
:

다형성

JAVA/JAVA 2015. 8. 28. 18:43 |

다형성


이전에 포스팅했엇는데 패턴 공부 하면서 다시한번 개념 잡기 위해 공부!!



//추상클래스 A
abstrct class A{
 int left,right;
 public void setInt(int left, int right){
  this.left = left ; 
  this.right = right ;
 }
 int sum(){
  return this.left + this.right;
 }
 public abstract void sum();
 public void run(){
    sum();
 }
}

class B extend A {
 public void sum(){
   System.out.println("+++sum :" +sum()); 
 }
}

class C extends A {
 public void sum(){
  System.out.println("---sum : " + sum )
 }
}
public class D {
  public static void execute(A a){
    System.out.println("실행결과");
    a.run();
  }
  public static void main(String[] arg){
   A a1= new B();
   A a2 = new C();
  
  a1.setInt(10,20);
  a2.setInt(10,20);

  execute(a1);
  execute(a2);
 
 }
}





'JAVA > JAVA' 카테고리의 다른 글

제네릭 메소드  (0) 2017.05.17
제네릭 개념 알기  (0) 2017.05.16
클라이언트 ip 구하기  (0) 2015.08.13
java foreach 반복문  (0) 2015.08.13
JAVA 앞뒤 공백제거 trim()  (0) 2015.08.13
Posted by 양승아
:


옵저버패턴

옵저버 패턴에서는 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 자동으로 갱신되는 방식으로 일대다 의존성(one-to-many)을 정의한다.


옵저버 패턴 조건

객체간의 결합도는 높아질수록 유지보수가 힘들기 때문에 일단 객체간의 결합도는 낮추는게 일반적이다.

옵저버를 언제든지 추가하려고 할때도 주제를 전혀 변경할 필요가 없다.


예제

가상 모니터링 애플리케이션을 구현해보자.

이 시스템은 다음과 같이 3개의 요소로 어루어져 있고(가상 스테이션, 날씨 데이터, 디스플레이 장비) Weather Data를 통해서 3개 혹은 그 이상 디스플레이 장비에 데이터를 보여주게 된다.





분석

1. 옵저버 패턴의 정의를 떠올리면 one-to-many 관계이므로 one = Weather Data , many = Display 장치가 된다

2. Weather Data 객체를 주제객체로 하고 Display 장치에서 옵저버로 하는 경우 Display 애서 자기가 원하는 정보를

    얻기위해  Weather Data 객체에 등록할수 있는 registerObserver()메소드가 필요하다.

3. 모든 Display 장치는 항목이 다를 수 있다. 그러므로 바로 이 부분이 공통 인터페이스를 이용해서 처리가 가능함

   각 장치마다 구성 요소의 형식이 달라도 똑같은 인터페이스를 구현해야만 Weather Data 객체에서 기상 스테이션으로 측정값을 보낼      수 있다.

4. 즉 모든 디스플레이 장치는 Weather Data 에서 호출할 수 있는 update()메소드가 필요하다. 그리고 이 update() 메소드는 모든 장치들    이 구현하는 공통 인터페이스에 정의 되야 한다.



옵저버 패턴 적용

UML 확인하고 코딩하기!




Observer .java


Subject .java

DisplayElement .java

WeatherData.java

CurrentConditionsDisplay.java

Main .java


display는 하나만 구현함!

동작 시나리오

① WeatherStation에서는 온도, 습도, 기압 정보를 수집한다.

② WeatherStation에서 주기적으로 (30분에 한번식) 현재 데이터(온도,습도,기압)을 WeatherData에 던져 준다.

③ WeatherData는 새로운 데이터를 받으면, Observable에 Observer로 등록되어 있는, 현재상태 출력장비(CurrentConditionDisplay)와 기압변동 출력장비(ForecastDisplay)에 새로운 데이터를 전달한다.

④ 현재상태 출력장비와 기압변동 출력장비는 새로운 데이터(온도, 습도, 기압)을 각자의 활용 방법에 따라 화면에 출력한다.

⑤ WeatehrStation에서 다시 새로운 데이터를 던져준다. 

⑥ ①~④ 번이 반복되며, 주기적으로 현재상태 출력장비와 기압변동 출력장비는 새로운 데이터를 출력한다.


java에서 제공하는 옵저버 패턴 적용




WeatherData.java


CurrentConditionsDisplay .java

Main.java

 java.util.Observable.class  확인


java.util.Observable.class


소스코드 보기


- addObserver(Observer o) : 옵저버를 등록한다. 이후에 들어오는 데이터는 등록된 옵저버에 전달된다.

- deleteObserver(Observer o) : 옵저버를 제거한다. 이후에 들어오는 데이터는 해당 옵저버에 전달되지 않는다.

- notifyObservers(), notifyObservers(Object arg) : 새로운 데이터가 들어오면 등록된 옵저버에 새로운 데이터와, 파라미터를 전달한다.

- deleteObservers() : 등록된 모든 옵저버를 제거한다. 이후에 들어오는 데이터는 전달되지 않는다.

- setChanged() : 신규 데이터가 들어오면, changed 값을 true로 변경, changed 변수가 true 일때만 데이터가 옵저버에 전달된다.

- clearChanged() : changed 값을 false 로 변경한다. 신규 데이터를 옵저버에 전달이 완료되면 clearChanged()를 호출한다.

- hasChanged() : 현재 changed 의 값을 반환한다.

- countObservers() : 현재 등록되어있는 옵저버의 수를 반환한다.



자바의 내장된 옵저버 패턴 이용 (Observable)


- setMeasurements(float temperature, float humidity, float pressure) : 기상스테이션에서 온도, 습도, 기압 측정값을 전달할때 호출한다. 파라미터로 받은 데이터를 갱신하고 measuermentChanged()를 호출한다.

- measurementsChanged() : 옵저버에 전달할 새로운 데이터가 있다고 알리고(setChanged()), 등록된 옵저버에 데이터를 전달한다.(notifyObservers())  (setChanged()와 notifyObservers()는 Observable에서 상속받은 함수이다.)


보는것과 같이 WeatherData.java는 Observable 을 상속하였다. 따라서 Observable의 함수를 사용하여, Observer들에게 데이터를 전달할 수 있다.


15열의 setMeasurements() 함수와 24열의 measurementsChanged() 함수를 보자

기상스테이션(WeatherStation.java)는 주기적으로 데이터(온도,습도,기압)값을 WeatherData의 setMeasurements() 함수를 사용하여 전달한다.

setMeasurements()는 전달받은 데이터를 각 변수에 갱신한 뒤, measurementsChanged() 함수를 호출한다.


measuremensChanged() 함수는 Observer에게 데이터를 전달한다.

먼저 setChanaged() 함수를 호출하여, 전달할 새로운 데이터가 있음을 설정한다. 그리고 notifyObservers() 함수를 호출하여, 갱신한 새로운 데이터를 각 등록된 옵저버에게 전달한다.


정말 간단하다. Observable 을 상속한뒤, 옵저버들에게 데이터를 전달할 때, setChanged()와 notifyObservers()를 순차적으로 호출하면 된다. 그러면 데이터가 등록된 옵저버들에게 전달되는 것이다.







'JAVA > Design patten' 카테고리의 다른 글

factory method pattern  (0) 2019.04.27
singleton-pattern  (0) 2019.04.27
Decorator Pattern (데코레이터 패턴)  (0) 2015.09.03
Posted by 양승아
:

JAVA 클라이언트 IP 구하기


클라이언트 ip 가져오는 방법은 아래와 같다.


Request.getRemoteAddr();

Requset 객체의 getRemoteAddr() 메소드를 호출한다.

로컬로 테스트 한다면 127.0.0.1 의 값을 가져올것이다.


만약 IPv6 형식(0:0:0:0:0:0:01)과 같은 형식으로 반환되면 

eclipse 환경 변수 설정 다이얼로그 띄운다.


Run -> Run Confiugations -> 좌측트리메뉴에서 Apache Tomcat 서버 선택 

-> Arguments 탭 메뉴 선택 -> VM Arguments 텍스트 박스 영역


"-Djava.net.preferIPv4Stack=true"

텍스트 박스 가장 하단에 위의 코드를 추가함





또는  톰캣서버 환경 설정 파일에서 직접 변경하기

\bin\catalina.bat 파일열기 

set JAVA_OPTS 검색하여


:noJuliConfig

set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%


:noJuliManager
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%


위의 2개의 설정 값에  -Djava.net.preferIPv4Stack=true 추가 해준다



:noJuliConfig

set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG% -Djava.net.preferIPv4Stack=true


:noJuliManager
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER% -Djava.net.preferIPv4Stack=true



위처럼 추가하면 127.0.0.1 로 나온다~!


'JAVA > JAVA' 카테고리의 다른 글

제네릭 개념 알기  (0) 2017.05.16
다형성  (0) 2015.08.28
java foreach 반복문  (0) 2015.08.13
JAVA 앞뒤 공백제거 trim()  (0) 2015.08.13
[java] URL(xml파일) java 파싱하는 방법  (0) 2015.08.12
Posted by 양승아
:

java foreach 반복문

JAVA/JAVA 2015. 8. 13. 13:45 |

Foreach 반복문 


for(변수타입 변수이름 : 배열이름){

실행부분;

}


foreach 에서는 배열의 항목 수만큼 실행부분을 반복하는데

반복이 이루어질때마다 배열의 항목을 순서대로 꺼내어 변수에 자동으로 대입해 준다.



( foreach 사용하면 배열값을 가져와 읽을수만 있고 수정할 수는 없다. )



'JAVA > JAVA' 카테고리의 다른 글

다형성  (0) 2015.08.28
클라이언트 ip 구하기  (0) 2015.08.13
JAVA 앞뒤 공백제거 trim()  (0) 2015.08.13
[java] URL(xml파일) java 파싱하는 방법  (0) 2015.08.12
예외처리  (0) 2015.07.31
Posted by 양승아
:

trim();

문자열에 공백에 포함된 경우 제거해야 할때가 있는데 

String 클래스에 trim() 이라는 함수를 사용한다.


앞뒤 공백 제거시

 결과 : "테스트"

=> 앞뒤 공백만 제거됨




문자열의 앞 공백만 제거시

결과 : "test test "





문자열의 뒤 공백만 제거시 

결과 : " test test"





문자열 모든 공백 제거시



'JAVA > JAVA' 카테고리의 다른 글

클라이언트 ip 구하기  (0) 2015.08.13
java foreach 반복문  (0) 2015.08.13
[java] URL(xml파일) java 파싱하는 방법  (0) 2015.08.12
예외처리  (0) 2015.07.31
인터페이스와 다형성  (0) 2015.07.31
Posted by 양승아
: