Related
This question already has an answer here:
Why can I override a static interface method?
(1 answer)
Closed 1 year ago.
Consider the following snippet:
interface Super{
public static void doIt(){}
}
class Sub implements Super{
public void doIt(){}
}
Here I have declared a static member method and it is being redeclared as the instance method in the child class.
This is allowed by the compiler - but when I do the same with the superclass and subclass types - this gives compilation error:
class Super{
public static void doIt(){}
}
class Sub extends Super{
public void doIt(){}
}
What is the rationale behind the same? - ideally the way to access the subclass is essentially the same - then why this restriction?
The reason for this is that Java allows invoking static methods in a non-static manner. Consider this example:
public class MyClass {
public static void sayHello() {
}
public void test() {
this.sayHello();
}
}
This will produce a compiler warning (The static method sayHello() from the type MyClass should be accessed in a static way), but it will compile and invoke the static method correctly at runtime.
That's why the following code will not compile because of an ambiguity (Duplicate method test() in type MyClass):
public class MyClass {
public static void test() {
}
public void test() {
}
}
The reason for the compile error is, that if you write the following, the compiler cannot know which method to invoke, because it allows to call static methods in a non-static manner:
public class MyClass {
public static void test() {
}
public void test() {
}
public void execute() {
this.test();
}
}
For the same reason it is not possible to have the static test() method in the parent class - the same rules apply. It is possible in Java to call static methods of super classes with or without qualification:
public class Super {
public static void test() {
}
}
public class Sub extends Super {
public void execute() {
this.test();
}
}
OR
public class Sub {
public void execute() {
test();
}
}
where the invocation of this.test() will produce a warning, but will work at runtime.
For static methods in interfaces, the above example will not work, because the compiler forces you to call the static method of the interface in a qualified manner (edit: because they are not being inherited). The following will not work (The method interfaceStatic() is undefined for the type Sub):
public interface Interface {
public static void interfaceStatic() {
}
}
public class Sub implements Interface {
public void test() {
interfaceStatic();
}
}
In order to call interfaceStatic() the invocation has to be qualified like this:
public class Sub implements Interface {
public void test() {
Interface.interfaceStatic();
}
}
That's the difference between defining the static method in an interface and defining it in the super class: The way of invocation. If you implement multiple interfaces which all have a static method with the same signature, the compiler cannot know which one to call.
This is the reason why it is allowed to define a static method with the same signature in an implemented interface, but not in the parent classes.
I have the following example:
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
A<ConcreteErrorHandler> a = new A<ConcreteErrorHandler>();
a.m(); //Exception here!
}
public static class AbstractErrorHandler {
public static void handle(){
throw new UnsupportedOperationException("Not implemented");
}
}
public static class ConcreteErrorHandler extends AbstractErrorHandler{
public static void handle(){
System.out.println("Concrete handler");
}
}
public static class A<T extends AbstractErrorHandler>{
public void m(){
T.handle();
}
}
}
IDEONE
Why the method of the base class is called, but not of the derived? The signatures of the handle() methods are perfectly the same. I know that static methods don't inherit, but shouldn't a compile-time error be thrown in my case then?
Could someone explain that behavior?
The reason for this is that the compiler doesn't know which exact subtype of AbstractErrorHandler will be replacing T at Runtime. That's why it just binds the method call T.handle() to the AbstractErrorHandler.handle() method.
The problem here is that you're mixing inheritance with the static features of the classes in Java.
In order to have this working (correctly), you have to get rid of the static modifier for the .handle() methods and keep an instance of T in the A class. This T instance (at Runtime) will be some specific subclass of AbstractErrorHandler and then the actual .handle() method will be executed.
For example:
class Ideone {
public static void main(String[] args) throws java.lang.Exception {
A<ConcreteErrorHandler> a = new A<ConcreteErrorHandler>(new ConcreteErrorHandler());
a.m();
}
public static class AbstractErrorHandler {
public void handle() {
throw new UnsupportedOperationException("Not implemented");
}
}
public static class ConcreteErrorHandler extends AbstractErrorHandler {
public void handle() {
System.out.println("Concrete handler");
}
}
public static class A<T extends AbstractErrorHandler> {
T instance;
A(T instance) {
this.instance = instance;
}
public void m() {
instance.handle();
}
}
}
4.4. Type Variables tells us that:
The members of a type variable X with bound T & I1 & ... & In are the members of the intersection type T & I1 & ... & In appearing at the point where the type variable is declared.
Therefore the members of T extends AbstractErrorHandler are the members of AbstractErrorHandler. T.handle(); refers to AbstractErrorHandler.handle();.
The erasure of a bounded type parameter is the bound (and in the case of a bound intersection, the first type in the bound). So in your case, T extends AbstractErrorHandler is erased to AbstractErrorHandler and your method is effectively replaced by:
public void m() { AbstractErrorHandler.handle(); }
See for example JLS 4.6
The erasure of a type variable (ยง4.4) is the erasure of its leftmost bound.
Because basically your method m will be compiled into
public void m(){
AbstractErrorHandler.handle();
}
I believe it is because static is class scoped and you are telling the compiler to use AbstractErrorHandler implicitly by using T extends AbstractErrorHandler.
The runtime will assume the highest class level since type erasure occurs at runtime.
The implementation of m only uses T which is an AbstractErrorHandler, despite the fact you declared it to be the concrete type in the main method, which is not in the scope of the m method.
Java compiler erases all type parameters in generic code, you cannot verify which parameterized type for a generic type is being used at runtime. Therefore upper bound type AbstractErrorHandler is used.
see for more details: https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html
The reason is because you are using generics and java static methods that are hidden not overriden. At compile time the only know information is the AbstractErrorHandler class (generics works at a compile time in java, there is no bytecode with generics information) and the method called is the one of the class.
If you change the method handle form static to "instance" the implementation called is the "right" one (because the method is overridden not hidden )as in the example below .
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
A<AbstractErrorHandler> a = new A<AbstractErrorHandler>();
a.m(new ConcreteErrorHandler()); //Exception here!
}
public static class AbstractErrorHandler {
public void handle(){
throw new UnsupportedOperationException("Not implemented");
}
}
public static class ConcreteErrorHandler extends AbstractErrorHandler{
public void handle(){
System.out.println("Concrete handler");
}
}
public static class A<T extends AbstractErrorHandler>{
public void m(T t){
t.handle();
}
}
}
My problem can be summed-up by this snippet:
public interface TheClass<T> {
public void theMethod(T obj);
}
public class A {
private TheClass<?> instance;
public A(TheClass<?> instance) {
this.instance = instance;
}
public void doWork(Object target) {
instance.theMethod(target); // Won't compile!
// However, I know that the target can be passed to the
// method safely because its type matches.
}
}
My class A uses an instance of TheClass with its generics type unknown. It features a method with a target passed as Object since the TheClass instance can be parameterized with any class. However, the compiler won't allow me to pass the target like this, which is normal.
What should I do to circumvent this issue?
A dirty solution is to declare the instance as TheClass<? super Object>, which works fine but is semantically wrong...
Another solution I used before was to declare the instance as raw type, just TheClass, but it's bad practice, so I want to correct my mistake.
Solution
public class A {
private TheClass<Object> instance; // type enforced here
public A(TheClass<?> instance) {
this.instance = (TheClass<Object>) instance; // cast works fine
}
public void doWork(Object target) {
instance.theMethod(target);
}
}
public class A {
private TheClass<Object> instance;
public A(TheClass<Object> instance) {
this.instance = instance;
}
public void do(Object target) {
instance.theMethod(target);
}
}
or
public class A<T> {
private TheClass<T> instance;
public A(TheClass<T> instance) {
this.instance = instance;
}
public void do(T target) {
instance.theMethod(target);
}
}
The solution is to also type A. Using a wildcard ? makes you loose the type information of TheClass and there is no way to recover it later. There are some ugly hacks you could do but your best shot is to also type A:
public interface TheClass<T> {
public void theMethod(T obj);
}
public class A<T> {
private TheClass<T> instance;
public A(TheClass<T> instance) {
this.instance = instance;
}
public void doIt(T target) {
instance.theMethod(target);
}
}
It won't break any API either.
The reason for the compile error is that the ? wildcard indicates the unknown type in Java. You may declare a variable with an unknown generic parameter, but you cannot instantiate one with it. Which means that the in your constructor the passed in generic class could have been created to hold types that are incompatible with what you are trying to later on use. Case in point:
public class A {
public static void main(String[] args) {
TheClass<String> stringHolder = null; // should constrain parameters to strings
A a = new A(stringHolder);
a.donot(Float.valueOf(13)) ; // this is an example of what could happen
}
private TheClass<?> instance;
public A(TheClass<?> instance) {
this.instance = instance;
}
public void do(Object target) {
instance.theMethod(target);
}
}
In this case the compiler is preventing you from writing code that would have been prone to bugs. As others have pointed out, you should add a generic parameter type to your A class, in order to constrain the allowed types - that will remove the compile time error.
Some suggested reading: Oracle Generics Trail
I am a Java developer. In an interview I was asked a question about private constructors:
Can you access a private constructor of a class and instantiate it?
I answered 'No' but was wrong.
Can you explain why I was wrong and give an example of instantiating an object with a private constructor?
One way to bypass the restriction is to use reflections:
import java.lang.reflect.Constructor;
public class Example {
public static void main(final String[] args) throws Exception {
Constructor<Foo> constructor = Foo.class.getDeclaredConstructor();
constructor.setAccessible(true);
Foo foo = constructor.newInstance();
System.out.println(foo);
}
}
class Foo {
private Foo() {
// private!
}
#Override
public String toString() {
return "I'm a Foo and I'm alright!";
}
}
You can access it within the class itself (e.g. in a public static factory method)
If it's a nested class, you can access it from the enclosing class
Subject to appropriate permissions, you can access it with reflection
It's not really clear if any of these apply though - can you give more information?
This can be achieved using reflection.
Consider for a class Test, with a private constructor:
Constructor<?> constructor = Test.class.getDeclaredConstructor(Context.class, String[].class);
Assert.assertTrue(Modifier.isPrivate(constructor.getModifiers()));
constructor.setAccessible(true);
Object instance = constructor.newInstance(context, (Object)new String[0]);
The very first question that is asked regarding Private Constructors in Interviews is,
Can we have Private constructor in a Class?
And sometimes the answer given by the candidate is, No we cannot have private constructors.
So I would like to say, Yes you can have private Constructors in a class.
It is no special thing, try to think it this way,
Private: anything private can be accessed from within the class only.
Constructor: a method which has same name as that of class and it is implicitly called when object of the class is created.
or you can say, to create an object you need to call its constructor, if constructor is not called then object cannot be instantiated.
It means, if we have a private constructor in a class then its objects can be instantiated within the class only. So in simpler words you can say, if the constructor is private then you will not be able to create its objects outside the class.
What's the benefit
This concept can be implemented to achieve singleton object (it means only one object of the class can be created).
See the following code,
class MyClass{
private static MyClass obj = new MyClass();
private MyClass(){
}
public static MyClass getObject(){
return obj;
}
}
class Main{
public static void main(String args[]){
MyClass o = MyClass.getObject();
//The above statement will return you the one and only object of MyClass
//MyClass o = new MyClass();
//Above statement (if compiled) will throw an error that you cannot access the constructor.
}
}
Now the tricky part, why you were wrong, as already explained in other answers, you can bypass the restriction using Reflection.
I like the answers above, but there are two more nifty ways of creating a new instance of a class which has private constructor. It all depends on what you want to achieve and under what circumstances.
1: Using Java instrumentation and ASM
Well in this case you have to start the JVM with a transformer. To do this you have to implement a new Java agent and then make this transformer change the constructor for you.
First create the class transformer. This class has a method called transform. Override this method and inside this method you can use the ASM class reader and other classes to manipulate the visibility of your constructor. After the transformer is done, your client code will have access to the constructor.
You can read more about this here: Changing a private Java constructor with ASM
2: Rewrite the constructor code
Well, this is not really accessing the constructor, but still you can create an instance. Let's assume that you use a third-party library (let's say Guava) and you have access to the code but you don't want to change that code in the jar which is loaded by the JVM for some reason (I know, this is not very lifelike but let's suppose the code is in a shared container like Jetty and you can't change the shared code, but you have separate class loading context) then you can make a copy of the 3rd party code with the private constructor, change the private constructor to protected or public in your code and then put your class at the beginning of the classpath. From that point your client can use the modified constructor and create instances.
This latter change is called a link seam, which is a kind of seam where the enabling point is the classpath.
Using java Reflection as follows :
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Test
{
private Test() //private constructor
{
}
}
public class Sample{
public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
{
Class c=Class.forName("Test"); //specify class name in quotes
//----Accessing private constructor
Constructor con=c.getDeclaredConstructor();
con.setAccessible(true);
Object obj=con.newInstance();
}
}
Yes you could, as mentioned by #Jon Steet.
Another way of accessing a private constructor is by creating a public static method within this class and have its return type as its object.
public class ClassToAccess
{
public static void main(String[] args)
{
{
ClassWithPrivateConstructor obj = ClassWithPrivateConstructor.getObj();
obj.printsomething();
}
}
}
class ClassWithPrivateConstructor
{
private ClassWithPrivateConstructor()
{
}
public void printsomething()
{
System.out.println("HelloWorld");
}
public static ClassWithPrivateConstructor getObj()
{
return new ClassWithPrivateConstructor();
}
}
You can of course access the private constructor from other methods or constructors in the same class and its inner classes. Using reflection, you can also use the private constructor elsewhere, provided that the SecurityManager is not preventing you from doing so.
Yes, we can access the private constructor or instantiate a class with private constructor. The java reflection API and the singleton design pattern has heavily utilized concept to access to private constructor.
Also, spring framework containers can access the private constructor of beans and this framework has used java reflection API.
The following code demonstrate the way of accessing the private constructor.
class Demo{
private Demo(){
System.out.println("private constructor invocation");
}
}
class Main{
public static void main(String[] args){
try{
Class class = Class.forName("Demo");
Constructor<?> con = string.getDeclaredConstructor();
con.setAccessible(true);
con.newInstance(null);
}catch(Exception e){}
}
}
output:
private constructor invocation
I hope you got it.
I hope This Example may help you :
package MyPackage;
import java.lang.reflect.Constructor;
/**
* #author Niravdas
*/
class ClassWithPrivateConstructor {
private ClassWithPrivateConstructor() {
System.out.println("private Constructor Called");
}
}
public class InvokePrivateConstructor
{
public static void main(String[] args) {
try
{
Class ref = Class.forName("MyPackage.ClassWithPrivateConstructor");
Constructor<?> con = ref.getDeclaredConstructor();
con.setAccessible(true);
ClassWithPrivateConstructor obj = (ClassWithPrivateConstructor) con.newInstance(null);
}catch(Exception e){
e.printStackTrace();
}
}
}
Output:
private Constructor Called
Reflection is an API in java which we can use to invoke methods at runtime irrespective of access specifier used with them.
To access a private constructor of a class:
My utility class
public final class Example{
private Example(){
throw new UnsupportedOperationException("It is a utility call");
}
public static int twice(int i)
{
int val = i*2;
return val;
}
}
My Test class which creates an object of the Utility class(Example)
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
class Test{
public static void main(String[] args) throws Exception {
int i =2;
final Constructor<?>[] constructors = Example.class.getDeclaredConstructors();
constructors[0].setAccessible(true);
constructors[0].newInstance();
}
}
When calling the constructor it will give the error
java.lang.UnsupportedOperationException: It is a utility call
But remember using reflection api cause overhead issues
Look at Singleton pattern. It uses private constructor.
Yes you can instantiate an instance with a private constructor using Reflection, see the example I pasted below taken from java2s to understand how:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Deny {
private Deny() {
System.out.format("Deny constructor%n");
}
}
public class ConstructorTroubleAccess {
public static void main(String... args) {
try {
Constructor c = Deny.class.getDeclaredConstructor();
// c.setAccessible(true); // solution
c.newInstance();
// production code should handle these exceptions more gracefully
} catch (InvocationTargetException x) {
x.printStackTrace();
} catch (NoSuchMethodException x) {
x.printStackTrace();
} catch (InstantiationException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
}
}
}
The basic premise for having a private constructor is that having a private constructor restricts the access of code other than own class' code from making objects of that class.
Yes we can have private constructors in a class and yes they can be made accessible by making some static methods which in turn create the new object for the class.
Class A{
private A(){
}
private static createObj(){
return new A();
}
Class B{
public static void main(String[]args){
A a=A.createObj();
}}
So to make an object of this class, the other class has to use the static methods.
What is the point of having a static method when we are making the constructor private?
Static methods are there so that in case there is a need to make the instance of that class then there can be some predefined checks that can be applied in the static methods before creation of the instance. For example in a Singleton class, the static method checks if the instance has already been created or not. If the instance is already created then it just simply returns that instance rather than creating a new one.
public static MySingleTon getInstance(){
if(myObj == null){
myObj = new MySingleTon();
}
return myObj;
}
We can not access private constructor outside the class but using Java Reflection API we can access private constructor. Please find below code:
public class Test{
private Test()
System.out.println("Private Constructor called");
}
}
public class PrivateConsTest{
public void accessPrivateCons(Test test){
Field[] fields = test.getClass().getDeclaredFields();
for (Field field : fields) {
if (Modifier.isPrivate(field.getModifiers())) {
field.setAccessible(true);
System.out.println(field.getName()+" : "+field.get(test));
}
}
}
}
If you are using Spring IoC, Spring container also creates and injects object of the class having private constructor.
I tried like this it is working. Give me some suggestion if i am wrong.
import java.lang.reflect.Constructor;
class TestCon {
private TestCon() {
System.out.println("default constructor....");
}
public void testMethod() {
System.out.println("method executed.");
}
}
class TestPrivateConstructor {
public static void main(String[] args) {
try {
Class testConClass = TestCon.class;
System.out.println(testConClass.getSimpleName());
Constructor[] constructors = testConClass.getDeclaredConstructors();
constructors[0].setAccessible(true);
TestCon testObj = (TestCon) constructors[0].newInstance();
//we can call method also..
testObj.testMethod();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Simple answer is yes we can have private constructors in Java.
There are various scenarios where we can use private constructors. The major ones are
Internal Constructor chaining
Singleton class design pattern
Also have another option create the getInstance() where we can create instance of private constructor inside same class and return that object.
class SampleClass1{
private SampleClass1() {
System.out.println("sample class constructor");
}
public static SampleClass1 getInstance() {
SampleClass1 sc1 = new SampleClass1();
return sc1;
}
}
public class SingletonDemo {
public static void main(String[] args) {
SampleClass1 obj1 = SampleClass1.getInstance();
}
}
We can create instance of private class by creating createInstance() in the same class and simply call the same method by using class name in main():
class SampleClass1{
private SampleClass1() {
System.out.println("sampleclass cons");
}
public static void createInstance() {
SampleClass1 sc = new SampleClass1();
}
}
public class SingletonDemo {
public static void main(String[] args) {
//SampleClass1 sc1 = new SampleClass1();
SampleClass1.createInstance();
}
}
Well, you can also if there are any other public constructors. Just because the parameterless constructor is private doesn't mean you just can't instantiate the class.
you can access it outside of the class its very easy to access
just take an example of singaltan class we all does the same thing make the private constructor and access the instance by static method here is the code associated to your query
ClassWithPrivateConstructor.getObj().printsomething();
it will definately work because i have already tested
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?
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.
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....
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
}
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.
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' !!!
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<T> {
private static T os;
// ...
}
If static fields of type parameters were allowed, then the following code would be confused:
MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> 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)
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());
}
}
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
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";
}
}
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
}