This is heapifying the array question and
this is my constructor of the heapcls which extends to Comparable
heapcls(T[] arr,boolean flag){
this(flag);
for (T item : arr) {
this.data.add(item);
}
for(int i=this.data.size()-1;i>=0;i--){
this.downheapify(i);
}
}
public static void main(String[] args) {
int[]arr={7,8,9,5,11,3,10,1,6,2,4,12,0,-1,13};
heapcls<Integer> client=`enter code here`new heapcls<>(arr,false);
}
this statement is giving ," Cannot infer type arguments error"
how should I change my CompareTo(by default function) to rectify the error.
since i havent overridden the bydefault CompareTo function.pls guide me.
The actual issue is that you're trying to pass an int[] to a constructor which has T[] as a parameter. Since the type on the left-hand side of the assignment is heapcls<Integer>, the constructor is supposed to have Integer[] passed to it as an argument.
Type arguments to generic types can't be primitive types and arrays of primitives aren't autoboxed. (Autoboxing an array would require allocating an entire new array.)
It seems like you could fix this just by using Integer[] instead of int[].
I'm not really sure why we get the "cannot infer type arguments" message in cases like this. I think it's a bug with the Java compiler when using the diamond type (i.e. <>) and the arguments to the constructor aren't applicable to any of the declared constructors. (Here's a much more minimal example showing the same issue with the error message: http://ideone.com/wJx16i.)
In any case, your code shouldn't compile, but because you're trying to pass an int[] as an argument to a constructor which effectively has Integer[] as a parameter, not really because the type arguments can't be inferred.
As a side note, class names in Java start with an upper-case character by convention, so your heapcls should be HeapCls (and probably just something like Heap).
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.
This question is specific to using varargs with generic-fied Enum<E>s:
Why do I get this warning Type safety: Potential heap pollution via varargs parameter elements if I define the method the like this:
<E extends Enum<E>> void someMethod(E... elements)
As opposed to this:
<E extends Enum<E>> void someMethod(E[] elements)
Accordingly, what should I look out for before declaring the method #SafeVarargs?
Similar questions
This question is similar to these questions regarding Collection<T>... but the scenarios shown in those answers do not seem to apply with Enum<E>...:
Potential heap pollution via varargs parameter
Type safety: Potential heap pollution via varargs parameter subtrees
Potential heap pollution via varargs parameter
Eclipse different behaviour for "Unchecked" warning due to "Potential heap pollution via varargs parameter". How to fix?
It is the reverse of this question which questions why there are no warning:
Why doesn't the following method produce potential heap pollution?
Sample code
This is what I tried to pollute the heap, but each bad attempt results in java.lang.ArrayStoreException and not a polluted array.
I am using Eclipse 4.6.0 and Java JDK 8u74.
public static void main(String[] args) {
Foo[] x = { Foo.A };
someMethod(x);
Foo y = x[0]; // How does one get a ClassCastException here?
}
private static enum Foo {
A, B, C,
}
private static enum Bar {
X, Y, Z,
}
// This produces a "Type safety" warning on 'elements'
private static <E extends Enum<E>> void someMethod(E... elements) {
Object[] objects = elements;
// Test case 1: This line throws java.lang.ArrayStoreException
objects[0] = "";
// Test case 2: Program terminates without errors
objects[0] = Foo.A;
// Test case 3: This line throws java.lang.ArrayStoreException
objects[0] = Bar.X;
}
There is a warning for the varargs method because varargs methods can cause implicit array creation at the calling site, whereas the version that takes an array parameter doesn't. The way that varargs works is that it causes the compiler to create an array at the call site filled with the variable arguments, which is then passed to the method as a single array parameter. The parameter would have type E[], so the array created should be an E[].
First, in the call site in your example, you are not using the variable arguments functionality at all. You are passing the array of variable arguments directly. So there is no implicit array creation in this case.
Even if you had used the variable arguments functionality, e.g. with someMethod(Foo.A);, the implicit array creation would be creating an array with a reifiable type, i.e. the variable argument type is known at the call site to be Foo which is a concrete type known at compile-time, so array creation is fine.
The problem is only if the variable argument type at the call site is also a generic type or type parameter. For example, something like:
public static <E extends Enum<E>> void foo(E obj) {
someMethod(obj);
}
Then the compiler would need to create an array of this generic type or type parameter (it needs to create an E[]), but as you know generic array creation is not allowed in Java. It would instead create an array with the component type being the erasure of the generic type (in this example it would be Enum), so it would pass an array of the wrong type (in this example, the passed array should be an E[], but the array's actual runtime class would be Enum[] which is not a subtype of E[]).
This potential wrong type of array is not always a problem. Most of the time, a varargs method will simply iterate over the array and get elements out of it. In this case, the runtime class of the array is irrelevant; all that matters is that the elements are type E (which indeed they are). If this is the case, you can declare your method #SafeVarargs. However, if your method actually uses the runtime class of the passed array (for example, if you return the varargs array as type E[], or you use something like Arrays.copyOf() to create an array with the same runtime class), then a wrong runtime class of the array will lead to problems and you cannot use #SafeVarargs.
Your example is a bit weird because, well, you are not even using the fact that the elements are of type E, let alone the fact that the array is E[]. So you could use #SafeVarargs, and not only that, you could simply declare the array as taking Object[] in the first place:
private static void someMethod(Object... objects)
I faced this issue and hence posting it as complete solution -
With Java 8, the below code will fail with Runtime exception. The problem is getInteger method is returning a generic Integer type and print method expects exact Object Type.
public static void main(String[] args) {
print(getInteger());
}
private static <T> T getInteger() {
return (T)new Integer(10);
}
private static void print(Object...o1){
for(Object o: o1){
System.out.println(o);
}
}
Your code mixes type inference with varargs.
In Java 7, it worked because there was no target type inference: the type of getInteger call was resolved as just Object, and then the object was boxed into an Object[] to fit the varargs call.
With Java 8, T is inferred from the target type as Object[]. Since you perform an unchecked cast in getInteger, this is completely valid, and mandated by the method signature resolution rules, which will consider varargs only if resolution failed without considering it. Here, that was not the case.
Lesson: by performing the unchecked type cast you have waived your right to expect type safety and correctness. You should be prepared to take care of it yourself.
As part of solution choose any of the following.
Break method call and argument pass in two calls –
Integer i = getInteger();
print(i);
Or
Call print method with Typed argument –
print(Main.<Integer>getInteger());
I hope it will help.
When instantiating ArrayLists I am used to seeing code like this
ArrayList<Type> arr = new ArrayList<Type>();
or
ArrayList<Type> arr = new ArrayList<>();
however today I have come across an instantiation of ArrayList that looks like this:
ArrayList<Type> arr = new <Type>ArrayList();
what is going on, and why does that give an "unsafe operations" compile warning?
Edit:
Yes, found the reference. See JLS §15.12.2.1 - Identify Potentially Applicable Methods:
If the method invocation includes explicit type arguments, and the
member is a generic method, then the number of type arguments is equal
to the number of type parameters of the method.
This clause implies that a non-generic method may be potentially
applicable to an invocation that supplies explicit type arguments.
Indeed, it may turn out to be applicable. In such a case, the type
arguments will simply be ignored.
Emphasis mine.
Also see JLS §15.9.3 - Choosing the Constructor and its Arguments, for understanding how the constructor invocation is resolved. It also mentions that the above mentioned process is followed for resolution.
Original answer:
Such kind of invocation is often required, when you have a generic constructor, and the compiler is not able to infer the correct type arguments. For example, consider the below code:
class Demo<T> {
public <X> Demo(X[] arg1, X arg2) {
// initialization code
System.out.println(arg1.getClass());
System.out.println(arg2.getClass());
}
}
Suppose you invoke that constructor like this:
Demo<String> demo = new Demo<String>(new String[2], new Integer(5));
You would think that the type inference should fail, as the type arguments should have same types. Here we're passing String and Integer types. But it doesn't. The compiler infers the type X as:
Object & Serializable & Comparable<? extends Object&Serializable&Comparable<?>>
Now, you might want the type parameter to be inferred as just Object, then in that case, you can provide explicit type arguments, as in the below code:
Demo<String> demo = new <Object>Demo<String>(new String[2], new Integer(5));
This is similar to how you give explicit type argument while method invocation.
Now, in your code, you have given the explicit type arguments, but you're using raw type of the class to instantiate it:
ArrayList<Integer> arr = new <String>ArrayList();
The <String> is the explicit type argument for the constructor, and compiler will be fine with it. But the issue is, you're instantiating raw type ArrayList, and that is where compiler is giving your unchecked warning. If you change that code to:
ArrayList<Integer> arr = new <String>ArrayList<>();
The warning will go away. But since ArrayList constructor is not a generic constructor, the type argument seems to be just ignored by the constructor. In fact there is no use of that type argument there.
Strangely enough, this also compiles:
public static void test() { }
public static void main(String... args) {
Main.<Integer>test();
}
...even though test() is a non-generic method.
I've just tried:
ArrayList<Integer> arr = new <String>ArrayList();
And got the same warning (not an error!). Looks like the compiler ignores1 the generics after the new keyword and before the ArrayList. It's just like writing:
ArrayList<Integer> arr = new ArrayList();
1 I'm not sure if it really "ignores" that, I'll be glad if someone confirms/correct me
The code, it does nothing!
int a = new <String>Integer(5);
It also compiles but generates a warning of "unused generics".
So basically it is useless but not bad enough to generate an error by default it seems. Either way your arraylist is NOT properly generified here.
Please note that generics are compiled away anyway so at the bytecode level it probably won't look any different. I have looked in eclipse for a way to turn this into an error instead of warning but no luck there.
UPDATE
This answer boils down to the same as the other one which is currently at +5, so why is mine downvoted? Please leave a comment if you downvote.
Given the following not-very-useful code:
package com.something;
import java.util.ArrayList;
import java.util.Collection;
//Not a generic class!
public class Test {
public <T> void plain(T param1, T param2) {}
public <T> void fancy(T param1, Collection<T> param2) {}
public void testMethod() {
//No error
fancy("", new ArrayList<String>());
//Compiler error here!
fancy("", new ArrayList<Integer>());
//No error
plain("", new ArrayList<Integer>());
}
}
(Please correct my understanding if it's wrong!)
The 2nd call to fancy() is a compiler error because Java can't infer any common type between the two arguments (can't infer Object since the second parameter must be a Collection.)
The call to plain() is not a compiler error because Java infers the common type of Object between the two arguments.
I recently came across code that had a method signature similar to plain().
My question is this:
Is plain()'s signature useful for anything?
Perhaps the person who wrote that code thought that plain()'s signature would enforce that both parameters have the same type at compile time, which is obviously not the case.
Is there any difference from or benefit to writing a method with a signature like plain() rather than just defining both parameters to be Objects?
While the compiler does not infer the generic type one might intend, it will enforce type constraints that are explicitly specified. The following invocation results in a type error.
this.<String>plain("", new ArrayList<Integer>()); /* Compiler error. */
The parameterized method <String>plain(String, String) of type Test is not applicable for the arguments (String, ArrayList<Integer>)
I guess you could say it serves as some sort of documentation, so that the user knows that you expect both arguments to be of the same type. Of course, any two objects are of the same type to some degree (they're all Object), so it's a meaningless statement.
Long story short, it's a useless signature.
Of course, if plain returned a type T, that'd be a different story.
The 2nd call to fancy() is a compiler error because Java can't infer
any common type between the two arguments (can't infer Object since
the second parameter must be a Collection.)
Well, I am not sure this is the reason, I would say the reason is that the generic type T in Collection<T> is an invariant whose value determines the type of the first parameter T.
For instance, this is valid:
fancy("", new ArrayList<CharSequence>()); //compiles Ok
Because all String are CharSequences. It is expected that the first parameter is a CharSequence once the type is inferred from ArraysList<CharSequence>.
However, this is not valid:
fancy((CharSequence)"", new ArrayList<String>()); //compiler error
Because it is expected the type of the first parameter be String, and we cannot ensure that all CharSequences are, in fact, of type String, right?
So, AFAIK, the reason the types are not compatible is due to the nature of generics in this case, and not to the fact that the second type is a Collection.