development

제네릭 클래스의 정적 메소드?

big-blog 2020. 5. 14. 20:42
반응형

제네릭 클래스의 정적 메소드?


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

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

그러나 나는 얻는다

비 정적 유형 T에 대한 정적 참조를 만들 수 없습니다

기본 용도 이외의 제네릭을 이해하지 못하므로 이해가되지 않습니다. 인터넷에서 주제에 관한 많은 정보를 찾을 수 없었습니다.

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


정적 메소드 또는 정적 필드에는 클래스의 일반 유형 매개 변수를 사용할 수 없습니다. 클래스의 유형 매개 변수는 인스턴스 메소드 및 인스턴스 필드에만 적용됩니다. 정적 필드와 정적 메소드의 경우 클래스의 모든 인스턴스, 다른 유형 매개 변수의 인스턴스간에 공유되므로 특정 유형 매개 변수에 의존 할 수 없습니다.

문제가 클래스의 type 매개 변수를 사용해야하는 것처럼 보이지 않습니다. 당신이하려는 일을 더 자세하게 설명한다면, 우리는 당신이 그것을하는 더 좋은 방법을 찾도록 도울 수 있습니다.


Java는 T유형을 인스턴스화 할 때까지 무엇을 알지 못합니다 .

어쩌면 호출하여 정적 메소드를 실행할 수 Clazz<T>.doit(something)있지만 할 수없는 것처럼 들립니다.

일을 처리하는 다른 방법은 type 매개 변수를 메서드 자체에 넣는 것입니다.

static <U> void doIt(U object)

U에 대한 올바른 제한은 없지만 아무것도 아닌 것보다 낫습니다 ....


나는이 같은 문제에 부딪쳤다. Collections.sortJava 프레임 워크에서 소스 코드를 다운로드하여 답변을 찾았습니다 . 내가 사용한 대답 <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>사이 staticvoid추가 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);
  }
}

콘솔을 실행할 때 다음 줄을 콘솔에 인쇄합니다.

그 전리품을 흔들어 'class com.eclipseoptions.datamanager.Clazz $ KC'!!!
그 전리품을 흔들어 'class 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는 phone, pager 및 pc에서 공유되므로 실제 os 유형은 무엇입니까? 스마트 폰, 호출기 및 TabletPC 일 수는 없습니다. 따라서 매개 변수 유형의 정적 필드를 작성할 수 없습니다.

chris의 대답 에서 올바르게 지적 했듯이이 경우 클래스가 아닌 메소드와 함께 유형 매개 변수를 사용해야합니다. 다음과 같이 작성할 수 있습니다.

static <E> void doIt(E object) 

다른 사람들은 이미 귀하의 질문에 대답했지만 O'Reilly Java Generics 책을 철저히 추천 할 수 있습니다 . 때로는 미묘하고 복잡한 주제이며, 무의미한 제한이있는 것처럼 보이지만이 책은 왜 자바 제네릭이 왜 그런지를 설명하는 꽤 잘 작동합니다.


다음과 같은 것이 당신을 더 가깝게 할 것입니다

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());
    }
}

When you specify a generic type for your class, JVM know about it only having an instance of your class, not definition. Each definition has only parametrized type.

Generics work like templates in C++, so you should first instantiate your class, then use the function with the type being specified.


Also to put it in simple terms, it happens because of the "Erasure" property of the generics.Which means that although we define ArrayList<Integer> and ArrayList<String> , at the compile time it stays as two different concrete types but at the runtime the JVM erases generic types and creates only one ArrayList class instead of two classes. So when we define a static type method or anything for a generic, it is shared by all instances of that generic, in my example it is shared by both ArrayList<Integer> and ArrayList<String> .That's why you get the error.A Generic Type Parameter of a Class Is Not Allowed in a Static Context!


@BD at Rivenhill: Since this old question has gotten renewed attention last year, let us go on a bit, just for the sake of discussion. The body of your doIt method does not do anything T-specific at all. Here it is:

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

So you can entirely drop all type variables and just code

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

Ok. But let's get back closer to the original problem. The first type variable on the class declaration is redundant. Only the second one on the method is needed. Here we go again, but it is not the final answer, yet:

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";
      }
}

However, it's all too much fuss about nothing, since the following version works just the same way. All it needs is the interface type on the method parameter. No type variables in sight anywhere. Was that really the original problem?

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";
      }
}

Since static variables are shared by all instances of the class. For example if you are having following code

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

T is available only after an instance is created. But static methods can be used even before instances are available. So, Generic type parameters cannot be referenced inside static methods and variables

참고URL : https://stackoverflow.com/questions/936377/static-method-in-a-generic-class

반응형