Java高级-03.反射-获取构造器对象并使用
一.获取构造器对象
获取构造器对象我们有四种方法,其中带Constructor的获取单个构造器对象。而带Constructors的是获取构造器对象数组。带Declared的是无论构造器是否私有都能拿到该构造器对象,而不带Declared的方法无法获取到私有的构造器对象。
首先我们将要使用到的Cat对象定义出来:
package com.njau.d2_reflect;
import com.sun.xml.internal.ws.api.ha.StickyFeature;
public class Cat {
private String name;
private int age;
private Cat(String name, int age) {
System.out.println("有参构造器执行了!");
this.name = name;
this.age = age;
}
private Cat() {
System.out.println("无参构造器执行了!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
接着我们使用上述四种方法获取构造器对象,在获取构造器对象的第一步,就是首先获取该类对象,因为构造器是类的一部分,只有获取到了该类对象,才能进一步获取该类的构造器对象。
Constructor<?>[] getConstructors() 获取全部的构造器(不包括private修饰的,只包括public修饰的)
Constructor<?>[] getDeclaredConstructors() 获取全部的构造器(包括private,public修饰的)
Constructor<?>[] getConstructor(Class<?>...parameterTypes) 获取某个构造器(不包括private修饰的,只包括public修饰的)
Constructor<?>[] getDeclaredConstructor(Class<?>...parameterTypes) 获取某个构造器(包括private,public修饰的)
在获取某个构造器时,使用getDeclaredConstructor方法,其中()内有参数的获取有参构造器,没有参数的获取无参构造器。
package com.njau.d2_reflect;
import org.junit.Test;
import java.lang.reflect.Constructor;
/**
* 目标:获取类的构造器、并对其进行操作
* Class提供了从类中获取构造器的方法
* Constructor<?>[] getConstructors() 获取全部的构造器(不包括private修饰的,只包括public修饰的)
* Constructor<?>[] getDeclaredConstructors() 获取全部的构造器(包括private,public修饰的)
* Constructor<?>[] getConstructor(Class<?>...parameterTypes) 获取某个构造器(不包括private修饰的,只包括public修饰的)
* Constructor<?>[] getDeclaredConstructor(Class<?>...parameterTypes) 获取某个构造器(包括private,public修饰的)
* 获取类构造器的作用:依然是初始化对象返回
* 获取类构造器的作用:依然是初始化对象返回
* T newInstance(Object...initargs) 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
* public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
*/
public class Test2Constructor {
@Test
public void testGetConstructors() throws Exception {
// 反射第一步:先得到类的Class对象
Class c1 = Cat.class;
System.out.println(c1.getName()); // com.njau.d2_reflect.Cat
// Constructor[] constructors = c1.getConstructors();
Constructor[] constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
}
}
@Test
public void testGetConstructor() throws Exception {
Class c2 = Cat.class;
// Constructor constructor = c2.getConstructor();
Constructor constructor = c2.getDeclaredConstructor();
System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
// Constructor constructor1 = c2.getConstructor(String.class,int.class);
Constructor constructor1 = c2.getDeclaredConstructor(String.class,int.class);
System.out.println(constructor1.getName() + "--->" + constructor1.getParameterCount());
}
}
.class用来拿到当前的类型。携带Declared方法功能较为强大,因此我们在使用时要使用带Declared的方法。getName()和getParameterCount()用来拿到构造器名字和构造器参数个数。
二.获取类构造器的作用
Cat.java
package com.njau.d2_reflect;
import com.sun.xml.internal.ws.api.ha.StickyFeature;
public class Cat {
private String name;
private int age;
private Cat(String name, int age) {
System.out.println("有参构造器执行了!");
this.name = name;
this.age = age;
}
private Cat() {
System.out.println("无参构造器执行了!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
作用:初始化一个对象返回
在使用反射初始化对象时,我们首先获得了类的构造器对象。该构造器对象可以调用newInstance方法创建出一个类的实例化对象并返回。在该方法中传入参数即调用有参构造器,无参数则调用无参构造器。
package com.njau.d2_reflect;
import org.junit.Test;
import java.lang.reflect.Constructor;
/**
* 目标:获取类的构造器、并对其进行操作
* Class提供了从类中获取构造器的方法
* Constructor<?>[] getConstructors() 获取全部的构造器(不包括private修饰的,只包括public修饰的)
* Constructor<?>[] getDeclaredConstructors() 获取全部的构造器(包括private,public修饰的)
* Constructor<?>[] getConstructor(Class<?>...parameterTypes) 获取某个构造器(不包括private修饰的,只包括public修饰的)
* Constructor<?>[] getDeclaredConstructor(Class<?>...parameterTypes) 获取某个构造器(包括private,public修饰的)
* 获取类构造器的作用:依然是初始化对象返回
* 获取类构造器的作用:依然是初始化对象返回
* T newInstance(Object...initargs) 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
* public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
*/
public class Test2Constructor {
@Test
public void testGetConstructors() throws Exception {
// 反射第一步:先得到类的Class对象
Class c1 = Cat.class;
System.out.println(c1.getName()); // com.njau.d2_reflect.Cat
// Constructor[] constructors = cat.getConstructors();
Constructor[] constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
}
// System.out.println(cat.getConstructor(String.class, int.class));
}
@Test
public void testGetConstructor() throws Exception {
Class c2 = Cat.class;
// Constructor constructor = c2.getConstructor();
Constructor constructor = c2.getDeclaredConstructor();
System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
// Constructor constructor1 = c2.getConstructor(String.class,int.class);
Constructor constructor1 = c2.getDeclaredConstructor(String.class,int.class);
System.out.println(constructor1.getName() + "--->" + constructor1.getParameterCount());
Cat cat1 = (Cat) constructor.newInstance(); // private修饰的,无法直接使用无参构造器进行初始化(Object对象,要进行强转)
System.out.println(cat1);
}
}
我们在刚才的无参构造器constructor的基础上调用newInstance方法来实例化对象。因为无参构造器constructor自己本身不知道自己是什么类型的,因此他声明出来的类实例化对象是Object类型的,因此要强转成Cat类型才行。
但当我们执行该代码时,发现报错。报错类型为
可以看到因为该无参构造器是私有的private修饰,因此并没有成功创建该类的实现类对象。要想解决这个问题,除了将该无参构造器改为公共的以外,还可以使用setAccessible()方法。
我们可以调用setAccessible方法设置为true,表示禁止检查访问控制,即使用暴力反射。这样的话即使是私有的构造方法也可以进行对象的实例化。
package com.njau.d2_reflect;
import org.junit.Test;
import java.lang.reflect.Constructor;
/**
* 目标:获取类的构造器、并对其进行操作
* Class提供了从类中获取构造器的方法
* Constructor<?>[] getConstructors() 获取全部的构造器(不包括private修饰的,只包括public修饰的)
* Constructor<?>[] getDeclaredConstructors() 获取全部的构造器(包括private,public修饰的)
* Constructor<?>[] getConstructor(Class<?>...parameterTypes) 获取某个构造器(不包括private修饰的,只包括public修饰的)
* Constructor<?>[] getDeclaredConstructor(Class<?>...parameterTypes) 获取某个构造器(包括private,public修饰的)
* 获取类构造器的作用:依然是初始化对象返回
* 获取类构造器的作用:依然是初始化对象返回
* T newInstance(Object...initargs) 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
* public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
*/
public class Test2Constructor {
@Test
public void testGetConstructors() throws Exception {
// 反射第一步:先得到类的Class对象
Class c1 = Cat.class;
System.out.println(c1.getName()); // com.njau.d2_reflect.Cat
// Constructor[] constructors = cat.getConstructors();
Constructor[] constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
}
// System.out.println(cat.getConstructor(String.class, int.class));
}
@Test
public void testGetConstructor() throws Exception {
Class c2 = Cat.class;
// Constructor constructor = c2.getConstructor();
Constructor constructor = c2.getDeclaredConstructor();
System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
// Constructor constructor1 = c2.getConstructor(String.class,int.class);
Constructor constructor1 = c2.getDeclaredConstructor(String.class,int.class);
System.out.println(constructor1.getName() + "--->" + constructor1.getParameterCount());
constructor.setAccessible(true); // 先设置为true,才能使用private修饰的无参构造器进行初始化对象
Cat cat1 = (Cat) constructor.newInstance(); // private修饰的,无法直接使用无参构造器进行初始化(Object对象,要进行强转)
System.out.println(cat1); // Cat{name='null', age=0}
constructor1.setAccessible(true);
Cat cat2 = (Cat) constructor1.newInstance("招财猫", 3);
System.out.println(cat2);
}
}