I am new to generics. If I have already created a generic interface IList. But I want to create a method that only works on a list of Students(Student is also another class I created for that problem). Where should I put this method.
P.S. I tried to put this method inside IList class but that doesn't compile since the elements are T rather that Student.
What should I do?
It is not possible to make 'conditional' methods, as in, it is not possible to make a method which only exists for some of the types. A Foo<T> object doesn't change what methods it has based on the T.
You can create a subtype:
public class Foo<T> {
private List<T> elems = ...;
void bar();
}
public class StudentFoo extends Foo<Student> {
void baz() {
for (Student s : elems) {}
}
}
works fine. But that isn't going to magically give all Foo<Student> objects a baz method; you'd have to make them specifically as new StudentFoo(), not as new Foo<Student>().
Related
Suppose we have the following:
public class Parent{
public void setXXX(String XXX);
public String getXXX();
}
public class Children extends Parent{
....
}
Now I want to create a method called clone List like the following:
public List<Something> cloneList(List<Something> original){
List<Something> newList=new ArrayList<>();
for(Something e:original){
Something newE=new Something();
newE.setXXX(e.getXXX());
newList.add(newE);
}
return newList;
}
The thing is we want cloneList can be applied to both List<Parent> and List<Children>, so is there anyway that applicable for "Something"?
Something cannot be "? extends Parent" or "Parent" due to the Java Collection<Parent> incompatible with Collection<Children>
Assumption:
1. Don't want to use any serialization approach or reflection.
We are unable to modify the Parent and Children class. This is predefined in 3rd party Jar.
SuperParent class is not possible because we cannot modify Parent as stated in 2.
That is not possible in Java. Take a look at Generic syntax for extends or equal to.
You could change your method as follows and make your Parent class extend SuperParent.
public static <T extends SuperParent> List<T> cloneList(List<T> original, Class<T> type) throws IllegalAccessException, InstantiationException {
List<T> newList=new ArrayList<>();
for(T e : original){
T x = type.newInstance();
x.setXXX(e.getXXX());
newList.add(x);
}
return newList;
}
Also, you could choose another cloning approach. For example, using Apache Commons' SerializationUtils:
List<Children> result = (List<Children>) SerializationUtils.clone(originalList);
You cannot use generics this way, only reflection.
For a type variable T, you cannot use new T(). That's because generics are a compile-time mechanism, and new is used in run-time to create a specific-type object, and the compiler cannot create the appropriate reference to the type at compile time. So while this:
new ArrayList<T>();
is legal, because the compiler actually compiles it into the code for creating the raw ArrayList type, this:
new T();
is not, because the compiler does not even know what the actual class will be (even if it was just defined as T extends Parents it could be a class that has not even been written when the program compiled, like Grandchildren or something), and does not even know if it has a parameterless constructor.
In a general sense, you should be able to use a method having this signature:
public <T extends Parent> List<T> cloneList(List<T> original)
That's not your biggest problem, however. THAT would be obtaining copies of the list elements. Your code cannot use
T newE = new T(); // doesn't work
because the existence of a nullary constructor for type argument T cannot be guaranteed. Instead, you need a method that will return a correctly-typed copy. You cannot do this with complete type safety, but you can come close. You can implement these methods:
public Parent Parent.copy();
public Children Children.copy();
... in whatever way is appropriate, and then write your method like so:
public <T extends Parent> List<T> cloneList(List<T> original) {
List<T> newList = new ArrayList<>();
for (T originalItem : original) {
newList.add(original.getClass().cast(original.copy()));
}
return newList;
}
(Note that although the documented return type of Object.getClass() is Class<?>, which would not work for this purpose, the method documentation says that the return type is actually a bit more specific than that, enough so to make this work.)
Change the signature of cloneList to:
public <X extends Parent> List<X> cloneList(final List<X> original)
Then it will work, at least for the method signature. You can internally construct a List<Parent> and then cast it to List<X> and ignore the warnings if you need to; there's no way to find out the runtime type of "X".
I'm attempting to create an ArrayList (so java, obviously) with type TileEntity (yes this is a minecraft mod). But I also need the objects added to the ArrayList to implement a certain interface.
The first option that came to mind was creating an abstract subclass of TileEntity that implemented interface, and using that as the ArrayList type. But given the fact that people normally create their own subclasses of TileEntity and use those as the class they normally subclass, and I want people to be able to hook into my mod, I can't expect them to subclass anything besides TileEntity.
My current solution is to check if(object instanceof MyInterface) before adding, but that seems ugly. Surely there's a way to set the type of an ArrayList to require that an object be both a subclass of TileEntity and an implementor of MyInterface.
You can make generic the method or class where the ArrayList is used. For example, a generic method:
public <T extends TileEntity & MyInterface> void doStuffWith(T obj) {
List<T> yourList = new ArrayList<T>();
yourList.add(obj);
...//more processing
}
And a generic class:
public class ArrayListProcessor<T extends TileEntity & MyInterface> {
List<T> theList;
public void processList(T obj) {
theList.add(obj);
...
}
public void someOtherMethod() {
T listElem = theList.get(0);
listElem.callMethodFromTileEntity();//no need to cast
listElen.callMethodFromMyInterface();//no need to cast
}
}
...//somewherein your code
//SomeObj extends TileEntity and implements MyInterface
ArrayListProcessor<SomeObj> proc = new ArrayListProcessor<SomeObj>();
You could add whatever methods of TileEntity you need to your interface, and just make the ArrayList of your interface. There is probably some fancy way of using generics to solve the problem in a better way, but I'm unsure how.
EDIT: dcernahoschi's solution is much better.
I have this test method:
public void load(Class<? extends Object> className, XXXX)
{
Criteria criteria = session.createCriteria(className);
List<Object> list = criteria.list();
for (Object item : list)
{
list.add(new Object(item.getId, item.getCode); /* Object doesn't know getId */
}
}
How to replace XXXX in load method to call it using concrete Object? Something like:
load(Foo.class, testObject)
Is it possible?
Every generic type must extend Object, so this is sufficient:
public <T> void load(Class<T> className, T object)
{
// snip...
}
public <X> void load(Class<X extends Object> className, X object)
I think this is what you mean.
This should work.
public <T extends Base> void load(T object){
Criteria criteria = session.createCriteria(object.class);
List<T> list = criteria.list();
for (T item : list)
{
System.out.println(item.getId)); /* Object doesn't know getId */
}
}
Parameterizing the the void allows you to use generics. Since you are looking for an instance of T, and T is not defined yet, when you pass an object into load(T object) it will automatically set T to whatever class the object is. It auto parametrizes the void.
Generics are extremely useful. For an example, it's used in the List and Set classes as well as Map. However they come with their own risks. If you don't put the T extends Base or some class then you'll get compilation errors because java can not be sure that the class passed will have getId. Setting up a class that it must inherit will ensure that the object must know that method.
replace Base with the base class that knows "getId" and make all other classes you could even end up passing into load() extend that class. Notice no need to pass a Class into the load() because we will just use the class of the object instead, which has the same effect.
I'm using several interfaces with generics types. While combining it together I have some problems when I have to use them from a part of the code that is unaware of the concrete type of the generic parameter.
Suppose I have the following interface:
public interface MyObjectInterface<T extends Number> {}
The object implementing that interfaceare stored in a generic collection with the same generic type:
public interface MyCollectioninterface<T extends Number> {
public void updateObject(MyObjectInterface<T> o);
}
Concrete instances of MyCollectionInterface hold several MyObjectInterface of the same generic parameter:
public class ConcreteCollection<T extends Number> implements
MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<T> o){}
}
Now, I have several questions on how to use these generic interfaces from a client class that is
(and must be) unaware of the concrete type of generics.
Suppose I have the following class:
public class ClientClass{
private MyCollectionInterface<?> collection; //1st possibility
private MyCollectionInterface collection; //2nd possibility
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //this doesn't compile
}
public void foo(MyObjectInterface<? extends Number> o){
this.collection.updateObject(o); //this doesn't compile either
}
public void bar(MyObjectInterface o){
MyObject b = o; //warning
this.collection.updateObject(o); //this compile but with warnings
}
}
First Question :
Considered the fact that ClientClass doesn't care of which concrete type extending Number is the collection, should I declare collection with or without "?" ? If I use the second version I get the following warning:
MyCollectionInterface is a raw type. References to generic type
LatticeInterface should be parameterized
Second Question :
Why method foo doesn't compile?
Third question:
It seems that I need to use bar signature to call updateObject method. Anyway this solution produce a warning while trying to assign the MyObjectInterface parameter, like in the first question. Can I remove this warning?
Last questions:
Am I doing something weird with this generic interfaces and I should refactor my code?
Do I really have to care about all these warnings?
How can I use safety a generic interface from a class where I don't know its concrete type?
Ok, I played a bit with your code and reached a conclusion.
The problem is that your ConcreteCollection (and its interface MyCollectionInterface) declare the method updateObject as receiving an argument of type MyObjectInterface<T> (where T extends Number) - note that the type is a concrete one (not a wildcard).
Now, in your client class you are receiving a collection and storing it as MyCollectionInterface<?> but the instance that is passed to ClientClass' constructor will be of a concrete type, for instance:
new ClientClass(new ConcreteCollection<Integer>());
This means that the method updateObject of that instance would only accept an argument of type MyCollectionInterface<Integer>.
Then, in method foo you are trying to pass a MyObjectInterface<?> to updateObject, but since the compiler doesn't know which generic type your collection accepts (it could be Integer like in my example but it could also be Double or any other type that extends Number), it won't allow any object to be passed.
Long story short, if you declare your reference as MyCollectionInterface<?> you won't be able to call updateObject on it. So you have two choices:
1) Pick a concrete type and stick with it:
private MyCollectionInterface<Number> collection;
public ClientClass(MyCollectionInterface<Number> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<Number> o){
this.collection.updateObject(o); //compiles
}
But then you are limiting the collections you can receive in your constructor (which may not be a bad idea), or:
2) Modify your interface to accept a wildcard type:
public interface MyCollectionInterface<T extends Number> {
public void updateObject(MyObjectInterface<? extends Number> o);
}
public class ConcreteCollection<T extends Number> implements MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<? extends Number> o) {}
}
private MyCollectionInterface<?> collection;
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //compiles
}
Also, note that even in 2) you could still run into the same problem in your implementation of the updateObject method unless you declare your list something like this (with ArrayList for example):
List<MyObjectInterface<? extends Number>> list = new ArrayList<MyObjectInterface<? extends Number>>();
In which case you could as well remove the <T extends Number> from MyCollectionInterface and ConcreteCollection since T isn't used anymore.
#Your last questions:
1) Probably yes
2) You should
3) You can't, if you don't really care which objects you store in the collection, you should ditch generics altogether.
Sorry for the long answer, hope this helps.
I just wonder what usage the following code has:
public class Sub extends java.util.ArrayList<String> {...}
There is no any compiling restriction on the generic constraint java.util.ArrayList<String>.
The compiler does place restrictions on other code based on the type parameter in this case.
This will compile
public class Sub extends java.util.ArrayList<String> {
void addTwice(String s) { this.add(s); this.add(s); }
}
but this will not
public class Sub extends java.util.ArrayList<String> {
void addTwice(Object x) { this.add(x); this.add(x); }
}
Let's say you were making an index for a book, but you don't know how many indices you will need. You could make a class BookIndex extends ArrayList<String> or if you want to get really picky: BookIndex extends ArrayList<IndexEntry>.
/e1
Also, when a one Class extends a generic Class like ArrayList<String> you can grab the String out from the generic declaration, unlike if you had a class ArrayList<T>. In ArrayList<T> you would never be able to figure out what the T is.
You can extend class ArrayList, but it is not something that you should normally do.
Only ever say "extends" when you can truthfully say "this class IS-A that class."
Remember, Its not a good practise to extend the standard classes
Why not use like this ?
public class Sub {
List<String> s = new ArrayList<String>();
// ..
// ...
}
If you do that you can add to the basic functionality of an ArrayList or even change its normal functionality.
For example, you can override the add() method so that it will only add emails to the list.