Java generic type arguments [duplicate] - java

This question already has answers here:
Get generic type of java.util.List
(15 answers)
Closed 4 years ago.
I have a method which takes a List<?> as an argument.
public static String method(List<?> arg){
// Do something based on type of the list
}
//I call the method as below
List<ClassA> listA = new ArrayList<ClassA>();
List<ClassB> listB = new ArrayList<ClassB>();
method(listA);
method(listB);
In method, how do I know if arg is a List of ClassA or a List of ClassB?

Technically speaking, you CAN use instanceof to check if an object is a certain type.
However... That's NOT a good idea.
The way you've declared your method, it can accept a List of any type, so it isn't necessarily going to be A or B.
It's hard to tell what you're trying to do, but you probably should make your method generic.
You can do so like this:
public static <T> String method(List<T> arg) {
// We now know that the type of the list is T, which is
// determined based on the type of list passed to this
// method. This would demonstrate the point better if
// the return type was T, but I'm leaving the return type
// as String, because that's what your code returns.
}
Here's a better example:
If you want to create a generic method that returns the first element of a list, you would do it like this:
public static <T> T firstElement(List<T> theList) {
if (theList == null) {
return null;
}
T objectOfTypeT = theList.get(0);
return objectOfTypeT;
}
Note that the return type is now T.
Because we made this method generic, it can return the same type that is used in the List.
You would typically just return theList.get(0), but I added a line to make the purpose of generics more obvious.
Explanation of syntax:
The <T> indicates that this method takes one type parameter named T.
The T that immediately follows is the return type (just like you would normally return String, Integer, etc...).
The T in the List parameter is how the compiler knows what the heck a T is.
This allows the compiler to say: "This method expects something of type T. Oh look... The list is also of type T. If somebody passes a list of Strings to this method, than T must be a String. If somebody passes a list of Integers to this method, T must be an Integer."
In contrast, your method can only return a String and it has no idea what type is used in the List.
Also...
If A and B both extend the same class, named TheParentClass, you could declare your method like this:
public static String method(List<? extends TheParentClass> arg)
That way, you'd know a little more about the possible types of your parameter (and can benefit from compile time type checking).

From an answer by the user called Romain " If you use < ?>, you mean you aren't going to use the parametrized type anywhere. Either go to the specific type (in your case it seems List< String>) or to the very generic List< Object> "
Also, I believe that if you use the question mark the compiler wont catch type mismatches until runtime (reified; p.119 of Effective Java), bypassing erasure, and effectively elimating the benefit you get from using generic types???
TO answer the question of the questioner: if you use List< Object> and then try to cast it to A or to B , possibly using instanceOf , that might be a way to tell what it is. I bet there is a better way to do it than that though.

Related

how to explain generics used in ImmutableList.builder().build() in guava?

I just saw this kind of code ImmutableList<String> list= ImmutableList.<String>builder().build();
which really confused me. How to understand the diamond after ImmutableList.?
Most parameterized types in java show up on a type. This looks like so:
interface List<T> {
void add(T elem);
}
So, any List type is parameterized, and as generics is really just a mechanism to link things, what it links is that a List<String> has an add method that takes String objects, and a get(int) method that returns a String, etc.
But, methods themselves may also want this linking behaviour. For example, let's say I want to make a method that takes 2 arguments of the same type, and returns the first non-null one. Here too I want to link things: The types of the 2 argument, and the return type? All the same thing, caller's choice as to what it might be.
Java supports this: Methods can ALSO have generics:
public <T> T firstNonNull(T a, T b) {
return a == null ? b : a;
}
is valid java, and you can call it:
String a = firstNonNull("hello", "world!");
Compiles without requiring a cast.
Java will infer generics if it can; it does that in my previous example (the two arguments are both strings; java infers you meant T to be String there). But you can, if you want, be explicit about it. This is where this funky syntax comes in:
Number a = ClassContainingFNN.<Number>firstNonNull(null, null);
You need the dot to use this syntax, hence why I had to make the call a little longer. With the ImmutableList builder method, java can't (easily) infer what type you wanted, as the call to builder() itself doesn't let the compiler know that you're attempting to build a list of, say, strings. That's why forcing it by explicitly telling java what you want the type param to be is useful, thus, why the usual way to call this builder is:
ImmutableList.<String>builder().add(aString).add(anotherString).build();
Java will always try to infer something if you don't explicitly pick something, but it would just infer Object here. Unless you wanted a list of objects, you need the 'forcibly pick a type' option.
See java support jls-15.12 for supporting TypeArguments after entering Type.
MethodInvocation:
MethodName ( [ArgumentList] )
TypeName . [TypeArguments] Identifier ( [ArgumentList] )
The builder is generic method
public static <E> Builder<E> builder()
And because it's static you entered before method name the type using diamond operator
In case of new instance it'll be as you expected:
new ImmutableList.Builder<Color>()

Why does a Java generic raw class erase all generics to object when type parameters are unspecified? [duplicate]

This question already has answers here:
Combining Raw Types and Generic Methods
(5 answers)
Why won't this generic java code compile?
(4 answers)
Closed 9 years ago.
If I have a class:
public class GenericClass<TBlah extends Number> {
public List<String> getList() {
return null;
}
}
When I attempt to use that method from another class:
public class OtherClass {
public void test() {
GenericClass a = null;
for (String s : a.getList()) {
}
}
}
Why does a.getList() return a List<Object> until I change the line above the for loop to:
GenericClass<Number> a = null;
At which point a.getList() returns a List<String> like it should do?
Edit: I don't understand why the contract specified by getList() should be affected whatsoever by how I declare my variable 'a'. getList() always returns a List<String>, it doesn't matter what TBlah is.
Because this is how generics work. Do not forget that before generics when you declared a List it was a list of Object. You were expected to put/get Object and you were forced to cast to get your object with the correct type. Actually it still is a list of Object in runtime.
Generics is a way for the compiler to guarentee you type safety at compile time assuming you have no warnings. In runtime there are no List<String>. There is just List. The compiler puts the automatic cast for you, so you are able in your code to write String s = list.get(i) without casting.
When you declare GenericClass a you are declaring a raw type (you should get a warning on this) thus the compiler does not have a way to know what type the a.getList() is supposed to return. So it uses Object. When you declare GenericClass<Number> a = null; now the compiler knows what type to expect for the a.getList() and uses the desired one.
Edit: It should be clarified that the compiler can know what to expect only if you respect the contract of the signature (i.e. as is the case with GenericClass<Number>). If you don't respect the contract (i.e. you are using a raw type that does not extends Number) then the contract does not apply anymore. The compiler behaves as if no type information was present. Do not forget that the compiler needs to also maintain backwards compatibility with code that was created in the pre-generics era

What does <T> (angle brackets) mean in Java?

I am currently studying Java and have recently been stumped by angle brackets(<>). What exactly do they mean?
public class Pool<T>{
public interface PoolFactory<T>{
public T createObject();
}
this.freeObjects = new ArrayList<T>(maxsize)
}
What does the <T> mean? Does it means that I can create an object of type T?
<T> is a generic and can usually be read as "of type T". It depends on the type to the left of the <> what it actually means.
I don't know what a Pool or PoolFactory is, but you also mention ArrayList<T>, which is a standard Java class, so I'll talk to that.
Usually, you won't see "T" in there, you'll see another type. So if you see ArrayList<Integer> for example, that means "An ArrayList of Integers." Many classes use generics to constrain the type of the elements in a container, for example. Another example is HashMap<String, Integer>, which means "a map with String keys and Integer values."
Your Pool example is a bit different, because there you are defining a class. So in that case, you are creating a class that somebody else could instantiate with a particular type in place of T. For example, I could create an object of type Pool<String> using your class definition. That would mean two things:
My Pool<String> would have an interface PoolFactory<String> with a createObject method that returns Strings.
Internally, the Pool<String> would contain an ArrayList of Strings.
This is great news, because at another time, I could come along and create a Pool<Integer> which would use the same code, but have Integer wherever you see T in the source.
It's really simple. It's a new feature introduced in J2SE 5. Specifying angular brackets after the class name means you are creating a temporary data type which can hold any type of data.
Example:
class A<T>{
T obj;
void add(T obj){
this.obj=obj;
}
T get(){
return obj;
}
}
public class generics {
static<E> void print(E[] elements){
for(E element:elements){
System.out.println(element);
}
}
public static void main(String[] args) {
A<String> obj=new A<String>();
A<Integer> obj1=new A<Integer>();
obj.add("hello");
obj1.add(6);
System.out.println(obj.get());
System.out.println(obj1.get());
Integer[] arr={1,3,5,7};
print(arr);
}
}
Instead of <T>, you can actually write anything and it will work the same way. Try writing <ABC> in place of <T>.
This is just for convenience:
<T> is referred to as any type
<E> as element type
<N> as number type
<V> as value
<K> as key
But you can name it anything you want, it doesn't really matter.
Moreover, Integer, String, Boolean etc are wrapper classes of Java which help in checking of types during compilation. For example, in the above code, obj is of type String, so you can't add any other type to it (try obj.add(1), it will cast an error). Similarly, obj1 is of the Integer type, you can't add any other type to it (try obj1.add("hello"), error will be there).
It is related to generics in java. If I mentioned ArrayList<String> that means I can add only String type object to that ArrayList.
The two major benefits of generics in Java are:
Reducing the number of casts in your program, thus reducing the number of potential bugs in your program.
Improving code clarity
is called a generic type. You can instantiate an object Pool like this:
PoolFactory<Integer> pool = new Pool<Integer>();
The generic parameter can only be a reference type. So you can't use primitive types like int or double or char or other primitive types.
<> is used to indicate generics in Java.
T is a type parameter in this example. And no: instantiating is one of the few things that you can't do with T.
Apart from the tutorial linked above Angelika Langers Generics FAQ is a great resource on the topic.
Generic classes are a type of class that takes in a data type as a parameter when it's created. This type parameter is specified using angle brackets and the type can change each time a new instance of the class is instantiated. For instance, let's create an ArrayList for Employee objects and another for Company objects
ArrayList<Employee> employees = new ArrayList<Employee>();
ArrayList<Company> companies = new ArrayList<Company>();
You'll notice that we're using the same ArrayList class to create both lists and we pass in the Employee or Company type using angle brackets. Having one generic class be able to handle multiple types of data cuts down on having a lot of classes that perform similar tasks.
Generics also help to cut down on bugs by giving everything a strong type which helps the compiler point out errors. By specifying a type for ArrayList, the compiler will throw an error if you try to add an Employee to the Company list or vice versa.

Java: generic interfaces and functions in such

I am still experimenting with how Java handles generics. I stumbled upon the fact/issue/thing that if you have a generic interface like A<T>, you cannot really check afterwards if some object is actually implementing A<B> or A<C>.
I wondered if that could cause actual problems.
Now I have tried this code:
static interface A<T> { void foo(T obj); }
static class B implements A<B> {
public void foo(B obj) { obj.bar(); }
void bar() {}
}
static {
assert (new B() instanceof A<?>);
((A<?>) new B()).foo(new Object());
}
This gives me this error (for the foo-call):
The method foo(capture#1-of ?) in the type Main.A<capture#1-of ?> is not applicable for the arguments (Object)
I wonder why that is. Eclipse tells me that the signature of foo after the cast to A<?> is foo(? obj) which I thought is the same as foo(Object obj).
The assert succeeds.
What I tried to figure out is at what point exactly does it cast the object when I call the foo function.
Also, how can I call foo from A<?>? This is the thing I actually need to be able to do. Or is that impossible with any other parameter than null?
A more real-world example where I actually wonder about this: I use the Comparable<T> interface a lot. That case is actually even more complicated; I might open another question about that if this here doesn't answer it.
I wonder why that is. Eclipse tells me that the signature of foo after the cast to A is foo(? obj) which I thought is the same as foo(Object obj).
Nope, absolutely not. Imagine A<T> is List<T> with foo(T) being add(T) and so A<?> is List<?>. Should you be able to do this?
List<String> strList = new ArrayList<String>();
List<?> wcList = strList;
wcList.add(Integer.valueOf(6)); //possible if add(?) is same as add(Object)
//...
String str = strList.get(0);
Of course not, since you'd get a ClassCastException in the final line.
What foo(?) really means is that the method applies to some unknown but specific type. You can't typically invoke these methods unless you pass null as the parameter, which is acceptable to assign to any reference type.
If you have "foo(? obj)" then the ? could be any type. If it is say String then you can't pass, say, an Integer to it. All you can pass is null.
Casting and use of instanceof should normally be avoided unless unavoidable (such as implementing equals), particularly with generics.
The compiler is correct because it does a compile-cast test on compile-time.
((A<?>) new B()).foo(new Object());
is errornous because the compiler expected
((A<?>) new B()).foo(A object)....
meaning that it wanted anything of type A or its children. Object is the parent of A and it doesn't match the compile-test Parameter type for compilation.
When you check if an instance of B is an instance of A<?> you just do the same thing as new B() instanceof A. You don't really check how T is set, it's just "something".
Later in the code with the cast, you tell that you'll use B as a A<?> so the variable will have the characteristic of a A but the generic type is still "something". This "something" exists and is probably a specified class but your don't care of the exact type.
That's why when you use the foo() method which take a T in parameter, you can't pass a "something" in parameter, because you don't know what it is, it could be an Object but it could be anything else.
Because of this the compiler tells you foo(capture#1-of ?) isn't applicable for the argument Object. The needed parameter is "something" but not necessarily an Object.
Then, when would you need this feature ?
For example if you work with a map, if you don't really care of the type of the key (if you only work with the values() method for example), you could do something like this :
Map<?, V> m
This way you won't be able to use features related to the key of the map (but you don't care about that), but you'll be able to use a map with any kind of key.
No, foo(? obj) is not actually the same as foo(Object obj). The difference is, when the parameter type is Object, it's explicitly stating that any type of object is legal. With a parameter type of ?, the method states that it does not know what type of object is legal... therefore nothing is legal except for null.
The reasoning for this becomes apparent when you consider a List rather than an arbitrary interface. Look at this method:
public void foo(List<?> list) {
list.add(...); // what can we add here?
}
The ? indicates that any type of List is acceptable... the List passed in could be a List<String>, a List<Integer> or a List<Map<Foo, Bar>>. There's no way of knowing. Note that this is only a problem with methods that consume generic parameters, such as add or your foo method. For methods that produce (return) an object of the generic type, it's fine to use such a method and assign the result as an Object. This, unlike the consumer method, cannot corrupt the internal state of the generic object.
Also notice that when you call ((A<?>) new B()).foo(new Object()), you're trying to do something illegal... if something (such as the Object) that is not a B were to be passed to B's foo method, it would explode at runtime. The compiler is correctly preventing you from doing this.
You may also want to check out my answer to another question here which explains some things about bounded wildcard types and such.
This is a simple explanation:
A<?> means A of unknown parametrized type. Given
A<?> ref = new B()
ref could point to any A: A<Object, A<String>, anything. So you can not call A.foo(new Object()) because in case of A<?> reference there is no way to know which parameter ref.foo() accepts. Actually the only thing valid is ref.foo(null).
Many have clarified that point about ? but noone has really answered the main question yet, so here it is:
It is possible to call A#foo like this:
((A) new B()).foo(new Object());
The cast then is done inside of foo.

Java : What is - public static<T> foo() {...}?

I saw a java function that looked something like this-
public static<T> foo() {...}
I know what generics are but can someone explain the in this context? Who decides what T is equal to? Whats going on here?
EDIT: Can someone please show me an example of a function like this.
You've missed the return type out, but apart from that it's a generic method. As with generic types, T stands in for any reference type (within bounds if given).
For methods, generic parameters are typically inferred by the compiler. In certain situations you might want to specify the generic arguments yourself, using a slightly peculiar syntax:
List<String> strings = Collections.<String>emptyList();
In this case, the compiler could have inferred the type, but it's not always obvious whether the compiler can or can't. Note, the <> is after the dot. For syntactical reasons the type name or target object must always be specified.
It's possible to have generic constructors, but I've never seen one in the wild and the syntax gets worse.
I believe C++ and C# syntaxes place the generic types after the method/function name.
The context is a generic method as opposed to a class. The variable <T> applies only to the call of the method.. The Collections class has a number of these; the class itself is not generic, but many of the methods are.
The compiler decides what T is equal to -- it equals whatever gets the types to work. Sometimes this is easier then others.
For example, the method static <T> Set<T> Collections.singleton(T o) the type is defined in the parameter:
Collections.singleton(String T)
will return a Set<String>.
Sometimes the type is hard to define. For example sometimes there is not easily enough information to type Collection.emptyList(). In that case you can specify the type directly: Collection.<String>emptyList().
T it's the formal type parameter wich will be replaced by the actual type
argument used at the instantiation of the object.
For example, here is the List and Iterator definitios in package java.util:
public interface List<E>{
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E>{
E next();
boolean hasNext();
}
Then you can instantiate a List this way:
List<String> ls = new ArrayList<String>()
Where you might imagine that List stands for a version of List where E has
been uniformly replaced by String:
public interface StringList{
void add(String x)
Iterator<String> iterator();
}

Categories

Resources