为什么带有varargs的Java方法会被标识为瞬态?

21
我正在使用Java反射API进行实验,发现带有可变参数列表的方法会变成瞬态。为什么会这样,这种情况下transient关键字是什么意思?
Java词汇表中,transient的定义如下:
“Java编程语言中的一个关键字,表示字段不是对象序列化形式的一部分。当对象被序列化时,其瞬态字段的值不包括在序列化表示中,而其非瞬态字段的值则包括在其中。”
然而,这个定义并未涉及到方法。有什么想法吗?
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Dummy {
    public static void main(String[] args) {
        for(Method m : Dummy.class.getDeclaredMethods()){
            System.out.println(m.getName() + " --> "+Modifier.toString(m.getModifiers()));
        }
    }

    public static void foo(int... args){}
}

输出:

main --> public static
foo --> public static transient

2
哦,有意思!我曾经以为方法不会被序列化,现在我很好奇。 - Kris
1
@biziclop,有什么惊人之处,试试Modifier.toString(-1),更好。 - bestsss
3个回答

21

javassist AccessFlag的代码中可以找到一个类似答案。

public static final int TRANSIENT = 0x0080;
public static final int VARARGS   = 0x0080;

看起来它们的值都相同。由于 transient 对方法没有意义,而对字段来说 varargs 也没有意义,所以它们相同是可以的。

但是 Modifier 类不考虑这一点是不合适的。我会提出一个问题。需要一个新的常量-VARARGS和一个新的方法-isVarargs(..)。并且 toString() 方法可以重新编写以包括“transient/varargs”。


2
Modifier.toString() 接受一个 int 类型的参数,然后从中获取信息;由于没有区分字段/方法,因此它永远不可能正确。 - bestsss
@bestsss - 那是真的。但是可以添加另一种方法,它以AccessibleObject作为参数。或者只需将两者都添加到消息中(请参见我的更新)。 - Bozho
AccessibleObject 不适用于 Class,需要使用 Object - bestsss
Reflection Modifier API 设计不足。就像 Java 的许多其他部分一样,我认为我们只能接受这种情况。现在是2016年,我仍然在使用Java 8时遇到相同的问题。 - Martin Kersten
@Martin Kersten:Modifier.toString(int) 的文档说明,你应该首先使用 methodModifiers() 对位进行 AND 运算,以获得方法的正确结果(这是自 Java 7 开始的官方解决方案)。当然,直接使用 Method.toString() 更容易,这是获取适当的 Java 8 的 default 修饰符的唯一方式... - Holger
但是Modifier类不考虑这一点是不可以的:Modifier类无法考虑到这一点,因为它不知道标志位来自哪里。 - user207421

6

1
为什么会出现bug?你可以传递任意数字,但是结果可能会出错。 - bestsss
@bestsss- 这是一个很好的观点。我原本以为Modifier类有更多关于标志位来源的信息。 - templatetypedef

4
在方法的上下文中,瞬态字段的标志已被重载,表示该方法是可变参数方法。同样,在方法的上下文中,易失性字段的标志被重载,表示该方法是桥接方法。请参阅:http://java.sun.com/docs/books/vmspec/2nd-edition/ClassFileFormat-Java5.pdf,第118-122页(或PDF文件中的第26-30页)。更新:阅读Modifier.java的源代码可以确认这个答案的第一句话(“瞬态字段的标志已被重载”)。以下是相关的源代码:
// Bits not (yet) exposed in the public API either because they
// have different meanings for fields and methods and there is no
// way to distinguish between the two in this class, or because
// they are not Java programming language keywords
static final int BRIDGE    = 0x00000040;
static final int VARARGS   = 0x00000080;
static final int SYNTHETIC = 0x00001000;
static final int ANNOTATION  = 0x00002000;
static final int ENUM      = 0x00004000;
static final int MANDATED  = 0x00008000;

1
这个答案是最接近正确答案的,应该被采纳。ClassFileFormat的链接已经失效。 - Jason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接