Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAVA getConstructor throws NoSuchMethodException

I'm new in JAVA and I'm trying to learn reflection. I want to get specific constructor (picking the example form here) from my class :

public class Example1 {
    public Example1() {
    }

    public Example1(int i) {
    }

    public Example1(String s) {
        System.out.println("using param = " + s);
    }

    public static void main(String[] args) throws Exception {  
        Class<?>[] paramTypes = String.class.getClasses();
        Constructor<Example1> ctor = Example1.class.getConstructor(paramTypes);
        ctor.newInstance("test");
    }
}

I get NoSuchMethodException when trying to instantiate ctor

What am I missing here?

like image 622
LordTitiKaka Avatar asked Mar 22 '15 13:03

LordTitiKaka


1 Answers

Working example:

import java.lang.reflect.Constructor;

public class Test {
    public Test(String str) {
        System.out.println(str);
    }

    public Test(int a, int b) {
        System.out.println("Sum is " + (a + b));
    }

    public static void main(String[] args) throws Exception {
        Constructor<Test> constructorStr = Test.class.getConstructor(String.class);
        constructorStr.newInstance("Hello, world!");

        Constructor<Test> constructorInts = Test.class.getConstructor(int.class, int.class);
        constructorInts.newInstance(2, 3);
    }
}

Note that method getConstructor actually doesn't take an array. It's defined like:

public Constructor<T> getConstructor(Class<?>... parameterTypes) {

... meaning that it accepts variable amount of arguments which should have been passed as I did. Passing an array is possible too, but it's not necessary.

What you've done originally was equivalent to:

    Constructor<Test> constructor = Test.class.getConstructor(String.class.getClasses());
    constructor.newInstance("Hello");

But, what does String.class.getClasses() return? Good question! Lets go debug:

    Class<?>[] classes = String.class.getClasses();
    System.out.println(classes.length); // prints 0

There's a documentation about getClasses(): https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getClasses. Check it and you'll find out the reason why it's so.

For the sake of completeness. The super-original-question (before edits) contained one more constructor - a non-parametric one:

import java.lang.reflect.Constructor;

public class Example1 {
    public Example1() {
    }

    public Example1(String s) {
        System.out.println("using param = " + s);
    }

    public static void main(String[] args) throws Exception {  
        Constructor<Example1> ctor = Example1.class.getConstructor(String.class.getClasses());
        ctor.newInstance("test");
    }
}

The problem which occurs here is IllegalArgumentException being thrown. It's because even though String.class.getClasses() returns an empty array, there actually is constructor which matches the criteria - a non-parametric constructor! It doesn't have any arguments and the array returned by String.class.getClasses() doesn't contain anything too. This means that constructor is successfully found, but when trying to instantiate it using ctor.newInstance("test"), it fails because the found constructor doesn't accept any arguments.

like image 135
tzima Avatar answered Oct 08 '22 10:10

tzima