Class类中的getDeclaredMethods()

时间:2018-01-05 12:30:12

标签: java reflection

java.lang.ClassNotFoundException: com.datastax.spark.connector.rdd.partitioner.CassandraPartition
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:348)
        at org.apache.spark.serializer.JavaDeserializationStream$$anon$1.resolveClass(JavaSerializer.scala:67)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1863)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1746)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2037)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2282)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2206)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2064)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:428)
        at org.apache.spark.serializer.JavaDeserializationStream.readObject(JavaSerializer.scala:75)
        at org.apache.spark.serializer.JavaSerializerInstance.deserialize(JavaSerializer.scala:114)
        at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:309)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

有如下文档。

public Method[] getDeclaredMethods() throws SecurityException

单个类如何具有两个具有不同返回类型,相同名称和相同参数类型的[声明]方法?

3 个答案:

答案 0 :(得分:5)

Java语言中不可能声明两个具有相同名称和参数类型但返回类型不同的方法。

然而,Java虚拟机(JVM)处理方法没有问题。

通过使用更具体的返回类型覆盖基类方法,可以隐式创建此类方法。

如果基类有一个方法Object foo(),并且您的类使用方法String foo()覆盖它,那么您的类的.class文件将具有合成(因此不是&#34) ;可见")方法Object foo()和"正常"方法String foo()。存在Object foo()方法,以便与希望将您的类视为基类实例的类兼容,并且不了解String foo()覆盖。

此外,一些非Java语言可能允许您明确地使用这些方法创建类。

答案 1 :(得分:1)

一个简单的例子:

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

public class MultipleMethods implements Callable<String> {
    public static void main(String[] args) {
        for(Method m: MultipleMethods.class.getDeclaredMethods()) {
            System.out.println(m);
        }
    }

    @Override
    public String call() {
        return "just an example";
    }
}

Test on ideone.com

public static void MultipleMethods.main(java.lang.String[])
public java.lang.Object MultipleMethods.call() throws java.lang.Exception
public java.lang.String MultipleMethods.call()

由于类型擦除,接口Callable有一个方法java.lang.Object call(),尝试调用该方法的代码只会查找该方法,因此,已插入名为bridge method以完成协议并委托给实际的实现方法String call()。您可以通过Method.isBridge()确定桥接方法。

使用covariant return types而不使用Generics时会创建相同类型的桥接方法,如this answer所述。此外,正如本答案所述,类文件可能是通过Java源代码之外的其他方式创建的,并且由于JVM可以处理仅在返回类型方面不同的方法,因此这些方法可能出现在这些类中而没有桥接语义。

顺便说一下,在字节码级别,甚至声明的字段都按名称​​和类型进行区分,因此,如果它们的类型不同,则不需要具有唯一的名称。没有办法使用Java源代码生成具有相同名称的声明字段的类文件,但是,如上所述,这不是创建类文件的唯一方法。

答案 2 :(得分:0)

您可能会混淆具有不同名称的getDeclaredMethod() : MethodgetDeclaredMethods() : Method[]privateGetDeclaredMethods() : Method[]混淆。

但是,您可以使用相同名称,相同返回类型但参数不同的方法。这可能是因为Java中的method overloading

为简单起见,这是一段非常合法的代码:

public class Test {
    public int get(int a) {
        return a;
    }

    public int get() {
        return 0;
    }
}

这不是:

public class Test {
    public int get() {
        return 0;
    }

    public long get() {
        return 0;
    }
}