Java Generics: Why does my @SuppressWarnings ("unchecked") work in this case, but not another?

The question is similar to this. Why should we use an intermediate variable for @SuppressWarnings ("unchecked"?)? but I could not get a solution from this.

As an exercise, I build a hash table design from scratch. So I wrote an additional LinkedListDemo class for HashTableDemo; LinkedListDemo tests are great. In particular, the following routine does not throw ClassCastException errors at runtime:

public LinkedListDemo<S, T> reverse() { if (count == 0) return null; @SuppressWarnings("unchecked") S[] keys = (S[]) new Object[count]; @SuppressWarnings("unchecked") T[] vals = (T[]) new Object[count]; ListNode<S, T> runner = head; for (int k = 0; k < count; k++) { keys[k] = runner.pair.getKey(); vals[k] = runner.pair.getValue(); runner = runner.next; } ArrayUtils.reverse(keys); ArrayUtils.reverse(vals); return new LinkedListDemo<S, T>(keys, vals); } 

While in my HashTable class the following:

 public class HashTableDemo<S, T> { private LinkedListDemo<S, T>[] table = (LinkedListDemo<S, T>[]) new Object[10]; // more code... } 

Does anyone know how the Java HashMap class circumvents this issue and / or how can I? I tried to create an intermediate variable inside the constructor, as indicated in the link above, but that didn't work.

+4
source share
1 answer

This will compile:

 @SuppressWarnings("unchecked") // this is okay because [insert reasoning here] private LinkedListDemo<S, T>[] table = (LinkedListDemo<S, T>[]) new LinkedListDemo<?, ?>[10]; 

The reason for your code errors is that Object[] not LinkedListDemo[] , similar to how Object not LinkedListDemo .

Earlier unverified roles work because S[] and T[] were erased before Object[] at runtime.

In general, arrays of parameterized types are discouraged because their very existence is unsafe. This is because:

  • Arrays are covariant - a LinkedListDemo<S, T>[] is Object[] . Thus, you can assign table variable Object[] , and then assign String as an element - this will be legal at compile time, but at least it will fail at runtime with ArrayStoreException , as arrays do a runtime type check.
  • Generic type information is not available at runtime because it was deleted by the compiler. You can again assign table variable Object[] , but this time assign LinkedListDemo<String, Integer> as an element. At run time, the array would only see that a simple LinkedListDemo was added, so it would not immediately crash if the generic types are wrong. This may lead to an unexpected ClassCastException at a later time.

See my answer here for a more complete explanation and example of this problem. See also this wonderful explanation from the Angelika Langer Generics FAQ: Can I create an array whose component type is a specific parameterized type?

The conclusion is that it will be simpler and safer to just use List<LinkedListDemo<S, T>> . If you ultimately decide to use LinkedListDemo<S, T>[] , make sure that it is carefully hidden as part of the implementation and does not understand how it can be used incorrectly.

A few other notes:

  • @SuppressWarnings("unchecked") does nothing but suppress the immediate compiler warning. Essentially, he said, “Believe me, I know what I'm doing,” but you still need to be careful that the uncontrolled actor does not abuse. See This Post for more information: How to send unverified throw warnings?
  • Like all major API classes, a source is available for HashMap , so you can freely view it if you want to better understand its internal workings.
+3
source

Source: https://habr.com/ru/post/1484009/


All Articles