I know that java is not supposed support generic arguments which are primitive types, and sure enough something like:
Vector<byte> test;
will fail to compile.
however with a little slight-of-hand that I accidentally performed in a program, I found that it is actually possible to create a generic object with a primitive type (technique shown below)
Furthermore, java falsely allows this instance to be assigned to a variable of type Vector<Byte> when as the print statements show, byte.class and Byte.class are two separate beasts. Because of this, attempts to do calls on the object result in unexpected and strange behaviors/errors.
Is this a java bug? or is there some rhyme or reason to this madness? It seems like even if java allowed the unexpected behavior of creating primitive-typed generics, they should not be assignable to a generic of the wrapper type which is of a distinct class from the primitive.
import java.util.Vector;
public class Test
{
//the trick here is that I am basing the return type of
//the vector off of the type that was given as the generic
//argument for the instance of the reflections type Class,
//however the the class given by byte.class yields a non-class
//type in the generic, and hence a Vector is created with a
//primitive type
public static <Type> Vector<Type> createTypedVector(Class<Type> type)
{
return new Vector<Type>(0,1);
}
public static void main(String ... args)
{
//these lines are to demonstrate that 'byte' and 'Byte'
//are 2 different class types
System.out.println(byte.class);
System.out.println(Byte.class);
//this is where I create an instance of type Vector<byte>
//and assign it to a variable of type Vector<Byte>
Vector<Byte> primitiveTypedGenericObject = createTypedVector(byte.class);
//this line causes unexpected exceptions to be thrown
//because primitiveTypedGenericObject is not actually type
//Vector<Byte>, but rather Vector<byte>
primitiveTypedGenericObject.set(0,(byte)0xFF);
}
}
Both Byte.class and Byte.TYPE are Class<Byte> objects. The latter are just used to distinguish between primitive type and object type.
Actually Byte.TYPE is defined as:
public static final Class<Byte> TYPE = (Class<Byte>) Class.getPrimitiveClass("byte");
and getPrimitiveClass is an opaque method which retrieves the type from the VM so we can't investigate it further.
So, even if you think that you are passing a primitive data type Class, since they don't exist (why should they, since they refer to something that is typable according to the Java typing system for objects, which doesn't include primitive types until they are boxed into wrapper classes), you are creating a Vector<Byte>.
But in the end this doesn't matter much, upon reaching run-time execution type annotations are erased and the generic type doesn't mean anything. Whenever you'll add a byte it will be autoboxed to a Byte object and that's it.
I have no way to test your code at the moment, which exceptions are thrown at runtime when adding items to the Vector?
You've stumbled upon autoboxing and unboxing. See http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html
The nutshell version
List<Integer> list = new List<Integer>();
list.add(1); // works
byte.class, int.class, etc. resolve to Byte, Integer, etc. See the Java Language Specification, 15.8.2:
15.8.2. Class Literals
......
The type of p.class, where p is the name of a primitive type (§4.2), is Class<B>, where B is the type of an expression of type p after boxing conversion (§5.1.7).
The type of void.class (§8.4.5) is Class<Void>.
No! It is not bug. It is called Autoboxing. When you pass byte to a generic method that expects Byte, the compiler automatically Autoboxes it to Byte which is an instance of Object. The antithesis of that operation is called Auto Unboxing and that is why operations like the one shown below are legal.
int a = new Integer(5);
Integer b = 5;
Related
I am doing tasks from the Java SE 8 book by Cay S. Horstmann (Chapter 6 task 21)
Using the #SafeVarargs annotation, write a method that allows you to build arrays of generalized types, as in the following example:
List<String>[] result = Arrays.<List<String> > construct (10) ;
// Sets the result in a list of type List<String>[] with a length of 10
My intended solution was such
static <T> T[] construct(int size) {
ArrayList<String> arr = new ArrayList<>();
for (int i = 0; i < size; i++) arr.add(null);
return (T[]) arr.toArray();
}
but it is incorrect since after erasing occurs
Exception in thread "main" java.lang.ClassCastException: class
[Ljava.lang.Object; cannot be cast to class [Ljava.util.List;
([Ljava.lang.Object; and [Ljava.util.List; are in module java.base of
loader 'bootstrap') at Main.main(Main.java:23)
Don’t use this in production code. This is only for answering the book’s question as-is, for educational purpose. See the end of the answer for details.
The #SafeVarargs does already provide a hint towards the intended solution. Make the method a varargs method. Since a variable number of arguments also allows zero arguments, this change allows unchanged invocations:
public class Example
{
#SafeVarargs
static <T> T[] construct(int size, T... template) {
return Arrays.copyOf(template, size);
}
public static void main(String args[])
{
List<String>[] result = Example.<List<String>>construct(10);
System.out.println(result.getClass().getComponentType());
}
}
Note that you don’t need explicit type parameters here. The caller can be simplified to
List<String>[] result = Example.construct(10);
which implies that we can even omit the declaring class when being in the same class or using import static …
List<String>[] result = construct(10);
But when the caller does provide arguments to the varargs parameter, they may show up in the resulting array. To enforce an array with only null elements, you could use
#SafeVarargs
static <T> T[] construct(int size, T... template) {
return Arrays.copyOf(Arrays.copyOf(template, 0), size);
}
or
#SafeVarargs
static <T> T[] construct(int size, T... template) {
T[] array = Arrays.copyOf(template, size);
Arrays.fill(array, null);
return array;
}
which can be tested with
List<String>[] result = construct(10, Collections.emptyList());
System.out.println(result.getClass().getComponentType());
System.out.println(Arrays.toString(result));
But as said, don’t use this code. The creation of generic arrays is not allowed for a reason. Consider
List<String>[] result = construct(10);
Object[] array = result;
array[0] = Arrays.asList(42);
List<String> stringList = result[0];
// this situation is called heap pollution
// at an entirely different place in you application, you might do
String s = stringList.get(0);
// without understanding what's going on
The reason why this code does not produce a warning, is that the #SafeVarargs prevents this and is used incorrectly here. For a varargs method to be safe, we must prevent any assignment to the array (this applies to copies of the array as well), but as soon as we return a generic array, we can’t guaranty this. As the user newacct correctly pointed out, there’s not even a guaranty that the array’s raw element type matches the intended type, e.g. if the caller also uses a type variable for T. If this has an impact on a method’s behavior, it must not use the #SafeVarargs annotation.
It's a common mistake. arr.toArray() returns Object[] and then you try to cast it to List[] array. Unlike generics the type of arrays is not removed during runtime. That's why you get a class cast exception.
It's not possible to write such a method in Java that will work in all circumstances, and I can prove it. The mention of #SafeVarargs indicates that they want you to use varargs, and the varargs semantics does allow you to do some interesting things, but it will still not allow you to write such a method that works in all circumstances.
When you have a varargs method in Java like someMethod(int size, String... args), it receives a second argument of type String[], and when you call it with (0 or more) String arguments (and not a String[] argument directly), the compiler will implicitly create a new array like new String[] { ... } and pass that to the method under the hood.
The varargs parameter can also be of type variable type like someMethod(int size, T... args). If you call this method with 0 or more T arguments, the compiler will also try to implicitly create an array of the arguments. If the compiler knows (whether by inference or you explicitly specified) that for this call T is a reifiable type like String, then it will do new String[] { ... } with no problems.
However, when the compiler's (inferred or explicitly specified) T for this call is a parameterized type or a type variable, there is a problem because Java does now allow creating an array of a parameterized type (e.g. new List<String>[...]) or an array of a type variable type (e.g. new U[...]). What Java does is implicitly create an array with the component type being the erasure of what it inferred T to be. So if T for this call is List<String>, it will create new List[] { ... }, and if T for this call is U, then it will create an array of the upper bound of U; so if U is unbounded, this would be new Object[] { ... }. It will then produce a warning to indicate that this is unsafe.
The reason why this warning is necessary is that the runtime type of the varargs array object received in the method is not compatible with the parameter's declared type (this is called "heap pollution"). In the case where the expected type is an array of a parameterized type (e.g. List<String>[]) and it creates an array of the raw type (e.g. List[]), the difference is mostly not a big deal (although there are still some reasons why a warning is a good idea that I won't go into), and in fact people often use new List[...] as a workaround when needing to create an array of a parameterized type. However, in the case where the expected type is an array of a type variable type (e.g. U[]), creating an array of the upper bound type (e.g. Object[]) is potentially a big problem, because if this is returned to a scope which expects U to be a specific type (e.g. String), then it will expect U[] to be String[], and an array of runtime type Object[] will not be able to be put into that type since String[] and Object[] are actually separate classes at runtime, and Object[] is not a subclass of String[].
For most varargs methods that take T[], they just iterate through the varargs arguments, and they just care that the elements are of type T, and don't care that the runtime type of the varargs array object is T[]. In such cases, Java provides a #SafeVarargs annotation that can be put on the method to suppress this warning. However, in varargs methods that do care about the runtime type of the varargs array object, you should not use this annotation, because it suppresses the warning that warns of a real problem.
#Holger's answer, which is probably what the book's author was thinking of, takes advantage of varargs' implicit array creation. Even in the case of 0 variable arguments, the compiler still implicitly creates an array of the right type, and the array carries runtime information about its component type, which the method can try to use to create the array to return. So in the case of Arrays.<List<String>>construct(10), even though it doesn't look like you are passing any information in at runtime about the component type of the array, you actually are because the compiler implicitly passes a new List[] {}, and this carries the type List into the method at runtime. (Again, there is a difference between List and List<String>, but the difference is minor, and in most cases, you are not going to run into problems with this.) But this only works because the component type (List) is known at compile time, so the compiler can hard-code it at compile-time.
If you instead call this method where the component type is not known at compile time, i.e. is a type variable like Arrays.<U>construct(10), then the only thing that the compiler can send into it is new Object[], i.e. the only type information that can be passed into the method at runtime is the upper bound of the type variable (because that is known at compile time), but not the actual type that the type variable represents. The method can then only create an array with runtime type of Object[], which is incompatible with the right type of U[] (unless U happens to be Object). As mentioned above, the compiler usually generates a warning when this happens, but the book suggests you to use #SafeVarargs to suppress this warning, so you wouldn't get a warning. (And #SafeVarargs is not suitable for such a method, because it does use the runtime type of the varargs array object to create its new array.)
We can extend this further to create a proof by contradiction that the method that the question asks for is impossible in Java. We assume that there does exist a way to write the method, and assume that we have the working implementation of construct(), that is annotated with #SafeVarargs. Then we can use it to write this method:
public static <U> U[] foo(int size) {
return construct(int);
}
This method takes a size, and returns an array of the desired component type with that size, without needing to be passed any information at runtime about what that component type is. This method does not use varargs, so there is no varargs shenanigans like implicit arguments under the hood. This is just a plain non-varargs method that just takes one parameter, the size. It compiles no warnings (since construct() is annotated with #SafeVarargs). It is very obvious that this method is impossible in Java. To create an array in Java, we need to provide the component type at runtime, and this method purports to magically be able to create an array of any type you want, without you telling it what type it is that you want at runtime. This is basically creation of an array of type variable type (i.e. new U[...]), and we know that this is not possible. Since this is a contradiction, that proves that the assumption that there exists a way to write the construct() method, is false.
If you limit the circumstances that the method has to work in to only those where the component type is a reifiable type or parameterized type, and not a type variable type, then #Holger's answer would qualify. But 1) that was not stipulated in the question from the book, and 2) such a restriction would go against the whole spirit of generics, since a generic method should work just as well no matter if it's called with T being a concrete type or type variable -- it shouldn't care at all.
I know what is going on inside of my code, and how to fix an error. However, I do not understand why things happen the way they do. Specifically, why my method returns interface List instead of ArrayList interface implementation?
What confuses me the most is after implementing moons as ArrayList, it still returns the interface.
Thanks in advance!
private static ArrayList<HeavenlyBody> makingSetOfMoons(){
List<HeavenlyBody> moons = new ArrayList<>();
for(HeavenlyBody planet : Main.planets){
moons.addAll(planet.getSatellites());
}
return moons;
}
Error output:
Incompatible types. Found: 'java.util.List<com.practice.HeavenlyBody>', required: 'java.util.ArrayList<com.practice.HeavenlyBody>'
Let's look at your method declaration:
private static ArrayList<HeavenlyBody> makingSetOfMoons(){
Java expects the method to return an ArrayList<HeavenlyBody>
But you return the moons variable which is declared:
List<HeavenlyBody> moons = ....
It doesn't matter what type of List subtype that you assign to the variable -- Java sees the variable as a List<HeavenlyBody>, pure and simple. Even if you assign an ArrayList<HeavenlyBody> to this variable, the Java compiler cannot use this to do an automatic implicit cast for you, because you could later in the method change the object that the variable refers to, now or later, and this could cause problems. As Jon Skeet states here:
The compiler uses the declared type of the variable to know how it can be used... it's as simple as that.
One solution is to change the moons variable to:
ArrayList<HeavenlyBody> moons = ...
This would work but would be wrong since it is almost always better to "code to the interface" (see: What does it mean to “program to an interface”?). Better to change the return type expected by the method in its declaration:
private static List<HeavenlyBody> makingSetOfMoons() {
This all gets down to the difference between a reference variable and a reference (or object), specifically the type of each. It is a fine distinction but an important one.
The variable and its type:
List<HeavenlyBody> moons
This variable is a reference variable that refers to an object, as opposed to a primitive variable that refers to a primitive type.
Currently you assign this reference to the variable:
new ArrayList<>();
and so the type of the variable is List<HeavenlyBody> and the type of the reference that it refers to is ArrayList<HeavenlyBody>
The compiler expects method to return object of type ArrayList or more specific one (class that extends ArrayList). However, the type of moons variable returned from the method is less specific, i.e. List.
In this case, it is not important for the compiler what specific type does an instance assigned to moons variable have - the implementation you are asking about - only the variable type matters.
I hope this answers your question, if not please ask, I'll try to elaborate.
Important thing that you seem to be missing in your understanding is two parts of the following expression:
Type identifier = new SubType();
Beware, that identifier is a variable of type Type (and not directly of type SubType), and it can store a reference to the object of any other type, as long as that "other" type is a subtype of Type (including Type itself, as type is a sub-type of itself in Java).
Therefore:
private static ArrayList<HeavenlyBody> makingSetOfMoons() {
List<HeavenlyBody> moons = new ArrayList<>();
...
return moons;
}
will not compile, as the type of moons is List<HeavenlyBody>.
Q: Why this is designed so?
A: Because
in Java programming language, every variable and every expression has a type that is known at compile time.JSL - Chapter 4: Types, Values, and Variables
Imagine you had:
public ArrayList<SomeType> something(List<SomeType> list) {
...
return list;
}
You can observe, that List<SomeType> list can accept anything that is sub-type of it; however, if you, in this case, were allowed to return list (of type List<SomeType>), there is a big chance you would have received a runtime exception, as not every sub-type of List<E> can be converted to ArrayList<E>.
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.
In java API documentation, it is written that Boolean wrapper class have 3 fields. True, False and Type.
For Type they have given description that:
TYPE: The Class object representing the primitive type boolean.
I can't understand what is this "type" field for?
Every Java class is represented in a running Java program by an object of type java.lang.Class, which, amongst other things, lets you perform reflective operations upon objects of that type. You can normally get to an object's Class by calling obj.getClass(), or by specifying its name explicitly, eg. String.class.
Primitive types, like int and boolean, don't have a class to represent them. But there are situations where it would be appropriate to have a Class object for them, and the TYPE members of the wrapper class types (like java.lang.Integer and java.lang.Double) represent exactly these Class objects.
You might be given one if you perform reflective operations on, say, an array of booleans, like this:
boolean[] bools = new boolean[1];
Class<?> c = bools.getClass().getComponentType();
Assert.assertEquals(Boolean.TYPE, c); // passes!
Note that the primitive boolean class is NOT the same as the Boolean wrapper class! That is,
Assert.assertNotSame(Boolean.TYPE, Boolean.class); // passes!
TYPE is a Class<Boolean> compile-time constant of the Boolean wrapper class representing the primitive type (boolean) the Boolean class wraps around.
The same is in all object wrappers: they all have a TYPE constant representing their primitive counterpart (e.g. Integer.TYPE).
It is used in the reflection API, to represent the type of a boolean argument or return type of a method, or the type of a field of a class.
I accidentally found that this works:
Class<?> a;
a = int.class;
System.out.println(a); // int
a = Integer.class;
System.out.println(a); // class java.lang.Integer
What does it really mean / do for primitives?
I tried and neither List<int> nor List<int.class> works (yeah, I know I have to use Integer). Also, obviously, I can't invoke getClass() on primitives, so it's useless for type checking of any sort.
In what situation would I use int.class and why is it even present in the language?
You would use it when you are trying to locate a method having an int argument via the reflection API.
From the specs:
The type of p.class, where p is the name of a primitive type
(§4.2), is Class<B>, where B is the type of an expression of
type p after boxing conversion (§5.1.7).
And
A class literal evaluates to the Class object for the named
type (or for void) as defined by the defining class loader
(§12.2) of the class of the current instance.
So how about
Class<Integer> a = int.class;
When to use: Lots of reflection use cases (for instance in argparse4j they use it to map from command line parameters to methods).