Generic method, multiple brackets, types - java

http://docs.oracle.com/javase/tutorial/java/generics/genmethods.html
Quoting from there-
A more realistic use of generic methods might be something like the following, which defines a static method that stuffs references to a single item into multiple boxes:
public static <U> void fillBoxes(U u, List<Box<U>> boxes) {
for (Box<U> box: boxes {
box.add(u); }
}
Here, what does this List<Box<U>> do? How does this work?
Further,
To use this method, your code would look something like the following:
Crayon red = ...;
List<Box<Crayon>> crayonBoxes = ...;
The complete syntax for invoking this method is:
Box.<Crayon>fillBoxes(red, crayonBoxes);
I couldn't understand all these.

You can think of U as a kind of placeholder for a Type or Interface.
If you have a class Foo and replace all U's in the method declaration with Foo, it will take an instance of Foo and a List>.
As the name "Generic" says, it is a generic way of "replacing" the generic type argument U with a real type. This way you can force that everyone who uses an object of Type U also has to use a List> to call the method.
Taking the Foo example, I can only call
public static <U> void fillBoxes(U u, List<Box<U>> boxes) {
with
Foo foo = new Foo();
List<Box<Foo>> fooList = new ArrayList<Box<Foo>>();
fillBoxes(foo, fooList);

List is a generic collection.
Box is another generic.
You can declare Box<Crayon> to construct a Box of Crayons
List<Box> is a collection of Boxes but Box is generic, need a Type for the box List<Box<Crayon>>.
Just follow the generic type U. FillBoxes method is static public static <U> void fillBoxes(U u, List<Box<U>> boxes). Static methods doesn't need a instance, if there is not a instance you can't declare the type of the box Box<Crayon>, you have to pass the type in the call of the method Box.<Crayon>fillBoxes, knowing that type, the compiler knows that the first parameter in FillBoxes (U u) is a Crayon type and the second is a List of Boxes of Crayons (List<Box<U>> boxes).
The method will fill a list of Crayon Boxes with red crayons :)
Ufff this was hard for a non Java programmer and non native english speaker...

List<Box<U>> simply means it's a list of boxes where you can store U-type objects in each of them.
If for example you have classes "crayon", "pencil", "pen" etc. implementing interface "U", you can store their instances in such boxes.

Related

How to return the same generic Collection-type with different element-type?

I have a method, that maps elements of a collection to other object and returns a collection containing the mapped elements. I want the returned Collection to be of the same Collection-type as the input Collection, but with a different element type.
My method would look something like this:
<E extends OriginalElement, T extends TargetElement,
C extends Collection<E>, R extends C<T>> R map(C elementsToMap) {
// snip
}
Obviously the part R extends C<T> doesn't work.
How can I specify that return type to be the same subclass of Collection as Type C, but with element type T instead of E?
You can't, I don't think, because e.g. ArrayList<String> and ArrayList<Integer> are essentially unrelated types.
Plus, when you say "same generic Collection-type", do you mean:
"if I give you some subclass of ArrayList, you'll give me back an instance of java.util.ArrayList"; or
"if I give you a specific subclass of ArrayList, you'll give me back an instance of the same specific subclass of ArrayList"?
Not only is that hard, because in general you don't know how to instantiate arbitrary subclasses, you might not be able to create such an instance, for example if the input is an IntegerArrayList (extends ArrayList<Integer>), and you want to map the elements to Strings. So, whilst you could return a java.util.ArrayList<String> in that case, you can't have a generic solution because you need some knowledge of "which type to instantiate in this specific case".
I am going to make an unquantified assertion that a small handful of collection types can handle most cases. So, provide overloads for these specific types:
</* type variables */> ArrayList<T> map(ArrayList<E> input) { ... }
</* type variables */> HashSet<T> map(HashSet<E> input) { ... }
</* type variables */> ImmutableList<T> map(ImmutableList<E> input) { ... }
// etc.
and then provide a general method for the other cases, and leave it up to callers to specify the collection type they want:
</* type variables */> Stream<T> map(Collection<E> input) { ... }
and then call the general method from the specific methods:
</* type variables */> ArrayList<T> map(ArrayList<E> input) {
return map((Collection<E>) input).collect(toCollection(ArrayList::new));
}
// etc.

Instantiating generic type ArrayList<T>

I am new to generics and read in a article "A parameterized type, such as ArrayList<T>, is not instantiable — we cannot create instances of them".
Full quote, from Java in a Nutshell:
A parameterized type, such as ArrayList<T>, is not instantiable - we
cannot create instances of them. This is because <T> is just a type
parameter - merely a place-holder for a genuine type. It is only when
we provide a concrete value for the type parameter, (e.g.,
ArrayList<String>), that the type becomes fully formed and we can
create objects of that type.
This poses a problem if the type that we want to work with is unknown
at compile time. Fortunately, the Java type system is able to
accommodate this concept. It does so by having an explicit concept of
the unknown type which is represented as <?>.
I understand that it should not be instantiable since the concrete (actual) type is not known. If so, why does the below code compiles without an error?
public class SampleTest {
public static <T> List<T> getList(T... elements) {
List<T> lst = new ArrayList<>(); // shouldn't this line return an error?
return lst;
}
}
I know there is a gap in my understanding of generics here. Can someone point out what am i missing here?
Because T is given as another generic type argument.
It's the whole purpose of generics to make the type parameterizeable. So the caller can specify the type. This can be done in multiple layers: the caller may also be generic and let its caller specify the type.
public static void main(String[] args)
{
foo(7);
}
public static <T> void foo(T value)
{
bar(value);
}
public static <U> void bar(U value)
{
baz(value);
}
public static <V> void baz(V value)
{
System.out.println(value.getClass().getSimpleName());
}
It prints out
Integer
A parameterized type, such as ArrayList<T>, is not instantiable
Means: You cannot create ArrayList of an unknown T. It must be specified at compile time. But it can be done indirectly, by another generic. In your case, it's another T, which will be specified again by the caller of your generic getList.
The wildcard <?> is something different. It is used to specify compatibility. <?> is the syntax to avoid specification of the type. You can use extends to require a basetype or interface. However, you cannot create instances with wildcards.
List<?> list = new ArrayList<String>();
list = new ArrayList<Integer>();
This wouldn't be possible otherwise. It makes most sense when using it in parameter specifications, for instance:
public static int foo(List<? extends Comparable> list)
{
return list.get(1).compareTo(list.get(2));
}
It's very confusing of this book. It assumes that <?> somehow solves the problem that a List with unknown T cannot be instantiated. IMHO, this is rubbish. T must be specified to create an instance.
The code that you mention can compile because the Object "lst" is not actually initialized until the method is called. Since the method knows that it will be getting a var-args argument of type T, it can compile in this scenario. Take the example Wrapper class below for example:
public class Wrapper<T> {
public static <T> List<T> getList(T... elements){
List<T> lst = new ArrayList<>();
for(T element: elements) {
lst.add(element);
}
return lst;
}
}
This code can compile because the method hasn't been called. When the method is called, Type T will be the type that we pass as the var-args argument and the code will have no issue compiling. Lets test this in our main method:
public static void main( String[] args ){
System.out.println(Wrapper.getList("Hi", "Hello", "Yo"));
}
And the output is:
[Hi, Hello, Yo]
However, lets generate a compile-time error to see what the article is talking about within our main method:
Wrapper<T> myWrap = new Wrapper<>();
We are actually trying initialize a generic Object of the Wrapper class in the code above, but is unknown. Since the value for the placeholder will be unknown even when we call the method, it results in a compile-time error, whereas creating a List of type T within the getList method does not cause a compile-time error because it will be initialized with a type when the method is called.
once you call the method -> you are using a concrete value.
the method defines T and later you use it in the return type and the parameter list.
public static <T> List<T> getList(T... elements)
once you will send the first parameter from specific type -> the contract will force you for the next parameters.
List<? extends Object> list = getList("", 1); -> in this case java doesnt find common between string and integer so it uses the most basic connection "Object"
List<String> list2 = getList("test", "test2"); -> here you can see that because all of the parameters are Strings - java find that in common and use it as the T.
The specific passage from the book doesn't make any sense and is wrong. new ArrayList<T>() is perfectly fine provided that we are in the scope of a type parameter named T (either a type parameter of a generic class that we are in, or a type parameter of the generic method we are in).
new ArrayList<T>() can no less be instantiated than new ArrayList<String>() -- both compile to the same bytecode and both just instantiate an ArrayList object at runtime. The object doesn't know anything about its type parameter at runtime, and therefore no knowledge of T at runtime is needed to instantiate it. The type parameter in an instantiation expression of a parameterized type (new ArrayList<T>) is just used by the compiler to type-check the parameters passed to the constructor (there are none in this case) and to figure out the type returned by the expression; it is not used in any other way.
And by the way the method does not need to receive any parameters of type T, or of any type containing T, in order for this to work. A method that receives no arguments can still instantiate and return an ArrayList<T> perfectly fine:
public static <T> List<T> emptyList() {
List<T> lst = new ArrayList<T>();
return lst;
}
Also, the section in the book where this statement appears in doesn't really have anything to do with instantiation -- the section is about wildcards, and wildcards don't really have anything to do with object instantiation at all. So I am not really sure why they are mentioning it (incorrectly) there.

Using class level like generic bounded type parameters for method's formal arguments

I am trying to learn generics in java. I see that at class level we can specify bounded type parameters as class Stats <T extends Number>.
Let's say that the class has an array of type T and an average method to calculate the average of those T's and another method to check if the averages of two objects are the same or not.
However, at the method level inside the class I can't do this:
boolean isAverageSame(Stats<T extends Number> ob) if I want to find that averages of two objects are the same or not.
Instead I have to do:
boolean isAverageSame(Stats<?> ob)
Why is this the case? Is this just how the syntax was defined in java or I am missing something?
Thanks.
It sounds like you want to declare a new generic parameter for the method, in which case you could use:
<U extends Number> boolean isAverageSame(Stats<U> ob)
Note that this will allow you to do something like:
Stats<Integer> x = ...;
Stats<Float> y = ...;
boolean z = x.isAverageSame(y);
Is that what you want? If you only want to be able to compare a Stats<Integer> with a Stats<Integer> (etc) then you just need:
boolean isAverageSame(Stats<T> ob)
... in other words, the method won't introduce another generic type parameter.

How does polymorphism differ from generics in Java ArrayLists?

If I have an ArrayList<Shape>, I'm under the impression that within that list I can store objects of class Shape or objects that are subclasses of Shape.
I've also seen a lot of notation around with things like ArrayList<T> or ArrayList<?>. Are these the same things? A T superclass and all its subclasses can be stored, and the ? is just a placeholder?
Basically, how does something like ArrayList<CLASSNAME> differ from ArrayList<T> where you just have the one letter.
First, the difference is not whether it is one letter as you might think. It is whether T is the name of a generic argument or not. If you declare a method like:
public <T> void method()
as opposed to:
public void method()
or a class like:
public class Whatever<T>
as opposed to:
public class Whatever
then T is a generic argument. You then get to use T anywhere you want as if it were a real class name, and a real class name will be substituted for T at compile time. But this is not the best picture of it, so let's say that the type of T is whatever type was passed to the arguments of type T. So, at any given moment, T has a value that is a real class name.
So, the difference between ArrayList<T> and ArrayList<Shape> is that ArrayList<T> holds objects of type T, whereas ArrayList<Shape> holds objects of type Shape. The trick is that T is whatever type was passed to arguments of type T, so it can vary.
Disclaimer: The type T does not actually change over time. In most cases, the compiler replaces it with Object. However, the compiler is good at hiding that, and it is a good idea to think of T changing.
First of all, ArrayList can't reference any subclass of Shape like this:
ArrayList<Shape> blah = new ArrayList<Square>
But you can do it this way:
ArrayList<? extends Shape> blah = new ArrayList<Square>
Polymorphism doesn't work with type parameter. It only works with objects such as:
Collection<String> blah = new ArrayList<String>
But you have to understand the purpose of using T. T is used to declare a type parameter for class and methods.
Such that when you declare a class with parameter T:
public class ArrayList <T>
T acts as a placeholder when the class is instantiated as object.
So in this case:
ArrayList<String>
you are replacing T with String in the ArrayList class.
Btw, you aren't suppose to use T as a type for argument. Because T isn't really defined, it is only a placeholder.
You express ArrayList<T> when you're declaring the type / class and ArrayList<String> when you're creating an instance of ArrayList and associate it with the type parameter String.
For example:
// class declaration
public class ArrayList<T> extends ... implements ... {
...
// Creating an arraylist of string
ArrayList<String> stringArray = new ArrayList<String>
You can think of generics as a type variable. Hence instead of creating a class which only works with String:
public class MyArray {
String get(int index) { ... }
}
You can create an array class that works with any arbitrary type
public class MyArray<T> {
T get(int index) { .. }
}

I'm studying Head First Java, but I can't understand Page 544

"When you declare a type parameter for the class, you can simply use that type any place that you'd use a real class or interface type. The type declared in the method argument is essentially replaced with the type you use when you instantiate the class.
If the class itself doesn't use a type parameter, you can still specify one for a method, by declaring it in a really unusual (but available) space-before the return type, This method says that T can be "any type of Animal"."
Can you explain?
What it means is that in a generic class, you can write methods like so:
public T doSomething () {
}
Note that the return type is 'T'.
At compile-time, the return type of that method will be whatever you have passed to the generic class when you instantiated it.
class Zoo<T> {
static void putAnimal(T animal) {
// do stuff
}
}
Zoo<Ape> apeZoo = new Zoo<Ape>(); // you can now put apes (and chimps) here
Zoo<Reptile> monkeyZoo = new Zoo<Reptile>(); // this zoo takes reptiles
apeZoo.putAnimal(new Chimp());
monkeyZoo.putAnimal(new Tortoise());
For the first paragraph, this is just how generics work for classes. For instance, for list, you can create a list of a generic type, such as integer, e.g.:
ArrayList<Integer> list = new ArrayList<Integer>();
(in real code you'd use List<Integer> of course)
Now ArrayList will be defined as:
public class Arraylist<T> { // implements....
// ...
public T get(int index) {
// ...
}
}
Which is what makes it possible to use the get method on list and get an Integer (because we made a class of type ArrayList<Integer> so T = Integer). Otherwise the compiler would have no idea what types of objects the list was storing and you'd have to get the method to return an Object, which is how it used to be.
What the second paragraph means is that you can add type parameters to methods just as you can to classes. e.g.:
public <T> void noOp(T element) {
// code here
}
This would allow you, for instance, to create a static utility method that returns something of type T. To return the first element of a List of T's:
public static <T> T getFirst (List<T> list) {
return list.get(0);
}
And you could use this method in a strongly typed fashion. Suggestions for better examples welcome. :-)
edit: I just realised I once wrote something that uses this functionality. I was using the JPA API and getting really annoyed at all the times you have to return something (a list, or a single item) from a query, and running into unchecked type warnings because there's no way to infer the type here. If you're like me and trying to avoid warnings in your code, you'd have to suppress the warnings every single time. So I wrote this method to suppress the warnings for me:
#SuppressWarnings("unchecked")
public static <T> List<T> returnResultList(Query query) {
return (List<T>)query.getResultList();
}
Which through the magic of type inference works on:
List<Integer> list = returnResultList(query);

Categories