Ответ 1
вложенный класс - класс, определенный в другом классе (включая статические и нестатические классы)
внутренний класс - нестатический вложенный класс (экземпляр внутреннего класса нужен экземпляр внешнего класса для существования)
не вложенные (верхний уровень) классы
На основании вашего вопроса мы знаем, что конструктор, к которому вы хотите получить доступ, не является общедоступным. Таким образом, ваш класс может выглядеть следующим образом ( класс в каком - то пакете отличается от нашего) A
package package1;
public class A {
A(){
System.out.println("this is non-public constructor");
}
}
Чтобы создать экземпляр этого класса, нам нужно получить конструктор, который мы хотим вызвать, и сделать его доступным. Когда это будет сделано, мы можем использовать Constructor#newInstance(arguments)
для создания экземпляра.
Class<?> c = Class.forName("package1.A");
//full package name --------^^^^^^^^^^
//or simpler without Class.forName:
//Class<package1.A> c = package1.A.class;
//In our case we need to use
Constructor<?> constructor = c.getDeclaredConstructor();
//note: getConstructor() can return only public constructors
//so we needed to search for any Declared constructor
//now we need to make this constructor accessible
constructor.setAccessible(true);//ABRACADABRA!
Object o = constructor.newInstance();
вложенные и внутренние классы
Если вы хотите получить доступ к вложенному (статическому и нестатическому) классу с Class.forName
вам нужно использовать синтаксис:
Class<?> clazz = Class.forName("package1.Outer$Nested");
Outer$Nested
говорит, что класс Nested
объявлен в классе Outer
. Вложенные классы очень похожи на методы, они имеют доступ ко всем членам своего внешнего класса (включая частные).
Но мы должны помнить, что экземпляр внутреннего класса для существования требует экземпляра его внешнего класса. Обычно мы создаем их через:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
так как вы видите, что каждый экземпляр класса Inner имеет некоторую информацию о его внешнем классе (ссылка на этот внешний экземпляр хранится в this$0
поле this$0
, больше информации: что это означает, если переменная имеет имя "this $ 0" в IntelliJ IDEA, тогда как отладка Java?)
Поэтому, создавая экземпляр класса Inner
с Constructor#newInstance()
вам нужно передать ссылку на первый аргумент в экземпляр класса Outer
(для моделирования outer.new Inner()
поведения outer.new Inner()
).
Вот пример.
в пакете1
package package1;
public class Outer {
class Inner{
Inner(){
System.out.println("non-public constructor of inner class");
}
}
}
в пакете2
package package2;
import package1.Outer;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) throws Exception {
Outer outerObject = new Outer();
Class<?> innerClazz = Class.forName("package1.Outer$Inner");
// constructor of inner class as first argument need instance of
// Outer class, so we need to select such constructor
Constructor<?> constructor = innerClazz.getDeclaredConstructor(Outer.class);
//we need to make constructor accessible
constructor.setAccessible(true);
//and pass instance of Outer class as first argument
Object o = constructor.newInstance(outerObject);
System.out.println("we created object of class: "+o.getClass().getName());
}
}
статические вложенные классы
Экземпляры статических вложенных классов не требуют экземпляра класса Outer (поскольку они являются статическими). Поэтому в этом случае нам не нужно искать конструктор с Outer.class
качестве первого аргумента. И нам не нужно передавать экземпляр внешнего класса в качестве первого аргумента. Другими словами, код будет таким же, как для не-вложенного (верхнего уровня) класса (возможно, кроме факта, что вам нужно будет добавить синтаксис $Nested
в Class.forName()
).