자바 제너릭 질문입니다...

cleol의 이미지

첫번째...

interface A<T>
{
	public T method();
}

class C implements A<String>
{
	public String method() //type safety 경고, eclipse3.1 m4
	{
		return "Hello";
	}
}

Sun 의 컴파일러는 위 코드에 대해 아무런 에러, 경고도 내지 않습니다. 그런데 이클립스 3.1 M4 의 컴파일러는 type safety 경고를 내는군요. 3.1 M4 에 대한 new and noteworthy 를 보면 java 5.0 에 대한 구현을 완료했다고 되어있던데... 굳이 경고를 내야할 상황이 아니라고 보는데 경고가 수두룩하니 나오니 기분이 안좋네요. 혹시 이클립스에서 이 경고를 제거할 수 있는 설정이 있는지 궁금합니다. 컴파일러 설정을 아무리 뒤져도 제 눈에는 안 띄네요.

두번쨰...


interface API
{
}

class APIImpl implements API
{
}

class C
{
	public List<API> method()
	{
		return new List<APIImpl>(); // 컴파일 에러 !!
		return (List<API>) (List<? extends API>) new List<APIImpl>();
	}
}

라이브러리나 프레임워크를 제작한다고 합시다. 인터페이스 API 가 있고 이를 구현한 APIImpl 클래스가 있습니다. 라이브러리의 사용자에게는 단지 API 인터페이스만을 보여주려고 합니다. APIImpl 에 대해서는 전혀 몰라도 되도록말입니다. 하지만 라이브러리 내부적으로는 APIImpl 를 직접 사용해야만 하는 경우도 있습니다. 이런 경우에 어떤 메소드에서 사용자에게 API의 컬렉션을 반환하도록 하고 싶습니다. 하지만 내부 처리를 위해 실제로는 APIImpl 의 컬렉션을 내부적으로 사용하다가 반환하는거지요. 그러려면 위 코드처럼 두번의 캐스트를 해야 합니다... 코드가 흉합니다.-_-; 뭔가 좋은 방법이나 패턴이 없는지 궁금하네요..

pool007의 이미지

첫번째 경우는 굳이 String에 대해서만 처리를 해야할 필요가 있을런지
의문입니다. generics는 parameterized polymorphism이고,
타입에 대해서는 일반적인 코드가 나와야할 것 같은데요..
상황을 다시 잘 설정해보세요..

두번째경우는, 역시 APIImpl을 리턴할 필요가 애초에 없을 것 같습니다.
내부에서도 API에 대한 리스트를 사용하면 되죠..

import java.util.*;

interface API 
{ 
   public void foo();
} 

class APIImpl implements API 
{ 
   public void foo()
   {
      System.out.println("foo");
   }
} 

class C 
{ 
   private List<API> list;
   public C()
   {
    
      list = new ArrayList<API>();
      list.add(new APIImpl());
      list.add(new APIImpl());
   }
   public List<API> method() 
   { 
      return list;
   } 


   public static void main(String[] args)
   {
       C c = new C();
       List<API> items = c.method();

       for (API a: items)
       {
          a.foo();
       }
   }
} 

이런 작업을 원하시는게 아닌지요?

--
Passion is like genius; a miracle.

cleol의 이미지

첫번째 경우는 C++ 로 치자면 "템플릿 특화" 를 하고 싶은 상황입니다. 각 타입에 따라 구현이 달라지지만 A.method 라는 인터페이스를 유지하고 싶은거지요.

두번째는 내부적으로 API 인터페이스를 사용할 수 없어서 그럽니다. 예를 들어


package tmp.api

interface API
{
	public method();
}


package tmp.api.impl

class APIImpl implements API
{
	public method()
	{
		//~~
	}

	//내부적인 구현과 관계된 메소드. 라이브러리 사용자들에게는 알려질 필요가 없지만
	//라이브러리 구현부분의 다른 클래스들에게 알려져야하는 메소드.
	public intrnalMethodForImpls()
	{
		//~~
	}
}


package tmp.api.impl

class C 
{ 
	private List<API> list; 

	public C() 
	{ 
		list = new ArrayList<API>(); 

		APIImpl a = new APIImpl();
		a.intrnalMethodForImpls();

		list.add(a); 
	} 

	public List<API> method() 
	{ 
		return new List<APIImpl>(); // 컴파일 에러 !! 
		return (List<API>) (List<? extends API>) new List<APIImpl>();
	} 
} 

이런 상황입니다. 제너릭을 사용하기 전에는 별로 고민할 필요가 없는 문제였는데 제너릭을 사용함으로 인해 위와 같은 캐스트가 발생하게 되서 깔끔한 방법을 찾는 중입니다.

atie의 이미지

첫번째 것은 eclipse의 noteworthy를 보면 옵션이 있었던 것 같으니, 찾아보세요. (확실치는 않습니다.)
그리고, 두번째 것은 JVM에서는 다른 리턴 타입을 가지는 메쏘드를 오버라이딩하는 것을 지원하지 않습니다. 컴파일러에 의해서 지원이 되므로 하신 것처럼 캐스팅을 해주어야 합니다. 좋은 방법은, 가능하다면 기존의 api 메쏘드를 와일드 카드나 제너릭 메쏘드를 써서 변경을 해주는 편이 나을 듯 합니다.

----
I paint objects as I think them, not as I see them.
atie's minipage

pool007의 이미지

이걸 원하시는게 아닌가요?

import java.util.*;

interface API
{
	public void method();
}


class APIImpl implements API
{
	public void method()
	{
		//~~
	}

	//내부적인 구현과 관계된 메소드. 라이브러리 사용자들에게는 알려질 필요가 없지만
	//라이브러리 구현부분의 다른 클래스들에게 알려져야하는 메소드.
	public void intrnalMethodForImpls()
	{
		//~~
	}
}


class C 
{ 
	private List<API> list; 

	public C() 
	{ 
		list = new ArrayList<API>(); 

		APIImpl a = new APIImpl();
		a.intrnalMethodForImpls();

		list.add(a); 
	} 

	public List<API> method() 
	{ 
		return list;
	} 
} 

C는 APIImpl을 알고 있습니다. C가 APIImpl을 생성하기 때문이죠. 따라서 확실히 APIImpl인걸 알기 때문에 C는 리스트가 API 타입이어도 그걸 꺼내서 다시 다운캐스팅 할 수 있습니다.

보여주신 코드에서는 method에서 new List<APIImpl>를 리턴할 경우, 단지 빈 리스트만 반환됩니다. 그런작업이 필요할런지요..
클라이언트는 APIImpl이 아닌 API에 대한 리스트를 기대하고 있고, 보여주신 코드에서 어떠한 APIImpl 리스트의 필요도 없는데요...

APIImpl 이 필요한 이유는 그 이름인 Impl에서 드러나듯이 API의 인터페이스를 구현합니다. 그리고 클라이언트는 API에 정의된 메소드만 호출할 것입니다.

APIImpl에만 정의된 함수를 사용할 수 있는 곳은 C입니다. C만 APIImpl이란 객체를 다루고 있음을 알기 때문이죠. 그리고 APIImpl에 특화된 메소드는 분명히 초기화 작업정도에서만 사용되고 말 것입니다. (그게 아니라면 API에서 정의된 함수인 method에서 APIImpl에 특화된 함수를 부르겠죠 - 즉, 아무런 문제가 없겠죠.) 그리고 그 초기화에만 관계된 함수는 제 생각에는 분명히 APIImpl의 생성자에서 호출하는 것으로 대신할 수 있을 거라 생각되네요..

즉, 그런 캐스팅이 필요없다는 얘기입니다...

단지 기술적인 측면에서 캐스팅을 어떻게 해야하나에만 초점을 맞춘다면, 기술하신 코딩은 잘하신 것 같아요.

그럼...

--
Passion is like genius; a miracle.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.