当前位置: 首页 > 知识库问答 >
问题:

Java8中的ClassFormatError?

蒋嘉颖
2023-03-14

我正在制作一个类似于LinkedListjava.util.类,得到了一个完全意想不到的类。我的IDE没有显示警告。仅供参考,我使用Java8u20。更新:固定在Java8u60。

3.T-T-h h-T-T-T-T-h-T-T-h-T-h-T-h-T-T-h h-T-T-h-T-T-T-h-T-h-T-T-T-T-T-T-T-T-h-T,i-i,i-T-i,i-T-T-T-i,i-s-a-s-s-T-T-T,i,i,i-s-s,i,i,i-s-a-a-a-s,i,i,i,i 82奈奈奈奈奈奈奈奈奈奈奈奈奈蒂蒂蒂蒂,我,我,我,本本本本研究研究,γγγ,r,r,r,r,r,r,r,r,r,r?本本本本本本s̶::,将示例更新为完全可编译:

import java.io.Serializable;
import java.util.*;
import java.util.function.Function;

public class Foo<E> implements Deque<E>, Serializable {
    private static final long serialVersionUID = 0L;

    private final Node sentinel = sentinelInit();
    private final Iterable<Node> nodes = (Iterable<Node> & Serializable) () -> new Iterator<Node>() {
        @SuppressWarnings("UnusedDeclaration")
        private static final long serialVersionUID = 0L;

        private Node next = sentinel.next;

        @Override
        public boolean hasNext() {
            return next != sentinel;
        }

        @Override
        public Node next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            Node old = next;
            next = next.next;
            return old;
        }

        @Override
        public void remove() {
             if (next.previous == sentinel) {
                throw new IllegalStateException();
            }
            removeNode(next.previous);
        }
    };

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public Object[] toArray() {
        return new Object[0];
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return null;
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return false;
    }

    @Override
    public void clear() {

    }

    @Override
    public void addFirst(E e) {

    }

    @Override
    public void addLast(E e) {

    }

    @Override
    public boolean offerLast(E e) {
        return false;
    }

    @Override
    public E removeFirst() {
        return null;
    }

    @Override
    public E removeLast() {
        return null;
    }

    @Override
    public E pollFirst() {
        return null;
    }

    @Override
    public E getFirst() {
        return null;
    }

    @Override
    public E getLast() {
        return null;
    }

    @Override
    public E peekFirst() {
        return null;
    }

    @Override
    public boolean removeFirstOccurrence(Object o) {
        return false;
    }

    @Override
    public boolean removeLastOccurrence(Object o) {
        return false;
    }

    @Override
    public E remove() {
        return null;
    }

    @Override
    public E element() {
       return null;
    }

    @Override
    public void push(E e) {

    }

    @Override
    public E pop() {
        return null;
    }

    @Override
    public boolean contains(Object o) {
        return false;
    }

    @Override
    public boolean offerFirst(E e) {
        return false;
    }

    @Override
    public E pollLast() {
        return null;
    }

    @Override
    public E peekLast() {
        return null;
    }

    @Override
    public boolean offer(E e) {
        Node node = new Node(e);
        sentinel.previous.next = node;
        node.previous = sentinel.previous;
        sentinel.previous = node;
        node.next = sentinel;
        return true;
    }

    @Override
    public E poll() {
        return null;
    }

    @Override
    public E peek() {
        return null;
    }

    @Override
    public boolean remove(Object o) {
        for (Node node : nodes) {
            if (node.value.equals(o)) {
                removeNode(node);
                return true;
            }
        }
        return false;
    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public Iterator<E> descendingIterator() {
        return null;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            private final Iterator<Node> backingIter = nodes.iterator();

            @Override
            public boolean hasNext() {
                return backingIter.hasNext();
            }

            @Override
            public E next() {
                return backingIter.next().value;
            }

            @Override
            public void remove() {
                backingIter.remove();
            }
        };
    }

    private Node sentinelInit() {
        Node sentinel = new Node();
        sentinel.next = sentinel;
        sentinel.previous = sentinel;
        return sentinel;
    }

    private void removeNode(Node node) {
        node.previous.next = node.next;
        node.next.previous = node.previous;
    }

    private class Node implements Serializable {
        private static final long serialVersionUID = 0L;
        public E value;
        public Node next;
        public Node previous;

        public Node(E value) {
            this.value = value;
        }

        public Node() {
            this(null);
        }
    }

    public static <I, O> List<O> map(Function<? super I, O> function, Iterable<I> objects) {
        ArrayList<O> returned = new ArrayList<>();
        for (I obj : objects) {
            returned.add(function.apply(obj));
        }
        return returned;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        boolean ret = false;
        for (boolean changed : map(this::add, c)) {
            if (changed) {
                ret = true;
            }
        }
        return ret;
    }

    @Override
    public boolean add(E e) {
        if (!offer(e)) {
            throw new IllegalStateException();
        }
        return true;
    }

    public static void main(String[] args) {
        Foo<String> list = new Foo<>();
        System.out.println("Constructed list");
        list.addAll(Arrays.asList("a", "B", "c"));
        System.out.println("Added a, B and c.");
        list.forEach(System.out::println);
        list.remove("B");
        list.forEach(System.out::println);
    }
}

以下是输出:

Constructed list
Added a, B and c.
Exception in thread "main" java.lang.ClassFormatError: Duplicate field name&signature in class file uk/org/me/Foo$1
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:455)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:367)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at uk.org.me.Foo.lambda$new$c83cc381$1(Foo.java:18)
    at uk.org.me.Foo$$Lambda$1/1392838282.iterator(Unknown Source)
    at uk.org.me.Foo$2.<init>(Foo.java:222)
    at uk.org.me.Foo.iterator(Foo.java:221)
    at java.lang.Iterable.forEach(Iterable.java:74)
    at uk.org.me.Foo.main(Foo.java:300)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

共有3个答案

禄源
2023-03-14

请尝试编译“文件”。jdk安装的命令行上的java文件。

使用JDK编译后,看看是否可以运行新的. class文件。如果你的类加载器在这些条件下工作,你的IDE没有使用javac的JDK副本(或者被配置为编译到不同的-目标级别)。

Eclipse曾经提供它自己的编译器(我相信现在仍然如此)。Netbeans总是遵从JDK编译器。在最近的两个版本中,JDK编译器为IDE集成做了大量工作;但是,我不认为Eclipse已经修改了他们的IDE来利用这一努力。

在任何情况下,您很快就能知道您的问题是JDK编译器还是IDE编译器。

楚意
2023-03-14

迭代的节点和名为Next私有类Node中的两个变量都具有相同的类型(Node),并且具有相同的名称:在私有类中,它们都在作用域中,但是不能消除歧义。

因此,问题不是next字段和next()方法,而是Iterable中的next命名变量

如果您重构sentinel.next为其他名称:

private final Iterable<Node> nodes = (Iterable<Node> & Serializable) () -> new Iterator<Node>() {
    @SuppressWarnings("UnusedDeclaration")
    private static final long serialVersionUID = 0L;

    private Node snext = sentinel.next;  // refactor `next` to `snext`
    ...

它将编译并运行。

作为个人注意事项,我不鼓励你编写这样的代码:阅读和弄清楚它是做什么的非常困难。

希望这有帮助!

厍书
2023-03-14

您的代码是有效的,ClassFormatError是由于Java 8编译器中的错误造成的。我认为您已经发现了一个边缘情况:加载为lambdahtml" target="_blank">表达式体生成的类文件可能会失败,该表达式体包含一个与该体中被重写的方法同名的变量。

我将您的代码粘贴到Intellij Idea(13.1.5)、NetBeans(8.0.1)和Eclipse(开普勒SR2)的最新版本中。在所有情况下编译的代码。在运行时,它失败了,在NetBeans和Idea中出现了ClassFormatError,但在Eclipse中运行良好。

堆栈跟踪显示错误是由于尝试加载由分配给实例变量Foo的lamba表达式生成的类失败引起的。节点。根本原因是在分配给Foo的lambda主体内。节点您有一个变量next,该变量与重写的方法next()同名。

正如您已经注意到的,如果您将声明中的变量重命名为私有Node Next=sentinel.next;到一些唯一的值(例如next2),问题就会消失。类似地,将其重命名为不同的重写方法(即删除hasNext)会导致问题再次出现。ClassFormatError("重复字段名")附带的消息

在失败的Idea类文件上运行javap(在我的例子中为foo/foo$1)显示:

C:\Idea\Java8\Foo\out\production\Foo\foo>"C:\Program Files\Java\jdk1.8.0_20\bin\javap.exe" Foo$1.class
Compiled from "Foo.java"
class foo.Foo$1 implements java.util.Iterator<foo.Foo<E>.Node> {
  final foo.Foo this$0;
  foo.Foo$1(foo.Foo);
  public boolean hasNext();
  public foo.Foo<E>.Node next();
  public void remove();
} 

但是,在相应的Eclipse类上运行javap(运行良好)会显示一个额外的条目:

public java.lang.Object next();

如果lambda主体中的变量Next被重命名为唯一的东西,允许代码运行,那么额外的方法条目也会神奇地出现在idea类文件中。我建议您将此作为编译器错误报告给JetBrains。

另外,作为一个不相关的问题,Iterator接口将remove()作为Java 8中的默认方法实现。因为您从不调用迭代器。remove()您可以删除两个实现。

更新:我向Oracle提出了一个关于这个问题的bug(JDK-80842),在1.8.0_60版中会有一个修复程序。

更新到更新(8/27/15):Oracle已经在8u60以后的所有版本中修复了此问题。我验证了8u60的修复。臭虫JDK-8080842指。

 类似资料:
  • 问题内容: 我正在使用jdk 1.8.0_45,我们的测试发现了路由中的错误。当决定舍入的最后一个小数为5时,RoundingMode.HALF_DOWN与RoundingMode.HALF_UP相同。 我发现了RoundingMode.HALF_UP的相关问题,但已在更新40中修复。我也向oracle放了一个bug,但根据我的经验,它们确实没有响应。 实际结果:舍入10.5556舍入10.555

  • 根据Java8中的这个链接,为了避免在map()中的冲突,使用平衡树来实现,而不是。 那么,如果: > (和其他映射()都是使用自平衡树实现的,因为最坏情况下的可访问性是相同的 我可以实现如下: 除了排序和可访问性,的其他属性是什么?

  • 我有这样的东西: 现在,我想在Java8中使用新的流过滤器API: 我对getFilteredRes_NEW()的问题是:

  • 我使用的是JDK1.8.045,我们的测试发现了路由中的一个bug。当决定舍入的最后一个小数为5时,RoundingMode.Half_Down的工作方式与RoundingMode.Half_Up的工作方式相同。 我发现了roundingmode.half_up的相关问题,但它们在更新40中得到了修复。我也给甲骨文放了一个bug,但根据我的经验,他们真的没有反应。 实际结果:下舍入10.5556上

  • 产出: 请提供2个方法将产生不同输出的例子。

  • 我有这个对象: 我想按收到日期排序; 但这似乎是不可能的,因为我得到了一个编译错误: