when to use java generic wildCard? - java

It was stated in comments that, question was creating confusion. So, i have edited the question, let me know, if it is still creating confusion.
Consider below code:
class Employee{}
class ContractEmployee extends Employee{
}
class PermanentEmployee extends Employee{
}
...
Can any one provide the basic difference between below two cases and
when to use which one
Case:1
public <T extends Employee> void empTest(ArrayList<T> list)
public <? extends Employee> void empTest(ArrayList<?> list)
Case:2
public void empTest(ArrayList<? extends Employee> list)
public void empTest(ArrayList<T extends Employee> list)

Not full explanation but you will get starting over here. We need to follow PECS pattern in generics.
PECS stands for Producer Extends and Consumer Super.
in your line below,
public void empTest(ArrayList list)
You are basically giving list which will act as a producer in further use inside that method. Now as you might know, generic is just compile time illusion and will get erased at runtime, your code in mrthod empTest is expecting the List of particular Employee. for example, if you have Fruit as superclass for Orange and Apple, you should not give list of both Orange and Apple to consumer and restrict it to either Apple or Orange. Does it make sense? I guess yes.

First of all, your question is quite legitimate, although with your examples, it's hard to explain / understand the differences.
In all the variants, you want to define a method empTest() that accepts an ArrayList of Employees or subclasses of Employee. You do this with
public void empTest(ArrayList<? extends Employee> list) { ... }
So, what are the other syntax variants meant for? Let's use a different example, as your empTest() method doesn't need anything else.
Say, we want to add an employee to a list using something like addEmp(list, emp);. First idea might be:
public void addEmp(ArrayList<Employee> list, Employee emp) { ... }
But that won't do the job, as you won't be able to pass an ArrayList<ContractEmployee> into the method. Next attempt:
public void addEmp(ArrayList<? extends Employee> list, Employee emp) { ... }
Now it accepts the list, but it also allows you to pass an ArrayList<ContractEmployee> in combination with a PermanentEmployee, and adding a PermanentEmployee to an ArrayList<ContractEmployee> isn't allowed. The compiler will flag the line in the method body where you add the employee, as illegal.
So, what we need here, is to check for using the same type of employee in both places, and that's what the named type parameters can be used for.
public <T extends Employee> void addEmp(ArrayList<T> list, T emp) { ... }
This says: it's ok to pass in an ArrayList of any subtype of Employee, and we call that subtype T. Then the emp argument must also come from the same subtype T (or from a sub-subtype because of normal class inheritance).
If being an Employee or not doesn't make a difference to the method, you can even write
public <T> void addEmp(ArrayList<T> list, T emp) { ... }
To summarize it:
Use the <... extends SomeClass> constructs if need more variability than the plain <SomeClass> construct.
If it's just one place where you need that variability, there's often no need to introduce a name for the subclass, so <? extends SomeClass> in the method's parameter list does the job.
If you need the same subclass in multiple places, you need to give it a name, so use something like <T extends SomeClass> in front of the return-type declaration and use T without the angle brackets in the parameters list.
Regarding syntax:
- If you need to introduce a name for the type parameter, this is done before the return type.
- In the method return type or the method parameter list, you can only use names that already exist, or use unnamed wildcard constructs.

Related

generic signature to accept Map<String,Object> or Map<String,String>

I currently have a method like this:
public static Report createReport(Map<String,Object> parameters) {...}
I'm trying to figure out if there is a way I can change the generic specification so that it will accept both Map<String,Object>s and Map<String,String>s for parameters.
Note that createReport needs to be able to add entries to parameters. Is this possible?
Please see:
Difference between <? super T> and <? extends T> in Java
Specifically this answer. The PECS (producer extends, consumer supers) rule is ingenious.
Try:
public static Report createReport(Map<String,? super String> parameters) {...}
You'll be able to add Strings and read Objects:
parameters.put("a,", "b");
Object object = parameters.get("c");
If you were only reading the values out of the Map you could have done something like this:
public static Report createReport(Map<String,?> parameters) {...}
However, since you also want to add enteries, you need to know the type, or at least be able to know that the type in the Map is the same as the type you are adding.
If it is variable, then I would suggest having another parameter that does the conversion to the type you need.
interface Converter<T>{
T convert(Object o);
}
Then add that parameter to your createReport method like this:
public static <T> Report createReport(Map<String,T> parameters, Converter<T> converter) {...}
Then inside your method you can do something like this:
T value = converter.convert(foo);
parameters.put(key, value);
It would then be up to the caller of createReport to provide the correct converter.
No it is not possible. There is no type-union in Java. You have to revert to the lowest common superclass, which is in your case Object. In some cases you could use an Interface instead, like for example a collection type or a -able style (Closeable) interface.

Generic type in class declaration

I have
1) a basic interface,
2) a few classes that implement this interface,
3) and a generic class that I want to accept, as a parameter, any of the implementing classes
I have tried the following:
public class Foo extends Bar<? extends SomeInterface> {
public Foo(List<? extends SomeInterface> someInterfaceList) {
super(someInterfaceList);
}
...
}
I receive the error No Wildcard Expected. Elsewhere in my code I have statements such as List<? extends SomeInterface> and I receive no errors, so why am I running into problems here? How can I fix this problem and still get the desired results?
I have tried search 'No Wildcard Expected' and 'wildcard in class declaration' to no avail. Thanks in advance!
It sounds like you want to declare a generic type argument that you will reference elsewhere. Wildcards only make sense when the type is used only once, and when declaring a generic type parameter for a class this doesn't make any sense.
Try this instead:
public class Foo<T extends SomeInterface> extends Bar<T> {
public Foo(List<T> someInterfaceList) {
super(someInterfaceList);
}
...
}
As your code was written, there was no way for the user of your class to specify the generic type argument for Bar<>, since Foo wasn't itself a generic type.
Further, if this were possible, it would have been possible for the generic argument to Bar<> to be different than the generic argument to List<> -- as long as both types implemented SomeInterface there would not be a compile-time issue with these definitions, but there could have been a much more confusing error message later when you incorrectly assumed that both types must be the same.
So, declare the generic type once as a generic argument to the Foo class, and then use that type (T in my example) elsewhere to refer to that type instead of accepting some new generic type argument that may not refer to the same type.
I'm not exactly sure what you're looking for, so it might help if you could provide a little more detail. Perhaps you could be a little more specific about how you're planning to instantiate and use these objects?
Anyways, I think you might be looking for something like this:
import java.util.List;
public class Foo<T extends SomeInterface> {
public Foo(List<T> someInterfaceList) {
for (T item : someInterfaceList) {
// do something with each item
}
}
}
class Bar<T> {}
interface SomeInterface<T> {
T x(T y);
}
Or, alternatively, you could just use the following for the constructor:
public Foo(List someInterfaceList) {
but you wouldn't have an easy way of getting the type T of the items in the list.

How to implement a list of Generic Interfaces

Hello I'm working on some interesting code and a thought has crossed my mind.
Here is some simplified code:
public interface SomeInterFace<T>
{
public List<T> doSomething();
}
Now, I got another interface which should extend this one for various Objects for instance
public interface OtherInterface extends SomeInterface<Integer>,
SomeInterFace<String>, SomeInterface<Number>, ...
Is there a possiblity to write this "OtherInterface" in a manner where it implements "SomeInterface" with a list of objects?
If you are able to handle any type of type argument for OtherInterface, then as others have suggested, you can write:
public interface OtherInterface<T> extends SomeInterface<T>
However, if you need to implement SomeInterface only for a particular list of type arguments (say, String and Number), then you cannot do that. At compile time, SomeInterface<(anything)> just becomes SomeInterface due to type erasure, and the casting is inserted for you after the compiler makes sure you aren't trying to do any unsafe casts (or you've told it not to check). Therefore, you would be trying to write a class that looked something like this:
public interface OtherInterface extends SomeInterface, SomeInterface {
public List doSomething();
public List doSomething();
}
...which is invalid for obvious reasons!
Hope that helps!

Where can we use ArrayList< ? extends My_Class>

Where can we ArrayList<? extends My_Class> because it won't allow you to add any new element if you declare it of this way:
ArrayList<? extends My_Class> obj=new ArrayList<? extends My_Class>();
list.add(new Derived_My_Class()); //this is compilation error
The widely-used acronym for describing these keywords is: PECS: Producer extends - consumer super.
So, if you use "extends" your collection produces elements of the given type. So you can't add to it, you can only take from it.
An example usage would be to provide a client of your API with a list:
public List<? extends CharSequence> getFoo() {
List<String> list = new ArrayList<String>();
list.add("foo");
return list;
}
Related: Java generics: Collections.max() signature and Comparator
You are correct, your ArrayList cannot be used the way it is derived: there is nothing that you can put into it.
What you want for storing My_Class and its subclasses is simply ArrayList<My_Class>; it will take objects of My_Class and all its DerivedClass correctly.
Well...There is no point one will declare ArrayList like this, rather your intentions will be fullfilled by writing
ArrayList< Supertype> obj=new ArrayList< Supertype>();
As per my epxerience, I have seen this notion in method arguments, where you expect your caller to provide a collection of subtypes of particular Supertype (or return from a method likewise as someone said above). like as follows
public getAnimals(List< ? extends Animal> obj){
obj.add(something); //not allowed
}
there are fair chances that you can add donkeys, monkeys and birds etc in your List of certain type say (Monkey). and get classCastException while getting from it.
That's why It not allowed in this case. read Effective Java by Josh Bloch. he has explained it well with producer consumer analogy(PECS)

How can I accept a supertype of generic parameter on a single object?

Is it possible to accept only supertypes of the generic Type of a class?
What I'm looking for is something like:
class <T extends Object> MyClass {
public <TS super T> void myMethod(TS someObjectSuperToTheClass) {
//do stuff
}
}
I don't really need it anymore (and it's probably not all that useful to begin with) but I'm curious if this is at all possible and if not, why.
Think about what it would mean in this case.
You want to assert that TS is either T, or any of its superclasses. But since TS is merely a reference, the actual someObjectSuperToTheClass parameter can be TS or a subclass.
Putting both halves together, in comes out that your code is entirely equivalent to
public void myMethod(Object someObjectSuperToTheClass) { //do stuff }
since together, you've got that TS can walk as high as it wants up the class hierarchy, and the parameter can walk down as far as it wants.
What was it you were trying to constrain the parameter to, with this syntax?
No you cannot! Only wildcards can have a super bound.

Categories