Java通用数组类强制转换异常

问题描述 投票:0回答:1

我正在使用以下方法创建树形图类以获取值的数组:

@SuppressWarnings("unchecked")
public V[] values() {
    V[] values = (V[]) new Object[size()];
    //System.out.println(values.getClass().getName());
    return values(root, 0, values);
}

现在,当我尝试访问此数组中的元素时,出现类强制转换异常。

private AVLTreeMap<Integer, Integer> rankingMap;
...
System.out.println(rankingMap.values()[0]); //Exception on this line

产量

Exception in thread "main" java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.Integer;

谁能解释为什么会这样以及如何解决?

谢谢。

编辑:这是整个树图类

import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;

public class AVLTreeMap<K extends Comparable<K> , V> implements /*Map<K, V>,*/ Serializable{
    private AVLTreeNode<K, V> root;
    private int size;

    public AVLTreeMap(){
        root = null;
        size = 0;
    }

    public int size(){
        return size;
    }

    public void add(K key, V val){
        root = insert(key, val, root);
        size++;
    }

    private AVLTreeNode<K, V> insert(K key, V val, AVLTreeNode<K, V> currNode){
        //AVLTreeNode<K, V> node = new AVLTreeNode<>(key, val);
        if(currNode == null) {
            return new AVLTreeNode<K, V>(key, val);
        }else if(currNode.key.compareTo(key) > 0){
            currNode.left = insert(key, val, currNode.left);
        }else if(currNode.key.compareTo(key) < 0) {
            currNode.right = insert(key, val, currNode.right);
        }else if(currNode.key.compareTo(key) == 0) {
            currNode.addDup(val);
        }
        updateNode(currNode);
        return rebalance(currNode);
    }

    private int balanceFactor(AVLTreeNode<K, V> node) {
        if(node.left == null && node.right == null){
            return 0;
        }else if(node.left == null){
            return -node.right.height;
        }else if(node.right == null){
            return node.left.height;
        }else {
            return node.left.height - node.right.height;
        }
    }

    private AVLTreeNode<K, V> rotateRight(AVLTreeNode<K, V> node){
        AVLTreeNode<K, V> swapNode = node.left;
        node.left = swapNode.right;
        swapNode.right = node;
        updateNode(node);
        updateNode(swapNode);
        return swapNode;
    }

    private AVLTreeNode<K, V> rotateLeft(AVLTreeNode<K, V> node){
        AVLTreeNode<K, V> swapNode = node.right;
        node.right = swapNode.left;
        swapNode.left = node;
        updateNode(node);
        updateNode(swapNode);
        return swapNode;
    }

    private void updateNode(AVLTreeNode<K, V> node){
        if(node.left == null && node.right == null){
            node.height = 1;
            node.size = 1;
        }else if(node.left == null){
            node.height = node.right.height + 1;
            node.size = node.right.size + 1;
        }else if(node.right == null){
            node.height = node.left.height + 1;
            node.size = node.left.size + 1;
        }else {
            node.height = Math.max(node.left.height, node.right.height) + 1;
            node.size = node.left.size + node.right.height + 1;
        }
    }

    private AVLTreeNode<K, V> rebalance(AVLTreeNode<K, V> node) {
        if (balanceFactor(node) < -1) {
            if (balanceFactor(node.right) > 0) {
                node.right = rotateRight(node.right);
            }
            node = rotateLeft(node);
        }
        else if (balanceFactor(node) > 1) {
            if (balanceFactor(node.left) < 0) {
                node.left = rotateLeft(node.left);
            }
            node = rotateRight(node);
        }
        return node;
    }

    public String tree(){
        return tree(root, 0, false);
    }

    private String tree(AVLTreeNode<K, V> node, int tabs, boolean left){
        String s = "\n";
        for (int i = 0; i < tabs - 1; i++) {
            s+="        ";
        }
        s += "----";
        if(node.left == null && node.right == null){
            return s + "|"  + node.toString();
        }else if(node.left == null){
            return s + "        |null" + s + "|" +  node.toString() + "|" + tree(node.right, tabs + 1, false);
        }else if(node.right == null){
            return tree(node.left, tabs + 1, true) + s + "|"+ node.toString() + "|" + s+  "        |null";
        }
        return tree(node.left, tabs + 1, true)  + s + "|"+ node.toString() +"|" + tree(node.right, tabs + 1, false);
    }

    @SuppressWarnings("unchecked")
    public K[] keys() {
        K[] keys = (K[]) new Comparable[size()]; //https://stackoverflow.com/questions/34827626/cannot-be-cast-to-ljava-lang-comparable
        return keys(root, 0, keys);
    }

    private K[] keys(AVLTreeNode<K, V> node, int idx, K[] keys){
        if (node != null) {
            keys = keys(node.left, idx, keys);
            idx += (node.left != null) ? node.left.size : 0;
            keys[idx++] = node.key;
            for (int i = 0; i < node.dups; i++) {
                keys[idx++] = node.key;
            }
            keys = keys(node.right, idx, keys);
        }
        return keys;
    }

    @SuppressWarnings("unchecked")
    public V[] values() {
        V[] values = (V[]) new Object[size()];
        //System.out.println(values.getClass().getName());
        return values(root, 0, values);
    }

    private V[] values(AVLTreeNode<K, V> node, int idx, V[] values){
        if (node != null) {
            values = values(node.left, idx, values);
            idx += (node.left != null) ? node.left.size : 0;
            values[idx++] = node.val;
            addDuplicates(node, values, idx);
            idx += node.dups;
            values = values(node.right, idx, values);
        }
        return values;
    }

    private void addDuplicates(AVLTreeNode<K, V> node, V[] arr, int idx){
        DuplicateNode<V> dup = node.nextDup;
        for (int i = 0; i < node.dups; i++) {
            arr[idx++] = dup.val;
            dup = dup.next;
        }
    }

    private static class AVLTreeNode<K, V>{
        public int height;
        public AVLTreeNode<K, V> left;
        public AVLTreeNode<K, V> right;
        public K key;
        public V val;
        public int dups;
        public int size;
        public DuplicateNode<V> nextDup;

        public AVLTreeNode(K key, V val){
            this.key = key;
            this.val =val;
            left = null;
            right = null;
            size = 1;
            height = 1;
            dups = 0;
            nextDup = null;
        }

        public void addDup(V val){
            DuplicateNode<V> dup = new DuplicateNode<>(val);
            dup.next = nextDup;
            nextDup = dup;
            dups++;
            size++;
        }

        public String toString(){
            return key.toString();
        }
    }

    private static class DuplicateNode<V>{
        public V val;
        public DuplicateNode<V> next;

        public DuplicateNode(V val){
            this.val = val;
            next = null;
        }
    }
}

我得到了正确值但类型不正确的数组。

java generics casting
1个回答
0
投票

您可能会考虑为什么java.util.Collection.toArray有两个重载:

  • 一个不带参数的返回Object[]
  • 一个采用数组参数E[],并返回类型为E[]的数组。

原因是无法构造通用数组。如果可能的话,就不需要第二种方法。

[您需要采取相同(或相似)的方法:将V[]作为可用于构造数组实例的参数:

public V[] values(V[] array) {
    // Basically, this: http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/classes/java/util/AbstractCollection.java#l176
    V[] values = (V[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size());

    //System.out.println(values.getClass().getName());
    return values(root, 0, values);
}

还有其他选择。例如,您可以将Supplier<V[]>(或V[]VClass<V>)传递给构造函数,然后在values()中使用它:

public AVLTreeMap(IntFunction<V[]> arraySupplier){
  this.arraySupplier = arraySupplier;  // Assign to a field
}

public V[] values() {
    V[] values = arraySupplier.apply(size());
    // ...
}

您应该根据构造和使用该类的负担来选择方法。

© www.soinside.com 2019 - 2024. All rights reserved.