本文介绍了Class#getInterfaces() 和 Class#getGenericInterfaces() 返回不同长度的数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果你从 Scala 2.10.2 中获取类 scala.runtime.AbstractPartialFunction(我没有检查其他版本)并比较 AbstractPartialFunction.class.getInterfaces() 的输出code> 和 AbstractPartialFunction.class.getGenericInterfaces() 您可能会注意到,结果不匹配.通用接口是 scala.Function1scala.PartialFunction,而 getInterfaces() 只返回 scala.PartialFunction代码>.从 scala 文档中我可以看到通用信息是正确的,因为 PartialFunction 是一个 Function1.

If you take the class scala.runtime.AbstractPartialFunction from Scala 2.10.2 (I did not check other versions) and compare the output of AbstractPartialFunction.class.getInterfaces() and AbstractPartialFunction.class.getGenericInterfaces() you may notice, that the results do not match. The generic Interfaces are scala.Function1<T1, R> and scala.PartialFunction<T1, R>, while getInterfaces() only returns scala.PartialFunction. Form the scala documentation I can see that the generic information is right, because PartialFunction is a Function1.

getInterfaces 的 javadoc 说:

The javadoc for getInterfaces says:

如果这个对象代表一个类,则返回值是一个包含代表该类实现的所有接口的对象的数组.数组中接口对象的顺序与该对象表示的类的声明的implements 子句中接口名称的顺序相对应.

和 getGenericInterfaces 具有完全相同的文本.

and getGenericInterfaces has the exact same text.

从那个(以及其他文本,包括 stackoverflow 信息)我会得出结论,数组的顺序和长度是相等的.只是这里的情况并非如此.为什么?

From that (and from other texts, including stackoverflow information) I would conclude that order and length of the arrays are equal. Only this is not the case here. Why?

到目前为止,我能够用几个 java7 和 java8 重现这个,没有尝试 java6 甚至 java5.

I was able to reproduce this with several java7 and java8 so far, didn't try java6 or even java5.

AbstractPartialFunction 的 javap 输出(当然只有头文件)是:

The javap output for AbstractPartialFunction (only the header of course) is:

Compiled from "AbstractPartialFunction.scala"
public abstract class scala.runtime.AbstractPartialFunction<T1, R> implements scala.Function1<T1, R>, scala.PartialFunction<T1, R>`

使用 asm lib 和 Textifier 在那里我可以看到这个标题信息:

Using the asm lib and the Textifier there I can see this header information:

// class version 50.0 (50)
// access flags 0x421
// signature <T1:Ljava/lang/Object;R:Ljava/lang/Object;>Ljava/lang/Object;Lscala/Function1<TT1;TR;>;Lscala/PartialFunction<TT1;TR;>;
// declaration: scala/runtime/AbstractPartialFunction<T1, R> implements scala.Function1<T1, R>, scala.PartialFunction<T1, R>
public abstract class scala/runtime/AbstractPartialFunction implements scala/PartialFunction

加上一个ScalaSigAttribute.当然我没有展示两种情况下的方法

plus a ScalaSigAttribute. Of course I did not show the methods in both cases

推荐答案

// Compiled from AbstractPartialFunction.scala (version 1.6 : 50.0, super bit)
// Signature: <T1:Ljava/lang/Object;R:Ljava/lang/Object;>Ljava/lang/Object;Lscala/Function1<TT1;TR;>;Lscala/PartialFunction<TT1;TR;>;
@scala.reflect.ScalaSignature(bytes="some bytes...")
public abstract class scala.runtime.AbstractPartialFunction implements scala.PartialFunction {

类型的签名大致相当于这个Java声明:

The signature of the type is roughly equivalent to this Java declaration:

class AbstractPartialFunction implements PartialFunction, Function1 {}

PartialFunction 扩展了 Function1:

// Compiled from PartialFunction.scala (version 1.6 : 50.0, no super bit)
// Signature: <A:Ljava/lang/Object;B:Ljava/lang/Object;>Ljava/lang/Object;Lscala/Function1<TA;TB;>;
@scala.reflect.ScalaSignature(bytes="some bytes...")
public abstract interface scala.PartialFunction extends scala.Function1 {

这里是一个Java类文件:

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

类型实现的接口存储在常量池中,并通过interfaces数组中的引用记录:

The interfaces the type implements are stored in the constant pool and recorded by references in the interfaces array:

类签名是存储为 attributes 数组中的属性:

The class signature is stored as an attribute in the attributes array:

Signature 属性记录任何类、接口、构造函数或成员的通用签名信息,这些类、接口、构造函数或成员在 Java 编程语言中的通用签名将包括对类型变量或参数化类型的引用.

所以这是我对正在发生的事情的有根据的猜测:

So here's my educated guess about what is happening:

  • Class.getInterfaces() 返回 interfaces 数组中的值
  • Class.getGenericInterfaces() 使用类型签名构建其返回值
  • Scala 编译器从 interfaces 数组中删除了 Function1,因为 PartialFunction 扩展了 Function1
  • Scala 编译器按原样保留类型签名
  • Class.getInterfaces() returns the values from the interfaces array
  • Class.getGenericInterfaces() builds its return value using the type signature
  • the Scala compiler removes Function1 from the interfaces array because PartialFunction extends Function1
  • the Scala compiler preserves the type signature as-is

这种行为与 Oracle JDK 从等效 Java 源生成的字节码不同,但它显然通过了 JVM 在加载类时所做的所有检查.

This behavior is different to the byte code that the Oracle JDK produces from equivalent Java sources but It's obviously passing all the checks the JVM makes when loading classes.

这篇关于Class#getInterfaces() 和 Class#getGenericInterfaces() 返回不同长度的数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-02 16:05