Static method in a generic class?

JavaGenericsStatic Methods

Java Problem Overview


In Java, I'd like to have something as:

class Clazz<T> {
  static void doIt(T object) {
    // ...
  }
}

But I get

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

I don't understand generics beyond the basic uses and thus can't make much sense of that. It doesn't help that I wasn't able to find much info on the internet about the subject.

Could someone clarify if such use is possible, by a similar manner? Also, why was my original attempt unsuccessful?

Java Solutions


Solution 1 - Java

You can't use a class's generic type parameters in static methods or static fields. The class's type parameters are only in scope for instance methods and instance fields. For static fields and static methods, they are shared among all instances of the class, even instances of different type parameters, so obviously they cannot depend on a particular type parameter.

It doesn't seem like your problem should require using the class's type parameter. If you describe what you are trying to do in more detail, maybe we can help you find a better way to do it.

Solution 2 - Java

Java doesn't know what T is until you instantiate a type.

Maybe you can execute static methods by calling Clazz<T>.doit(something) but it sounds like you can't.

The other way to handle things is to put the type parameter in the method itself:

static <U> void doIt(U object)

which doesn't get you the right restriction on U, but it's better than nothing....

Solution 3 - Java

I ran into this same problem. I found my answer by downloading the source code for Collections.sort in the java framework. The answer I used was to put the <T> generic in the method, not in the class definition.

So this worked:

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

}

Of course, after reading the answers above I realized that this would be an acceptable alternative without using a generic class:

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

Solution 4 - Java

I think this syntax has not been mentionned yet (in the case you want a method without arguments) :

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

And the call :

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

Hope this help someone.

Solution 5 - Java

It is possible to do what you want by using the syntax for generic methods when declaring your doIt() method (notice the addition of <T> between static and void in the method signature of doIt()):

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

I got Eclipse editor to accept the above code without the Cannot make a static reference to the non-static type T error and then expanded it to the following working program (complete with somewhat age-appropriate cultural reference):

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

Which prints these lines to the console when I run it:

> shake that booty 'class com.eclipseoptions.datamanager.Clazz$KC' !!!
> shake that booty 'class com.eclipseoptions.datamanager.Clazz$SunshineBand' !!!

Solution 6 - Java

It is correctly mentioned in the error: you cannot make a static reference to non-static type T. The reason is the type parameter T can be replaced by any of the type argument e.g. Clazz<String> or Clazz<integer> etc. But static fields/methods are shared by all non-static objects of the class.

The following excerpt is taken from the doc:

> A class's static field is a class-level variable shared by all > non-static objects of the class. Hence, static fields of type > parameters are not allowed. Consider the following class: >
> public class MobileDevice { > private static T os; >
> // ... > } >
If static fields of type parameters were allowed, then the following code would be confused: >
> MobileDevice phone = new MobileDevice<>(); > MobileDevice pager = new MobileDevice<>(); > MobileDevice pc = new MobileDevice<>(); >
Because the static field os is shared by phone, pager, and pc, what is the actual type of os? It cannot be Smartphone, Pager, and > TabletPC at the same time. You cannot, therefore, create static fields > of type parameters.

As rightly pointed out by chris in his answer you need to use type parameter with the method and not with the class in this case. You can write it like:

static <E> void doIt(E object) 

Solution 7 - Java

Something like the following would get you closer

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

EDIT: Updated example with more detail

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

Solution 8 - Java

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

Solution 9 - Java

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.

Solution 10 - Java

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!

Solution 11 - Java

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

Solution 12 - Java

T is not in the scope of the static methods and so you can't use T in the static method. You would need to define a different type parameter for the static method. I would write it like this:

class Clazz<T> {

  static <U> void doIt(U object) {
    // ...
  }

}

For example:

public class Tuple<T> {

    private T[] elements;

    public static <E> Tuple<E> of(E ...args){
        if (args.length == 0) 
             return new Tuple<E>();
        return new Tuple<E>(args);
    }

    //other methods
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndr&#233; ChalellaView Question on Stackoverflow
Solution 1 - JavanewacctView Answer on Stackoverflow
Solution 2 - JavaJason SView Answer on Stackoverflow
Solution 3 - JavaChrisView Answer on Stackoverflow
Solution 4 - JavaOreste VironView Answer on Stackoverflow
Solution 5 - JavaBD at RivenhillView Answer on Stackoverflow
Solution 6 - Javaakhil_mittalView Answer on Stackoverflow
Solution 7 - JavaekjView Answer on Stackoverflow
Solution 8 - JavaBharatView Answer on Stackoverflow
Solution 9 - JavaMarcin CylkeView Answer on Stackoverflow
Solution 10 - Javauser6288471View Answer on Stackoverflow
Solution 11 - JavaHubert KaukerView Answer on Stackoverflow
Solution 12 - JavaCheng ThaoView Answer on Stackoverflow