Conflicts of common Java classes and methods

I have a Generic Class Factory class that has two methods that use the common value of class T, and the other uses only its own definitions of the general methods of the method.

public class GenericClassFactory<T extends ClassMatchable> { public <E, K> E newObject(ClassMatcher<E, K> matcher, K key, String packageName){...} public <K> T newObject(K key, String packageName){...} } 

A method that uses T generic works fine, but when I want to use another method that does not care that T generic will not use Generic E, it just returns the object, and then I have to type cast it.

 Data data = new GenericClassFactory().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl"); 

This one has compilation errors because it wants me to attribute it (Data). If I pass the GenericClassFactory a valid Generic class, it will work. Its like he does not recognize the general methods of the method, if you have Generic Generic, but not used.

 Data data = new GenericClassFactory<ClassMatchable>().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl"); 

It works great. But it is stupid that I would have to define a class like the one when it is not needed for my purposes. I could do this:

 public class GenericClassFactory { public <E, K> E newObject(ClassMatcher<E, K> matcher, K key, String packageName){...} public <T extends ClassMatchable, K> T newObject(K key, String packageName){...} } 

But now my second method seems too broad or something ... maybe not. I mean, it will still give a compilation error if the object you assign to the return type does not implement ClassMatchable. So should I go? So I do not need to resort to type?

+2
source share
4 answers

That's right, if you do not type a link to a class, then even generic methods that use only method type parameters will not be generated. This is one of the weird nuances of Java Generics. As you say, you can enter an arbitrary type for T :

 Data data = new GenericClassFactory<ClassMatchable>().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl"); 

But it is more likely that this is not even an instance method. Isn't that a static method? If so, you can simply call it like this:

 Data data = GenericClassFactory.newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl"); 

Edit

Note that this applies to all members of the instance, not just the general methods of the instance. Thus, there are simpler cases that demonstrate this odd nuance. This code only compiles with warnings:

 public class Scratchpad<T> { List<String> list; public static void main(String[] args) { Scratchpad sp = new Scratchpad(); List<Integer> list = sp.list; } } 

And this is because sp.list allowed as List , not List<String> , although Scratchpad.list has nothing to do with T

This is described in detail in JLS, section 4.8 :

The type of constructor (§8.8), the instance method (§8.8, §9.4) or the non-static field (§8.3) M of the raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the general declaration corresponding to C. The type of static a member of raw type C is the same as its type in the general declaration corresponding to C.

+6
source

You must specify the actual types E and K when calling the method:

  new GenericClassFactory<ClassMatchable>().<TypeforE, TypeforK>newObject(...) 

It seems that Java cannot deduce it from the argument.

And of course:

It seems like it does not recognize the generic method if you have a Generic class but not used.

exactly true.

+1
source

As if it doesn’t recognize the general methods of the method, if you have Generic Generic but not used.

That's right. If you define a general constraint for a class, and then instantiate the class without providing any general constraints (i.e. you do not include <> ), then you have just entered the Raw Types area , where nothing happens.

Raw types exist only for backward compatibility. According to Angelika Langer, excellent Java Generics FAQs ,

Using source types in code written after introducing typicality into the Java programming language is not recommended. According to the Java language specification, it is possible that future versions of the Java programming language will prohibit the use of raw types.

He also states :

Raw type methods or constructors have a signature that they will have after deleting the type. Calling a method or constructor for a raw type generates an unchecked warning if erasing changes the types of arguments.

If the newObject() method does not use a parameter of type T for the class to which it belongs, then something is wrong with your design: most likely newObject() should be made a static method.

However, if for some reason this really should be an instance method, you can get it to work using the GenericClassFactory<?> Lookup type :

 GenericClassFactory<?> gcf = new GenericClassFactory(); Data data = gcf.newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl"); 
+1
source

Consider if T indeed a type parameter of a class or method. For example, is there something in the class that restricts the created T types (class level) or, perhaps, is used as a convenience to avoid casting result values ​​(method level).

From what you posted here, it seems to me that T should be a type of method and that your last example is the answer. The definition of a method does not seem too broad if the implementation of the class is general and can produce different types each time the method is called.

0
source

All Articles