I have a method that usually takes an item from a list and has a signature of:
myMethod(T item)
I want to use this method but I know what I am sending the method.
SpecificItem myItem = new SpecificItem();
myMethod((T) myItem);
This doesn't sit well with me. Is this a sign of bad code?
myMethod is defined in a generic class, somewhat like:
public class MyClass<T> {
T myItem;
public void myMethod(T item) {
// do Something with item
}
public T myOtherMethod() {
myMethod(myItem); // casting is not necessary
return myItem;
}
}
If you instantiate this class, you exchange the variable type T with a real one:
MyClass<SpecificItem > concreteClass = new MyClass<SpecificItem >();
And if you call myMethod on this instance, you have to provide a SpecificItem, because SpecificItem is the generic type for this instance.
(I'm not sure it my post answers your question, please comment so I can improve it)
It's better that you code to interface. For example :
In myMethod :
<T extends <? super Item>> void (T item);
This tells compiler to only accepts a generic type of T which is an implementation/extention of Item interface/class. This will make sure that given input is in correct type. Compiler guarantees it.
In main class :
Item myItem = new SpecificItem();
Code given above is the best practice. Get used to it. But (i discourage this) you can code like this too :
SpecificItem myItem = new SpecificItem();
You can read Java source code. For example in class java.util.Collections. In method sort(List) you may notice that Joshua Bloch makes sure that given input is always in correct format. To give it a try, do this :
public class Class1 {
public static void main(String[] args) {
List<Class1> list = new ArrayList<Class1>();
Collections.sort(list);
}
}
Above code will produce compilation error. To fix this compilation error Class1 must implement interface Comparable. This maintains the precondition of method sort(List) which assumes that given input is a List of Comparable.
Oh i almost forget about your question. Actually it's not a bad code since it works. I just want to tell you that there is a better way to do that.
You might be looking for something like this:
class C<? extends T> {
public void myMethod(T myItem) {
...
}
}
The way you call the method looks strange. If you have declared your generic method as
public <T> void myMethod(T item);
the compiler knows, that T is some abstract type and you shouldn't need to cast an input parameter to it. Just make sure, that T is not declared as some specific type in your code.
upd: look here for an example: http://www.java2s.com/Tutorial/Java/0200__Generics/Usinggenericmethodstoprintarrayofdifferenttypes.htm
Probably better way would be to make SpecificItem a subclass of T or make T an interface and have SpecificItem implement it.
Related
I can't believe I cannot capture P without typing the class to a redundant 2-type class:
public class MyClass<T extends List<P>> {
T getList(/**/){}
P getRandomElement(){ /**/ }
}
Do I need, really, to define and instantiate MyClass as MyClass<String,ArrayList<String>>, couldn't it be inferred someway?
EDIT: What I mean is I see redundant having to define MyClass<P,T extends List<P>> because then I need to instantiate it always as MyClass<String,ArrayList<String>>, and carry String everywhere. It would be nice if the language allowed something like MyClass<L extends List<P>> or similar. That way, MyClass<ArrayList<String>> would return an ArrayList<String> when executing getList() and an String when executing getRandomElement(), nicely.
If you really must have the exact type of List returned from getList, then you need the type parameter T as well as P.
public class MyClass<P, T extends List<P>> {
This way you can have a MyClass<String, ArrayList<String>> whose getList method returns an ArrayList<String> and a getRandomElement method that returns a String.
However, it is usually unnecessary to know the exact type of List. Usually, if you have a List, then it doesn't matter to the user of this class which kind of List is really is. In this case, you don't need the type parameter T, only P. You can change your class to this:
public class MyClass<P> {
List<P> getList(/**/){}
P getRandomElement(){ /**/ }
}
Then you can have a MyClass<String> whose getList method returns an List<String> and a getRandomElement method that returns a String.
I am currently making a library which is an utility for me to handle something which is not associated with the question (I am implicitly not saying the subject because it is not really important), however it does use reflection.
I am retrieving all declared and inherited methods from a class, which currently works fine and is not the issue. But the thing is, I need to do this as well for sub-classes since those inherit over like methods do (however you cannot override those like methods).
The problem that I am facing that it will use the same algorithm but there will be on difference, instead of calling clazz.getDeclaredMethods() I need to call clazz.getMethods. What is the best way too approach this, and I kind of need to return Class[] and Method[] in the method signature as well.
Normally I would look for a shared superclass, but in this case I prefer to the have Class[] and Method[] accordingly. For starters, I did some research and found some shared superclasses:
GenericDeclaration
AnnotatedElement
Since I need both Class[] and Method[] arrays I am thinking something
like generics, so the method would look like:
public static <T extends GenericDecleration> T[] getT () {
}
As mentioned by dasblinkenlight this will not work since the method doesn't take any arguments and cannot check whether to retrieve Class or Method objects.
But how would I detect whether I need to call getDeclaredMethods or getDeclaredClasses?
What is the best approach on how to do this without duplicating a lot of code? I really tried to explain myself here, but if it is still unclear what I am doing please feel free to ask away!
Thank you very much in advance!
After messing around with this, I have found a solution that totally fits my needs. This is a combination of generics and #dasblinkenlight's solution, like so:
public interface DeclExtractor<T extends GenericDecleration> {
public T[] extract (Class clazz);
public Class<? extends T[]) getGenericClass ();
DeclExtractor<Method> methodExtractor = new DeclExtractor<Method>() {
#Override
public Method[] extract (Class clazz) {
return clazz.getDeclaredMethods();
}
#Override
public Class<? extends Method[]> getGenericClass () {
return Method[].class;
}
}
// Same for Class
}
Now the method which also will return the correct type so you dont have to manually cast all GenericDeclaration to your original object type. My issue was that I used a collection for it and not the correct array:
public <T> T[] getAll (final DeclExtractor<T> extractor, Class<?> clazz) {
T[] declaration = extractor.extract (clazz);
//.. The algorithm..
// Return an instance of a collection as array (I use a set in my implementation)
final Object[] objects = myCollection.toArray();
return Arrays.copyOf(objects, objects.length, extractor.getGenericClass());
}
Technically you do not need the getGenericClass method in the interface, but I am using extract directly in a loop so I cannot pull the class of that, however, you can.
Hopefully this helps someone in the future :) Thanks again to #dasblinkenlight for the inspiration!
Your getT needs to get some input in order to decide what to do.
What about a method which can takes an enum as argument to determine whether it needs to get classes or methods? (from a comment)
There is a better approach: define an interface that performs the appropriate extraction, and make two instances of it - one for extracting classes, and one for extracting methods:
public interface DeclExtractor {
GenericDecleration[] extract(Class cl);
final DeclExtractor forClasses = new DeclExtractor() {
public GenericDecleration[] extract(Class cl) {
// make an array of GenericDecleration from extracted classes
}
};
final DeclExtractor forMethods = new DeclExtractor() {
public GenericDecleration[] extract(Class cl) {
// make an array of GenericDecleration from extracted methods
}
};
}
Now you can rewrite your getT to take an "extractor", like this:
public static GenericDecleration[] getT (DeclExtractor extractor, Class cl) {
...
// When it's time to get components of the class, make this call:
GenericDecleration[] components = extractor.extract(cl);
...
}
To initiate a call to getT, pass DeclExtractor.forClasses or DeclExtractor.forMethods:
GenericDecleration[] c = getT(DeclExtractor.forClasses);
GenericDecleration[] m = getT(DeclExtractor.forMethods);
I have no particular use for this in mind, but is it possible to write a method that accepts any number of nested lists in Java?
I got as far as this:
private <T extends List<? extends T>> void masterOfLists(final T list) {
}
The small issue with this now is that it never ends. I neither want to lose generics, so simply accepting an Object and try casting it to a List every pass is not an option in my question.
I hoped it would be clear enough, but appereantly it isn't for some, I want the method masterOfLists to accept the following examples (and way more):
masterOfLists(new ArrayList<Object>())
masterOfLists(new ArrayList<List<Object>>())
masterOfLists(new ArrayList<List<List<Object>>>())
masterOfLists(new ArrayList<List<List<List<Object>>>>())
Instead of Object it may also be a concrete type like String.
The used List may be any type of list, like ArrayList or LinkedList or your custom implementation.
Using pure List won't help you here, you need to define a recursive class.
As an additional source of inspiration you can take a look at my code for Recursive Tic-Tac-Toe
You could create a class something like this:
public class Recursive<T> {
List<Recursive<T>> sub;
T value;
boolean hasSub() {
return sub != null;
}
T getValue() {
return value;
}
void forEach(Consumer<T> t) {
if (hasSub())
sub.forEach(t);
else t.accept(value);
}
}
You can use logic in this class to prevent it from both having a sub-list and an actual value, using constructors and/or setters.
And then if you want to iterate over it and print out all the sub-items recursively, you can use
Recursive<T> recursive;
recursive.forEach(System.out::println);
Then your method can look like this:
private <T> void masterOfLists(final Recursive<T> list) {
You won't get anywhere using pure Lists because the generic type of the list is not available at runtime, and the generics will only create a mess for you here. Using a recursive class is much easier.
The 'cheap' solution is to extend the ArrayList class with your own name, and force the Generics on the subclass. The SubClass is still an ArrayList....:
public class NestingList extends ArrayList<NestingList> {
// all we do is set the Generics...
}
I have this class, just for the purpose of learning:
public class MyClass{ //Looking for a solution without making my class also generic <Type>
//Private Arraylist var to hold the value called myvar
public MyClass(ArrayList<MyDesiredType> incoming) {
//CODE myVar=incoming
}
public MyDesiredType getType() {
return myVar.get(0);
}
}
Is there any way to infer in the incoming object from the constructor to the return type of the method without warnings and castings and loosing typesafeness, but most of all WITHOUT making the whole class GENERIC (seems redundant to me)? If not, why should I think this is not feasible for the compiler?
This is a reformulated question I already did, but it was my first one and I learned how to expose it clear because nobody understood. I tried to edit later the original question but everything was buried. I changed and simplified the example and try to put it easy. Original question: Java Generics Silly Thing (Why cant I infer the type?).
If there is any problem just tell it to me and I will remove it.
No, there is not. How would the compiler know what type to return? The generic type of ArrayList in the constructor will not be known during compile time. You either have to make the whole class generic or take another approach.
Consider this:
public class Test {
public static void main(String[] args) {
List<String> arrList = new ArrayList<String>();
arrList.add("FOO");
Test test = new Test(arrList);
String testStr = test.returnWhat();
System.out.println("testStr");
}
private final List myList; //warning
public <T> Test(List<T> ttype) {
myList = ttype;
}
public <T> T returnWhat() {
return (T) myList.get(0); //warning
}
}
This works but gives you warnings on the marked lines. So, really there is no way to achieve what you are describing without making the whole class generic.
Because, what if:
public class Test {
public static void main(String[] args) {
List<String> arrList = new ArrayList<String>();
arrList.add("FOO");
Test test = new Test(); // now what?
String testStr = test.returnWhat(0); // no warning...
JPanel p = test.returnWhat(0); // goes through without warning, real nice...
test.returnWhat(0); // returns Object
Test test2 = new Test(arrList);
test2.addElement(new Object()); // boom, inserted object into list of string.
String nono = test2.returnWhat(1); // the universe goes down. assign an object to string without warning. even
// though one COULD think the class is generic.
}
// private List<T> myList = new ArrayList<T>(); compiler error, T is unknown
private List myList = new ArrayList();
public Test() {
myList.add(new Object());
}
public <T> Test(List<T> ttype) {
myList = ttype;
}
public <T> T returnWhat(int index) {
return (T) myList.get(index);
}
public <T> void addElement(T el) {
myList.add(el);
}
}
The second one doesn't compile when myList is made generic. How could the compiler determine the type of <T> in the case where the default constructor is used?
Further, this could lead to serious problems with Objects in collections that rely on the fact that only certain types are inserted.
This will generate the following exception:
Exception in thread "main" java.lang.ClassCastException:
java.lang.Object cannot be cast to java.lang.String at
Test.main(Test.java:27)
Did I manage to convince you?
Real nice question, btw. I had to think about this one quite a bit.
When you say that you want the compiler to "infer in the incoming object from the constructor to the return type of the method without warnings and castings and loosing typesafeness", it seems that you are saying that it should infer the result of getType() from the input of the constructor. If both happen in the same function, it could. The problem is that the object may not exist in only one function, and so the extra type information (the generic type) is needed to pass this kind of object between functions.
For example, if I want to write a function that takes a MyClass object, I need to know what getType() will return so I can use the returned value. By adding a generic type of MyClass we are giving a description to what it holds.
Another way to look at it is that MyClass is a container. By adding generics, we are saying it is a container of a specific type of thing, and so we can more easily predict what we will get out of it.
There is no way for the compiler to know at runtime what type your arraylist is. I really dont see the problem using something along the lines of this:
public class MyClass<TYPE> {
private ArrayList<TYPE> incoming;
public MyClass(ArrayList<TYPE> incoming) {
this.incoming = incoming;
}
public TYPE getType() {
return incoming.get(0);
}
}
This way you can do:
ArrayList<Integer> numbers = createListOfNumbers();
MyClass<Integer> myClass = new MyClass<>(numbers);
Integer number = myClass.getType();
Or am i misinterpreting the question and you want to know the class at runtime?
No, if you want a class that can hold a list of a parameterized type.
Yes, if you want a class that can hold a list of exactly one type. You can declare that type explicitly in the field, constructor and accessor.
What you're forgetting is that not all code that you may run against is visible to the compiler! Jars can be added, removed, substituted at run time, that the compiler never saw. You may compile against an interface that is just:
public interface MyClassFactory {
MyClass getInstance();
}
Then at runtime you supply into the JVM an implementation. So the compiler never saw the actual code creating the MyClass that you will be using, so there is no way to perform such a compile time inference. You must either make the class generic or accept that there will not be type safety.
I am trying to use a combination of wildcards in the type of the receiver and in the type of an argument to a method in Java. The context is that of defining a container. Now, the type Container should not admit insertions whatsoever, since this type does not specify the type of the contained objects. However, if the underlying data structure allows it, there should be a way for searching an object of type T, or of any other type that extends T.
Here is a code snippet that demonstrates the problem. Any ideas on how I can achieve this design goal in Java?
public class Main {
public static class Container<T extends Item> {
public void insert(T t) {
System.out.println("Inserting " + t);
}
public <R extends T> int find(R r) {
return r.hashCode();
}
}
public static class Item {
// Nothing here
}
public static class ExtendedItem extends Item {
// And nothing here...
}
public static class Client {
public static void main(String[] args) {
useContainerOfItem();
useContainerWildCardOfItem(new Container<Item>());
Container<? extends Item> c;
c = new Container<Item>(); // OK. type of c, is a super type of Container<Item>
c = new Container<ExtendedItem>(); // OK. type of c, is a super type of Container<ExtendedItem>
useContainerWildCardOfItem(c);
}
private static void useContainerOfItem() {
Container<Item> c = new Container<Item>();
c.insert(new Item()); // OK. We can insert items
c.insert(new ExtendedItem()); // OK. We can insert items
c.find(new Item()); // OK. We can find items in here.
c.find(new ExtendedItem()); // OK. We can also find derived items.
}
private static void useContainerWildCardOfItem(Container<? extends Item> c) {
c.insert(new Item()); // Error: expected. We should not be able to insert items.
c.insert(new ExtendedItem()); // Error: expected. We should not be able to insert anything!
c.find(new Item()); // Error. Why??? We should be able to find items in here.
c.find(new ExtendedItem()); // Error. Why??? We should be able to find items in here.
}
}
}
The error message is telling you precisely what is the issue. Your find method is using a generic R extends T, and the T in this case is ?, so the compiler has no way of checking your supplied R (an Item) to check if it extends "capture#6-of ?".
I think your find method is parameterized incorrectly. In particular, you almost certainly don't mean to use extends in the declaration R extends T.
You seem to accept that with the wildcarded generic parameter <? extends Item>, you are not going to be able to insert anything, because the compiler cannot assert that any particular object you pass in conforms to the bounds (with the single exception of the null literal). Remember that this is not because of any specials semantics of an insert-type method, but solely because of the interface.
Your find method cannot be called for the exact same reason. Bear in mind that declaring <R extends T> and then declaring a parameter as type R, is exactly the same as declaring the parameter of type T. (Think about it the allowed values in both cases). And as you've seen above, no non-null objects can be accepted as an instance of T in your wildcarded case.
I think you may have intended to write your find method as <R super T>. In this case, the compiler can know for sure that no matter actual type of T is, it's Item or a subtype - and so Item or any of its superclasses (including Object) will always be valid for R and thus can be passed in. However, in this case, since Object is a valid substitution for the bounds, and all objects can be accepted for an Object parameter, this method is then equivalent to
public int find(Object r) {
return r.hashCode();
}
This is fact is entirely the semantics you're trying to capture - you don't need the generic bounding as they don't provide any bounds. Typically it's only ever worth using super in generic bounds when it's a nested generic parameter, e.g. you're accepting a collection as a parameter that you want to add objects of type T to (in which case you'd want a Collection<? super T>).
Alternatively, reading through your own answer to the question, my assessment in the above paragraph may be slightly incorrect. There are, then, three different restrictions you could try to apply to the type of the argument to the find method:
Anything is allowed (i.e. Object).
The argument must be an instance of the highest possible bound for the contained types (so if Container is defined as Container<T extends Item>, you declare the method to take a parameter of type Item).
The types must match exactly (i.e. T).
Generally speaking I would recommend to go as general as is possible - if you need to call methods that are defined in the Item class in order to test the match, then your hands are tied and you'll have to go with the second option. However, if you don't need to do this, then accept arguments of type Object to give callers the most flexibility.
Along those lines, there is essentially no possible argument for ever taking option 3 - you won't get any extra functionality in your method (since you can't call any more specific methods than you could in the second case), and you're simply restricting clients. Consider the following:
MyItem a = new MyItem();
Container<MyItem> c = new Container<MyItem>();
c.insert(a);
// Much later, possibly passing through various layers of the stack/maps/etc.
Item i = a;
c.find(i); // Will not compile if the find method takes an argument of type T
There is no benefit at all in forcing callers to downcast their Item reference to T specifically, when by definition you will be able to make the required method calls within find on an Item object, and can return an appropriate response based on the actual state of the object rather than the reference it is currently held in.
The key point is that the type of Container<? extends Item> means a container of something that extends Item, not anything that extends Item. Therefore it is possible that an object of type Item (the one being passed into the find method) may not be a compatible subclass of the something that extends Item. The compiler can not verify whether your code is correct, so it throws an error. The best you can do is allow a much broader parameter to find and restrict the return type:
public class Container<T> {
public void insert(T item) {
// insert...
}
public T find(Object o) {
// Lookup using a map or something return null if not found
}
}
I think the goal is misdirected here. You concede that your Container#insert() method can't work on a reference to wildcard-bound Container, but you expect that your Container#find() method can work. It's the same problem in both cases; you're trying to use covariance in both cases, which can't be enforced in Java against a wildcard like this.
Your original signature for Container#find() was fine. It met your specification. The latter one involving Searchable#find() is too relaxed; it allows one to search on any type of Item, rather than just types equivalent to or derived from the lower type T of the container. If the specification says that one should only be able to search for entries that are possibly in the container, and we don't know the specific type of the entries in the container, than we can't enforce that contract from a call site like Container#find().
Instead, try avoiding the wildcards like this:
private static <C extends Item, U extends C>
void useContainerOfSpecificItem(Container<C> c, C key1, U key2) {
c.find(key1);
c.find(key2);
}
There, you can see that find() accepts covariant types of keys, though, in this limited use, it's not actually necessary to distinguish type U from type C.
I could understand the error message, but still, this does not answer my question, which was:
Any ideas on how I can achieve this design goal in Java?
My current best solution is to use not one, but two generic parameters for the Collection class. The first designating what you can search for, and the other what you can insert.
If this is cumbersome, you use a superclass to capture the fact that you do not care about the type that "find" expects.
Still, I am not happy with this, and I hope a simpler solution exists.
public class Main {
public static class Searchable<R extends Item> {
public int find(R r) {
return r.hashCode();
}
}
public static class Container<T extends Item> extends Searchable<Item>{
public void insert(T t) {
System.out.println("Inserting " + t);
}
}
public static class Item {
// Nothing here
}
public static class ExtendedItem extends Item {
// And nothing here...
}
public static class Client {
public static void main(String[] args) {
useContainerOfItem();
useContainerWildCardOfItem(new Container<Item>());
Container<? extends Item> c;
c = new Container<Item>(); // OK. the type of c is a super type of Container<Item>
c = new Container<ExtendedItem>(); // OK. the type of c is a super type of Container<ExtendedItem>
useContainerWildCardOfItem(c);
}
private static void useContainerOfItem() {
Container<Item> c = new Container<Item>();
c.insert(new Item()); // OK. We can insert items
c.insert(new ExtendedItem()); // OK. We can insert items
c.find(new Item()); // OK. We can find items in here.
c.find(new ExtendedItem()); // OK. We can also find derived items.
}
private static void useContainerWildCardOfItem(Container<? extends Item> c) {
c.insert(new Item()); // Error: expected. We should not be able to insert an item!
c.insert(new ExtendedItem()); // Error: expected. We should not be able to insert anything!
c.find(new Item()); // No error, we should be able to find an Item
c.find(new ExtendedItem()); // No error, we should be able to find an ExtendedItem
}
}