var does not give a warning for generic - java

In Java 10, this is giving me a warning -
ArrayList a = new ArrayList<>();
a.add(23);
a.add("str");
"ArrayList is a raw type. References to generic type ArrayList
should be parameterized"
And the reason is Generic behind, but for this code
var b = new ArrayList<>();//Object type
b.add(3);
b.add("string");
Why was any warning not given by compiler?
Note:- I know var is limited to method scope. Just wanted to know design concept resected to generics for var
Edit1:- Don't mark as duplicate as I just wanted to know about internal design and why java not added generic stuff for var?

Here's how the compiler computes the type of
var b = new ArrayList<>();
It starts by computing the standalone type of the initializer. Because the initializer is a diamond invocation, we must use inference. So we introduce an inference variable alpha, and the type on the RHS is ArrayList<alpha>. Now we must solve for alpha.
To solve, we gather constraints. We start with the primordial constrain that alpha <: Object (because all type variables are reference types). We then look to the constructor args (nothing there) and the target type (nothing there) to gather constraints. So the only constraint we have is alpha <: Object, and so we choose alpha=Object, and get ArrayList<Object> on the RHS. That's the type of b.
No raw type here, hence no warning.

Because it is an ArrayList<Object>. Object is the top level type in Java which represents any type, so it is always safe to add anything to the list.
In the first example, you got a warning because you used a raw type. Raw types are legacy in Java and only exist for backward compatibility. You should not use them.

Related

Generic array to int array method call? (Error: The method sort(T[]) in the type (...) is not applicable for the arguments (int[]) [duplicate]

Why do generics in Java work with classes but not with primitive types?
For example, this works fine:
List<Integer> foo = new ArrayList<Integer>();
but this is not allowed:
List<int> bar = new ArrayList<int>();
Generics in Java are an entirely compile-time construct - the compiler turns all generic uses into casts to the right type. This is to maintain backwards compatibility with previous JVM runtimes.
This:
List<ClassA> list = new ArrayList<ClassA>();
list.add(new ClassA());
ClassA a = list.get(0);
gets turned into (roughly):
List list = new ArrayList();
list.add(new ClassA());
ClassA a = (ClassA)list.get(0);
So, anything that is used as generics has to be convertable to Object (in this example get(0) returns an Object), and the primitive types aren't. So they can't be used in generics.
In Java, generics work the way that they do ... at least in part ... because they were added to the language a number of years after the language was designed1. The language designers were constrained in their options for generics by having to come up with a design that was backwards compatible with the existing language and the Java class library.
Other programming languages (e.g. C++, C#, Ada) do allow primitive types to be used as parameter types for generics. But the flip side of doing this is that such languages' implementations of generics (or template types) typically entail generation of a distinct copy of the generic type for each type parameterization.
1 - The reason generics were not included in Java 1.0 was because of time pressure. They felt that they had to get the Java language released quickly to fill the new market opportunity presented by web browsers. James Gosling has stated that he would have liked to include generics if they had had the time. What the Java language would have looked like if this had happened is anyone's guess.
In java generics are implemented by using "Type erasure" for backward compatibility.
All generic types are converted to Object at runtime.
for example,
public class Container<T> {
private T data;
public T getData() {
return data;
}
}
will be seen at runtime as,
public class Container {
private Object data;
public Object getData() {
return data;
}
}
compiler is responsible to provide proper cast to ensure type safety.
Container<Integer> val = new Container<Integer>();
Integer data = val.getData()
will become
Container val = new Container();
Integer data = (Integer) val.getData()
Now the question is why "Object" is chose as type at runtime?
Answer is Object is superclass of all objects and can represent any
user defined object.
Since all primitives doesn't inherit from "Object" so we can't use it
as a generic type.
FYI : Project Valhalla is trying to address above issue.
As per Java Documentation, generic type variables can only be instantiated with reference types, not primitive types.
This is supposed to come in Java 10 under Project Valhalla.
In Brian Goetz paper on State of the Specialization
There is an excellent explanation about the reason for which generic were not supported for primitive. And, how it will be implemented in future releases of Java.
Java's current erased implementation which produces one class for all reference instantiations and no support for primitive instantiations. (This is a homogeneous translation, and the restriction that Java's generics can only range over reference types comes from the limitations of homogeneous translation with respect to the bytecode set of the JVM, which uses different bytecodes for operations on reference types vs primitive types.) However, erased generics in Java provide both behavioral parametricity (generic methods) and data parametricity (raw and wildcard instantiations of generic types.)
...
a homogeneous translation strategy was chosen, where generic type variables are erased to their bounds as they are incorporated into bytecode. This means that whether a class is generic or not, it still compiles to a single class, with the same name, and whose member signatures are the same. Type safety is verified at compile time, and runtime is unfettered by the generic type system. In turn, this imposed the restriction that generics could only work over reference types, since Object is the most general type available, and it does not extend to primitive types.
The collections are defined to require a type which derives from java.lang.Object. The basetypes simply don't do that.

What type is <?> when making instantiating lists?

I have seen in multiple different places people who instantiate a list or ArrayList like:
List<?> l = new ArrayList<>();
What type is ?? Does this mean that it can hold any types in it? If so, why would this be used instead of just and ArrayList?
Does this mean that it can hold any types in it?
No. It means that your l variable could be referring to a list parameterized with any type. So it's actually a restriction: you will not be allowed to add any object to l because you have no idea which items it accepts. To give a concrete example, l could be a List<String> or it could be a List<ExecutorService>.
As correctly pointed by Marko, its an unknown restriction on the List type.
The Java docs says that:
The unbounded wildcard type is specified using the wildcard character
(?), for example, List<?>. This is called a list of unknown type.
There are two scenarios where an unbounded wildcard is a useful
approach:
If you are writing a method that can be implemented using functionality provided in the Object class.
When the code is using methods in the generic class that don't depend on the type parameter. For example, List.size or List.clear.
In fact, Class<?> is so often used because most of the methods in
Class do not depend on T.
Let me make this a long bed time story; read it to fall asleep:)
Let's begin with this point -- To invoke a generic method, its type arguments must be supplied. (Unless the method is invoked in a "raw" manner, i.e. in the erased form, which is another topic:)
For example, to invoke Collections.<T>emptyList(), T must be supplied. It can be supplied explicitly by the programmer --
List<String> list = Collections.<String>emptyList(); // T=String
But that is tedious, and kind of dumb. Obviously in this context, T can only be String. It's stupid if the programmer has to repeat the obvious.
That's where type inference is helpful. We can omit the type argument, and the compiler can infer what the programmer intends it to be
List<String> list = Collections.emptyList(); // T=String is implied
Remember, <String> is still supplied, by the programmer, implicitly.
Supposedly, the programmer is the all-knowing dictator of all type arguments, and, the compiler and the programmer have a common understanding on when type arguments can be omitted and inferable from context. When the programmer omits a type argument, he knows the compiler can infer it exactly as he intended, based on a rigorous algorithm (which he masters:)
It is not the compiler's discretion to pick and choose type arguments, rather, the programmer does, and conveys it to the compiler.
Realistically, type inference is so complex, few no programmer has any idea what's going on in a lot of cases:) The programmer is more like a dictator making vague commands, and the compiler tries its best to make sense out of it. We mostly write code on intuition, not paying attention to details, and we sort of believe that the code does what we want if the compiler approves it.
In any case, all type arguments are fixed precisely and predictably at compile time. Any omitted type argument is equivalent to an explicitly specified one.
Some type arguments are "undenotable", e.g. a type variable introduced by capture conversion. They can not be explicitly specified, they can only be inferred. (Nevertheless the programmer is supposed to know what they are, even though they cannot be named)
In the previous example, T can only be inferred as String, there's no other choices. But in a lot of cases, there are more candidates for T, and the type inference algorithm must have a strategy to resolve it to one of the candidates. For example, consider this lonely statement
Collections.emptyList();
T could be any type; T is resolved to Object, because, well, there's no good reason to resolve it to anything else, like Integer or String etc. Object is more special because it's the supertype of all.
Now, let's get to constructors. Formally speaking, constructors are not methods. But they are very much alike in a lot of aspects. Particularly, type inference on constructors is almost the same as on methods. Invoking a constructor of a class CLASS takes the form of new CLASS(args).
Just like methods, a constructor can be generic, with its own type parameters. For example,
class Bar
{
<T>Bar(T x){ .. }
and type inference works on generic constructors too
new Bar("abc"); // inferred: T=String
To explicitly supply type arguments for a constructor,
new <String>Bar("abc");
It's pretty rare though that a constructor is generic.
A generic constructor is different from a generic CLASS! Consider this
class Foo<T>
{
Foo(T x){ .. }
The class is generic, the constructor is not. To invoke the constructor for class Foo<String>, we do
new Foo<String>(""); // CLASS = Foo<String>
Method type inference we've been talking about so far does not apply here, because the constructor is not even generic. In Java 5/6, there is no type inference on CLASS, therefore <String> must be explicitly specified. It's stupid, because <String> is obvious in this context. There were workarounds (i.e. using static factory methods), but people were of course very upset and demanded a solution.
In Java 7, this problem is solved by "diamond inference" -
new Foo<>(""); // inferred: T=String
"diamond" refers to the curious <> operator. It is required; we cannot simply write
new Foo("");
because that already had a different meaning - invoking the constructor of "raw" Foo.
With diamond inference, we can do things we couldn't in Java 5/6
List<Object> list = new ArrayList<>(); // Java 7. inferred: E=Object
// equivalent to
List<Object> list = new ArrayList<Object>(); // <Object> is required in Java 5/6
Remember, T=Object is still supplied, through diamond inference.
Finally, we come back to your original question
List<?> list = new ArrayList<>();
Here, E=Object is inferred (what else?). The code is equivalent to
List<?> list = new ArrayList<Object>();
Yep, the list object is indeed an ArrayList<Object>, not ArrayList<SomethingElse>.
Also note that the following would be illegal and nonsensical
List<?> list = new ArrayList<?>();
^^^
CLASS in new CLASS(args) must be a concrete type. We can only instantiate an ArrayList of a specific element type.
The declared type List<?> of variable list is too general though. For a local variable, it is the best practice IMO to declare it in its more specific type
ArrayList<Object> list = new ArrayList<>();
Don't use <?> here - it just causes confusion to everybody.
On a related note, a lot of people would argue for "program against interface"
List<Object> list = new ArrayList<>();
^^^^
That is wrong IMO. Who are we providing abstraction for in a local block? Use the most specific type in implementation for max clarity;
use abstract types in interfaces.
zzzzzzzzzz

Java: using typed variables in a generic class

Could someone please explain to me why this piece of code does not compile?
Even though it uses a generic class without providing the specific type T, it should be able to recognize at compile time that the ArrayList holds strings.
public class Test {
public static void main(String[] args){
Container container = new Container();
container.strings.add("test");
String s1 = container.strings.get(0); // does not compile
ArrayList<String> local = container.strings;
String s2 = local.get(0); // does compile
}
static class Container <T>{
ArrayList<String> strings = new ArrayList<String>();
}
}
When you use a generic class as a raw type (one where you don't specify a type), ALL generic information is stripped from the class (whether the omitted type is used or not).
So when you code Container container (instead of Container<SomeClass> container) ArrayList<String> strings becomes ArrayList strings, which is used as if it were ArrayList<Object>.
To "fix", specify the type for Container (even though you don't use the type):
Container<Object> container = new Container<Object>();
the rest will now compile.
The reason this is done is to be backward compatible with earlier pre-generic versions of java (1.4 and earlier)
As Bohemian said, every type argument in a raw type is thrown away. At the beginning I thought it was a bug, but there's even an entry in the bug database (#6244346) which explicitely quotes the relevant JLS §4.8
The type of a constructor (§8.8), instance method (§8.4, §9.4), or
non-static field (§8.3) M of a raw type C that is not inherited from
its superclasses or superinterfaces is the raw type that corresponds
to the erasure of its type in the generic declaration corresponding to
C.
The type of a static method or static field of a raw type C is the
same as its type in the generic declaration corresponding to C.
It is a compile-time error to pass type arguments to a non-static type
member of a raw type that is not inherited from its superclasses or
superinterfaces.
It is a compile-time error to attempt to use a type member of a
parameterized type as a raw type.
The reason why you can't get a String from a raw List, but you can assign a List to a List<String> is because in the latter the compiler issues a warning (unchecked conversion) but you don't report it (do you read warnings, don't you? :P). I tested your code with javac and the Eclipse compiler, and both honor the spec.
Raw types were introduced for interoperability with legacy code, but in this case I can't figure out a way how keeping type information for non-static members would have break things. Using a parameterized type instead of a raw type would mean code partially ported, so maybe in this case the purpose is not simply backcompat, but ensuring a coherent codebase, either the code is full 1.4, or it's entirely Java 5+. Another option is that using raw types like this may have slowed down the adoption of unbounded wildcards in similar contexts.
BTW (but I think you figured it out by yourself) you can simply use an unbounded wildcard if you don't use the type parameter, ie Container<?>

What is the use and point of unbound wildcards generics in Java?

I don't understand what is the use of unbound wildcards generics. Bound wildcards generics with upper boundary <? extends Animal> makes perfect sense, because using polymorphism I can work with that type or collection. But what is the point of having generics that can be of any type? Doesn't it defeat the purpose of generics? Compiler doesn't find any conflict and after type erasure it would be like no generics was used.
An unbound type can be useful when your method doesn't really care about the actual type.
A primitive example would be this:
public void printStuff(Iterable<?> stuff) {
for (Object item : stuff) {
System.out.println(item);
}
}
Since PrintStream.println() can handle all reference types (by calling toString()), we don't care what the actual content of that Iterable is.
And the caller can pass in a List<Number> or a Set<String> or a Collection<? extends MySpecificObject<SomeType>>.
Also note that not using generics (which is called using a raw type) at all has a quite different effect: it makes the compiler handle the entire object as if generics don't exist at all. In other words: not just the type parameter of the class is ignored, but also all generic type parameters on methods.
Another important distinctions is that you can't add any (non-null) value to a Collection<?>, but can add all objects to the raw type Collection:
This won't compile, because the type parameter of c is an unknown type (= the wildcard ?), so we can't provide a value that is guaranteed to be assignable to that (except for null, which is assignable to all reference types).
Collection<?> c = new ArrayList<String>();
c.add("foo"); // compilation error
If you leave the type parameter out (i.e. use a raw type), then you can add anything to the collection:
Collection c = new ArrayList<String>();
c.add("foo");
c.add(new Integer(300));
c.add(new Object());
Note that the compiler will warn you not to use a raw type, specifically for this reason: it removes any type checks related to generics.
When you need to perform an instanceof check.
You can't parameterize like this:
Object value;
if (value instanceof List<String>) {
// ...
}
So you do:
Object value;
if (value instanceof List<?>) {
// ...
}
While using raw types means that you don't know about generics (because you're lazy or code was written ages ago), using <?> means that you know about generics and explicitly emphasize that your code can work with any kind of objects.
There are (rare) perfectly correct use cases for unbound wildcards. The SDK contains some of them.
One example is a method that does a definite action on a list of any kind and does not return anything as rotate in Collections:
static void rotate(List<?> list, int distance)
Another example is when you want to list the possible constructors for a class, the method is :
Constructor<?>[] getConstructors()
Here it in not even possible to use a generic, because by definition the array will contain different constructor each with its own actual class. By contrast, the API does use a generic signature for getting one single constructor : Constructor<T> getConstructor(Class<?>... parameterTypes).
The conclusion is that even if it is mainly used for compatibility with older code, there are still places where unbound wildcard generics are the correct way.
Allow me to rephrase the question:
"What is the difference between List<Object> and List<?> ?"
The answer to that is that List<?> is more restrictive. It tells us that we have a bunch of object of some type, but that type is not necessarily Object.
Since we don't know what that type is, we cannot add to the list at all - anything we add may be of wrong type. In fact, we cannot pass any argument of ? type to any method, not just add().
On the plus side, when we specify that a method takes List<?>, it can take List<String> or List<Integer> or any other List<>. List<Object> can only take List<Object>.
Using unbounded wildcards only makes sense, AFAIK, when wrapping old code that is not using generics, basically Collections.
If you look at what you can do with such a generic it's basically nothing.
If you have a collection you can't add anything, if you try to read something out you will always get an Objectand so on.
This in turns helps guaranteeing that you will handle the data in a type safe way, whereas using the raw type would have caused the compiler to ignore any mess you'd make.
Which methods and fields are accessible/inaccessible through a reference variable of a wildcard parameterized type? from Angelika Langers Java Generics FAQ might be of interest.
List<Object> is a List that may contain any Object, e.g. l[0] may be an Integer, l[1] may be a String, etc.
List<?> may be a List<Integer> or List<String>, etc. If it is a List<Integer>, it stores only Integers, if it is List<String>, it stores only Strings.

Wikipedia says for Generics - "One version of the class or function is compiled, works for all type parameters. "

How does Java do this? If there are not multiple Classes being created, then how does it support multiple Typed instantiations of the Generic class?
Until now I used to believe that it is like C++, but now i am totally confused.
Can't figure out how Java pulls this off?
-Ajay
This is due to type erasure. Java's generics are primarily a compile-time feature. All generic types are, at runtime, Objects replaced with their lower bound.
Thanks to Michael for the correction:
Generics are not strictly a compile-time feature. If a class, method or field has a generic type with a concrete type parameter specified, this information will be present at runtime and is available via reflection.
To elaborate:
When runtime inspecting a parameterizable type itself, like java.util.List, there is no way of knowing what type is has been parameterized to. This makes sense since the type can be parameterized to all kinds of types in the same application. But, when you inspect the method or field that declares the use of a parameterized type, you can see at runtime what type the paramerizable type was parameterized to. In short:
You cannot see on a type itself what type it is parameterized to a runtime, but you can see it in fields and methods where it is used and parameterized. Its concrete parameterizations in other words.
Source
Since only reference types can be used as generic type arguments in Java, and all pointers are the same size, the same byte code can be used.
As for type safety, generics in Java a compile/link-time only. That is, during compilation generic types are replaced by their erasure. The erasure of a type variable T is its lower bound (or Object, if it doesn't have one). For instance,
class Complex<N extends Number> {
N real;
N imag;
}
becomes
class Complex {
Number real;
Number imag;
}
as far as byte code is concerned.
Needless to say that is not pretty and causes numerous limitations. The most obvious one is that
new N();
does not compile, because the runtime does not know the type N stands for and hence can't instiate the type. Similarly,
(N) n
will compile, but unlike an ordinary cast in Java, will not be checked at runtime. An incorrect cast can therefore cause a variable to hold an object of the wrong type. This is called heap pollution. To ensure (a weaker form of) type safety, the compiler will introduce casts into calling code. For instance,
boolean right(Complex<Integer> c) {
return c.real > 0;
}
will become
boolean right(Complex c) {
return ((Integer) c.real) > 0;
}
To sum things up, the generics implementation in Java is not pretty, especially compared to the .NET one. The things we have to live with for the sake of backwards compatibility ...
good question. The genetic information is not kept during runtime. E.g if you have this code
List<Apple> apples = new ArrayList<Apple>(); // this is a list of apples
But in runtime it becomes :
List apples = new ArrayList(); // this is how it looks in runtime

Categories

Resources