天天看點

[Java]反射:getDeclaredConstructors newInstance wrong number of arguments

1. 在進行單例反射操作的時候報錯:newInstance wrong number of arguments

public class Lazy {

    private static boolean initialized = false;

    private Lazy() {
        synchronized (Lazy.class){
            System.out.println("lazy : " + initialized);
            if (!initialized){
                initialized = true;
            }else {
                throw new RuntimeException("單例被反射");
            }
        }
    }

    public static final Lazy getInstance(){
        return LazyHolder.instance;
    }

    private static class LazyHolder{
        private static final Lazy instance = new Lazy();
    }
}      
Class<?> clazz = Lazy.class;
        Constructor < ? > [] constructors = clazz.getDeclaredConstructors();
        System.out.println("constructors size: " + constructors.length);

for (Constructor c:
             constructors) {
            c.setAccessible(true);
            Object o = c.newInstance(new Object[] {null});
        }      

最開始的時候,Object o = c.newInstance()這樣使用直接報錯,構造方法都不能進去需要添加參數才能進去.

但是構造體能進去了,仍然報wrong number of arguments

參考:​​https://stackoverflow.com/questions/14491699/java-reflections-error-wrong-number-of-arguments​​

**補充: getDeclaredConstructors()與getConstructors()差別是,前者public/private都get,後者隻拿public

2. 那問題來了,為什麼我Lazy類裡面隻有一個constructor,但是constructors傳回的長度是2呢

那我debug一下:

[Java]反射:getDeclaredConstructors newInstance wrong number of arguments

發現竟然是這樣的:constructor[1]裡面的才是我想要的private的constructor,是以直接newInstance()不帶參是不報錯的

那$1是什麼?

原來Java中類後面$1表示類中存在内部類,普通内部類編譯出class為内部類類名$1,匿名内部類編譯成class為類$1

也就是說constructor[0]是内部類的constructor,再看debug

[Java]反射:getDeclaredConstructors newInstance wrong number of arguments

我們看到c1的constructor是有參數要求的

對比c2,可以看c2是沒有的:

[Java]反射:getDeclaredConstructors newInstance wrong number of arguments

3.那麼匿名内部類的constructor究竟是什麼樣子的呢?

簡要一說,匿名内部類繼承自父類

class testtest.InnerTest$1 extends testtest.Test

這個類有構造方法:

testtest.InnerTest$1(testtest.InnerTest, int);      

這裡也很容易了解,兩個參數,一個是匿名内部類的外部類引用直接傳了進來,這也是我們能在内部類中直接通路外部類成員的實作原理。另外一個就是int類型的參數了。也就是說其實編譯器自動的給我們添加了帶參數的構造方法。

是以核心就在這裡,多了一個int的參數了

[Java]反射:getDeclaredConstructors newInstance wrong number of arguments
for (Constructor c:
             constructors) {
            System.out.println(c.getClass());
            c.setAccessible(true);
            if (c.getParameterTypes().length == 1){
                Object o = c.newInstance(new Object[] {null});
            }else{
                Object o = c.newInstance();
            }

        }