문제

Java에서는 다음과 같은 것을 갖고 싶습니다.

class Clazz<T> {
  static void doIt(T object) {
    // shake that booty
  }
}

하지만 나는 얻는다

Cannot make a static reference to the non-static type T

나는 기본 용도 이상의 제네릭을 이해하지 못하므로 그에 대해 많은 의미를 가질 수 없습니다.인터넷에서 해당 주제에 대한 많은 정보를 찾을 수 없었다는 것은 도움이 되지 않습니다.

비슷한 방식으로 그러한 사용이 가능한지 누군가가 명확히 할 수 있습니까?또한 원래 시도가 실패한 이유는 무엇입니까?

도움이 되었습니까?

해결책

정적 메소드 또는 정적 필드에서 클래스의 일반 유형 매개 변수를 사용할 수 없습니다. 클래스의 유형 매개 변수는 예를 들어 메소드 및 인스턴스 필드의 범위에 있습니다. 정적 필드 및 정적 방법의 경우 클래스의 모든 인스턴스, 다른 유형 매개 변수의 인스턴스까지 공유되므로 특정 유형 매개 변수에 의존 할 수는 없습니다.

클래스의 유형 매개 변수를 사용해야하는 문제가 아닌 것 같습니다. 당신이 당신이 무엇을하려고하는지 더 자세히 설명한다면, 더 나은 방법을 찾도록 도울 수 있습니다.

다른 팁

Java는 무엇을 모릅니다 T 유형을 인스턴스화 할 때까지입니다.

호출하여 정적 메소드를 실행할 수 있습니다 Clazz<T>.doit(something) 그러나 당신이 할 수없는 것 같습니다.

물건을 처리하는 다른 방법은 메소드 자체에 유형 매개 변수를 넣는 것입니다.

static <U> void doIt(U object)

당신에게 올바른 제한을 얻지는 못하지만 아무것도 아닌 것보다 낫습니다 ....

나는이 같은 문제에 부딪쳤다. 소스 코드를 다운로드하여 내 대답을 찾았습니다. Collections.sort Java 프레임 워크에서. 내가 사용한 대답은 <T> 클래스 정의가 아닌 방법의 일반적인.

그래서 이것은 효과가있었습니다.

public class QuickSortArray  {
    public static <T extends Comparable> void quickSort(T[] array, int bottom, int top){
//do it
}

}

물론, 위의 답변을 읽은 후 나는 이것이 일반적인 클래스를 사용하지 않고 허용 가능한 대안이라는 것을 깨달았습니다.

public static void quickSort(Comparable[] array, int bottom, int top){
//do it
}

선언 할 때 일반적인 방법에 구문을 사용하여 원하는 것을 수행 할 수 있습니다. doIt() 방법 (추가를 확인하십시오 <T> ~ 사이 static 그리고 void 방법 서명에서 doIt()):

class Clazz<T> {
  static <T> void doIt(T object) {
    // shake that booty
  }
}

나는 Eclipse 편집기가 위의 코드를 수락 할 수 있도록 Cannot make a static reference to the non-static type T 오류 후 다음 작업 프로그램으로 확장했습니다 (다소 연령에 맞는 문화적 참조로 완성) :

public class Clazz<T> {
  static <T> void doIt(T object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }

  private static class KC {
  }

  private static class SunshineBand {
  }

  public static void main(String args[]) {
    KC kc = new KC();
    SunshineBand sunshineBand = new SunshineBand();
    Clazz.doIt(kc);
    Clazz.doIt(sunshineBand);
  }
}

이 라인을 실행할 때이 라인을 콘솔에 인쇄합니다.

그 전리품 '클래스 com.eclipseoptions.datamanager.clazz $ kc'!!!
그 전리품 '클래스 com.eclipseoptions.datamanager.clazz $ sunshineband'!!!

이 구문은 아직 언급되지 않았다고 생각합니다 (인수가없는 메소드를 원하는 경우) :

class Clazz {
  static <T> T doIt() {
    // shake that booty
  }
}

그리고 전화 :

String str = Clazz.<String>doIt();

이것이 누군가를 도울 수 있기를 바랍니다.

오류에 올바르게 언급되어 있습니다. 비 정적 유형 T를 정적으로 참조 할 수 없습니다. 그 이유는 유형 매개 변수입니다. T 유형 인수로 대체 할 수 있습니다. Clazz<String> 또는 Clazz<integer> 등. 그러나 정적 필드/방법은 클래스의 모든 비 정적 객체와 공유됩니다.

다음 발췌문은 다음에서 가져옵니다 문서:

클래스의 정적 필드는 클래스의 모든 비 정적 객체가 공유하는 클래스 수준 변수입니다. 따라서 유형 파라미터의 정적 필드는 허용되지 않습니다. 다음 수업을 고려하십시오.

public class MobileDevice<T> {
    private static T os;

    // ...
}

유형 매개 변수의 정적 필드가 허용되면 다음 코드가 혼동됩니다.

MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();

정적 필드 OS는 전화, 호출기 및 PC로 공유되므로 실제 OS 유형은 얼마입니까? 스마트 폰, 호출기 및 tabletpc는 동시에 할 수 없습니다. 따라서 유형 매개 변수의 정적 필드를 만들 수 없습니다.

Chris가 그의 바로 지적했듯이 대답 이 경우 클래스가 아닌 메소드와 함께 유형 매개 변수를 사용해야합니다. 당신은 다음과 같이 쓸 수 있습니다.

static <E> void doIt(E object) 

다른 사람들은 이미 당신의 질문에 대답했지만, 또한 나는 O'Reilly를 철저히 추천 할 수 있습니다. 자바 제네릭 책. 그것은 때때로 미묘하고 복잡한 주제이며, 종종 무의미한 제한이있는 것처럼 보이지만,이 책은 왜 Java 제네릭이 그 방식인지 설명하는 데 아주 좋은 일을합니다.

다음과 같은 것이 당신을 더 가까이 갈 것입니다

class Clazz
{
   public static <U extends Clazz> void doIt(U thing)
   {
   }
}

편집 : 자세한 내용은 업데이트 된 예제입니다

public abstract class Thingo 
{

    public static <U extends Thingo> void doIt(U p_thingo)
    {
        p_thingo.thing();
    }

    protected abstract void thing();

}

class SubThingoOne extends Thingo
{
    @Override
    protected void thing() 
    {
        System.out.println("SubThingoOne");
    }
}

class SubThingoTwo extends Thingo
{

    @Override
    protected void thing() 
    {
        System.out.println("SuThingoTwo");
    }

}

public class ThingoTest 
{

    @Test
    public void test() 
    {
        Thingo t1 = new SubThingoOne();
        Thingo t2 = new SubThingoTwo();

        Thingo.doIt(t1);
        Thingo.doIt(t2);

        // compile error -->  Thingo.doIt(new Object());
    }
}

클래스의 일반 유형을 지정할 때 JVM은 정의가 아닌 클래스 인스턴스 만있는 것에 대해 알고 있습니다. 각 정의에는 매개 변수 유형 만 있습니다.

제네릭은 C ++의 템플릿처럼 작동하므로 먼저 클래스를 인스턴스화 한 다음 지정된 유형이있는 기능을 사용해야합니다.

또한 간단한 용어로 말하면 제네릭의 "지우기"속성 때문에 발생합니다. 이는 우리가 정의하지만 ArrayList<Integer> 그리고 ArrayList<String> 컴파일 시간에는 두 개의 다른 콘크리트 유형으로 유지되지만 런타임에는 JVM이 일반 유형을 지우고 두 클래스 대신 하나의 Arraylist 클래스 만 생성합니다. 따라서 우리가 정적 유형 방법이나 일반적인 방법을 정의 할 때, 그것은 그 제네릭의 모든 인스턴스와 공유되며, 내 예에서는 두 가지 모두가 공유합니다. ArrayList<Integer> 그리고 ArrayList<String> 그렇기 때문에 오류가 발생하는 이유입니다. 정적 컨텍스트에서 클래스의 일반 유형 매개 변수는 허용되지 않습니다!

Rivenhill의 @bd : 작년 에이 오래된 질문이 새로운 주목을 받았기 때문에 토론을 위해 조금 가십시오. 당신의 몸 doIt 방법은 아무것도하지 않습니다 T-전혀 특이 적. 여기있어:

public class Clazz<T> {
  static <T> void doIt(T object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }
// ...
}

따라서 모든 유형 변수를 완전히 삭제하고 코드 만

public class Clazz {
  static void doIt(Object object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }
// ...
}

확인. 그러나 원래의 문제에 더 가까이 다가 가자. 클래스 선언의 첫 번째 유형 변수는 중복됩니다. 방법의 두 번째 만 필요합니다. 여기서 우리는 다시 가지만 아직 최종 답변은 아닙니다.

public class Clazz  {
  static <T extends Saying> void doIt(T object) {
    System.out.println("shake that booty "+ object.say());
  }

  public static void main(String args[]) {
    Clazz.doIt(new KC());
    Clazz.doIt(new SunshineBand());
  }
}
// Output:
// KC
// Sunshine

interface Saying {
      public String say();
}

class KC implements Saying {
      public String say() {
          return "KC";
      }
}

class SunshineBand implements Saying {
      public String say() {
          return "Sunshine";
      }
}

그러나 다음 버전은 똑같은 방식으로 작동하기 때문에 아무것도 아닌 것에 대한 소란입니다. 필요한 것은 메소드 매개 변수의 인터페이스 유형입니다. 어디서나 유형 변수가 보이지 않습니다. 정말 원래 문제였습니까?

public class Clazz  {
  static void doIt(Saying object) {
    System.out.println("shake that booty "+ object.say());
  }

  public static void main(String args[]) {
    Clazz.doIt(new KC());
    Clazz.doIt(new SunshineBand());
  }
}

interface Saying {
      public String say();
}

class KC implements Saying {
      public String say() {
          return "KC";
      }
}

class SunshineBand implements Saying {
      public String say() {
          return "Sunshine";
      }
}

정적 변수는 클래스의 모든 인스턴스에서 공유되기 때문입니다.예를 들어 다음 코드가 있는 경우

class Class<T> {
  static void doIt(T object) {
    // using T here 
  }
}

T는 인스턴스가 생성된 후에만 사용할 수 있습니다.그러나 인스턴스를 사용할 수 있기 전에도 정적 메서드를 사용할 수 있습니다.따라서 일반 유형 매개변수는 정적 메소드 및 변수 내에서 참조될 수 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top