답변:
정적 메소드 또는 정적 필드에는 클래스의 일반 유형 매개 변수를 사용할 수 없습니다. 클래스의 유형 매개 변수는 인스턴스 메소드 및 인스턴스 필드에만 적용됩니다. 정적 필드와 정적 메서드의 경우 클래스의 모든 인스턴스, 다른 유형 매개 변수의 인스턴스간에 공유되므로 특정 유형 매개 변수에 의존 할 수 없습니다.
문제가 클래스의 type 매개 변수를 사용해야하는 것처럼 보이지 않습니다. 당신이하려는 일을 더 자세하게 설명한다면, 우리는 당신이 그것을하는 더 좋은 방법을 찾도록 도울 수 있습니다.
Java는 T
유형을 인스턴스화 할 때까지 무엇을 알지 못합니다 .
어쩌면 호출하여 정적 메소드를 실행할 수 Clazz<T>.doit(something)
있지만 할 수없는 것처럼 들립니다.
일을 처리하는 다른 방법은 type 매개 변수를 메서드 자체에 넣는 것입니다.
static <U> void doIt(U object)
U에 대한 올바른 제한은 없지만 아무것도 아닌 것보다 낫습니다 ....
나는이 같은 문제에 부딪쳤다. 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
}
T extends XXX
구문 이 포함 된 예를 제공하기위한 소품 .
Comparable
. <T extends Comparable<? super T>>
대신 시도하십시오 .
메소드를 선언 할 때 일반 메소드의 구문을 사용하여 원하는 것을 수행 할 수 있습니다 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);
}
}
콘솔을 실행할 때 다음 줄을 콘솔에 인쇄합니다.
그 전리품을 흔들어 'class com.eclipseoptions.datamanager.Clazz $ KC'!!!
그 전리품을 흔들어 'class com.eclipseoptions.datamanager.Clazz $ SunshineBand'!!!
<T>
것과 같은 방식으로 첫 번째 마스크를 마스크합니다 . class C { int x; C(int x) { ... } }
x
x
static <E extends SomeClass> E foo(E input){return input;}
다음과 같은 일을하고 싶을 때 각각의 모든 방법에 대한 팬이 아닙니다static <E extends SomeClass>; //static generic type defined only once and reused
static E foo(E input){return input;}
static E bar(E input){return input;}
//...etc...
이 구문은 아직 언급되지 않았다고 생각합니다 (인수가없는 메소드를 원할 경우).
class Clazz {
static <T> T doIt() {
// shake that booty
}
}
그리고 전화 :
String str = Clazz.<String>doIt();
이것이 누군가를 돕기를 바랍니다.
<String>
변수에 할당하기 때문에 단순히 type 인수를 유추하기 때문에 가능하지 않습니다 . 할당하지 않으면 간단히 추론 Object
됩니다.
그것은 제대로 오류에서 언급 한 : 당신이 비 정적 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)
다음과 같은 것이 당신을 더 가깝게 할 것입니다
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 ++에서 템플릿과 같이 작동하므로 먼저 클래스를 인스턴스화 한 다음 지정된 유형의 함수를 사용해야합니다.
Clazz<int>::doIt( 5 )
)
또한 그것 때문에 우리가 정의하지만, 그 generics.Which 수단의 "소거"속성의 발생, 간단한 용어를 넣어 ArrayList<Integer>
및 ArrayList<String>
컴파일 시간에,이 두 가지 구체적인 유형으로 유지하지만 런타임시 JVM이 제네릭 형식 및 삭제됩니다 두 클래스 대신 하나의 ArrayList 클래스 만 만듭니다. 우리가 일반에 대한 정적 유형 방법 또는 아무것도를 정의 할 때, 그것은 그 일반의 모든 인스턴스에 의해 공유되고, 내 예에서 모두가 공유 ArrayList<Integer>
하고 ArrayList<String>
거긴 당신은 클래스하지 않음을의 error.A 제네릭 형식 매개 변수를 얻을 이유 정적 컨텍스트에서 허용됩니다!
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";
}
}