有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

反射获取java。调用方法时发生lang.NullPointerException。援引

我遵循这个tutorial on Java annotaitons并实现了测试注释,如图所示。但是当运行代码时,我得到以下输出

java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at TestAnnotationParser.parse(Demo.java:24)
    at Demo.main(Demo.java:51)
Passed:0   Fail:1

下面是我的代码。有人能指出我做错了什么吗

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Test {
    Class expected();
}

class TestAnnotationParser {
    public void parse(Class<?> clazz) throws Exception {
        Method[] methods = clazz.getMethods();
        int pass = 0;
        int fail = 0;

        for (Method method : methods) {
            if (method.isAnnotationPresent(Test.class)) {
                Test test = method.getAnnotation(Test.class);
                Class expected = test.expected();
                try {
                    method.invoke(null);
                    pass++;
                } catch (Exception e) {
                    if (Exception.class != expected) {
                        e.printStackTrace();
                        fail++;
                    } else {
                        pass++;
                    }
                }
            }
        }
        System.out.println("Passed:" + pass + "   Fail:" + fail);
    }
}

class MyTest {

    @Test(expected = RuntimeException.class)
    public void testBlah() {
    }
}

public class Demo {
    public static void main(String[] args) {
        TestAnnotationParser parser = new TestAnnotationParser();
        try {
            parser.parse(MyTest.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

共 (4) 个答案

  1. # 1 楼答案

    对你的问题Method#invoke有答案:

    public Object invoke(Object obj,
                Object... args)
                  throws IllegalAccessException,
                         IllegalArgumentException,
                         InvocationTargetException
    

    抛出: NullPointerException-如果指定的对象为null,并且该方法是实例方法

  2. # 2 楼答案

    传递给invoke的参数必须是调用该方法的对象,除非该方法是static。你通过反思所做的相当于:

    MyTest obj = null;
    obj.testBlah();
    

    当然,这里有一个NPE。要解决此问题,请传递一个要调用该方法的对象,或使该方法static

    下面是一种修复方法:

    public <T> void parse(Class<T> clazz, T obj) throws Exception {
        Method[] methods = clazz.getMethods();
        int pass = 0;
        int fail = 0;
    
        for (Method method : methods) {
            if (method.isAnnotationPresent(Test.class)) {
                Test test = method.getAnnotation(Test.class);
                Class expected = test.expected();
                try {
                    method.invoke(obj);
                    pass++;
                } catch (Exception e) {
                    if (Exception.class != expected) {
                        e.printStackTrace();
                        fail++;
                    } else {
                        pass++;
                    }
                }
            }
        }
        System.out.println("Passed:" + pass + "   Fail:" + fail);
    }
    
    ...
    
    parser.parse(MyTest.class, new MyTest());
    

    Demo on ideone

  3. # 3 楼答案

    这个问题在这里:

    method.invoke(null);
    

    该方法的第一个参数是调用该方法的对象。这是类似这样的动态(反射)等价物:

    Object foo = null;
    foo.toString();
    

    当然,我们希望这段代码给出一个NullPointerException,因为foonull

  4. # 4 楼答案

    问题是您正在将一个空目标对象传递给method.invoke(object)方法。 目标对象不应为null,否则应为nullpointerexception

    invoke方法有以下用法:

    Method.invoke(targetObject, args1, args2, args3...); where args1, args2, args3 etc are argument to the method being invoked.