反射系列传送门
什么是反射?
Java反射(Reflection)是一种新的操作类中成员变量、构造方法和普通方法的机制。
为了实现对成员变量、构造方法和普通方法的操作,我们需要借助Java自身提供的java.lang包下的Class类和java.lang.reflect包下的反射API 。
在上篇博客(如何获取Class类对象)中,已经介绍如何获取Class类对象,而Class类的实例化对象其实就是反射机制的实现入口,本篇博客将会详细介绍反射中的构造方法。
现有学生类如下(用于本篇博客的实例证明):
public class Student {
String name;
Integer id;
public Student() {
}
public Student(String name) {
this.name=name;
}
private Student(Integer id) {//Integer为int类型的包装类
this.id=id;
}
public void sleep() {
System.out.println(name+" go to sleep ");
}
public void say() {
System.out.println("学号为:"+id);
}
}
使用反射获取构造方法的实例对象
借助Class类某些方法可以获取对应类中声明的构造方法的实例化对象。
实例化构造方法的对象有四种方法,可以分为两类:适用于public修饰的构造方法和不区分访问权限。
第一类:适用于public修饰的构造方法
1、使用Class类实例化对象.getConstructor()获取无参构造方法的实例化对象
package test;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class clazz=null;
clazz = Student.class;//通过使用类名.class获取Class类实例
try {
Constructor constructor = clazz.getConstructor();//获取无参构造方法的实例化对象
System.out.println(constructor.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、使用Class类实例化对象.getConstructor(Class<?>... parameterTypes)获取有参构造方法的实例化对象
package test;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class clazz=null;
clazz = Student.class;//通过使用类名.class获取Class类实例
try {
Constructor constructor = clazz.getConstructor(String.class);//获取有参构造方法的实例化对象
System.out.println(constructor.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
第二类:不区分访问权限
3、使用Class类实例化对象.getDeclaredConstructor()获取无参构造方法的实例化对象
package test;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class clazz=null;
clazz = Student.class;//通过使用类名.class获取Class类实例
try {
Constructor constructor = clazz.getDeclaredConstructor();//获取无参构造方法的实例化对象
System.out.println(constructor.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
4、使用Class类实例化对象.getDeclaredConstructor(Class<?>... parameterTypes)获取有参构造方法的实例化对象
注意:如果方法参数的数据类型为基本数据类型,则parameterType应为基本数据类型包装类.TYPE;如果方法参数的数据类型为基本数据类型包装类,则的数据类型应为包装类.class
package test;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class clazz=null;
clazz = Student.class;//通过使用类名.class获取Class类实例
try {
Constructor constructor = clazz.getDeclaredConstructor(Integer.class);//获取有参构造方法的实例化对象
System.out.println(constructor.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用反射获取构造方法的属性
1、获取构造方法所在的类:Class<T> getDeclaringClass()
该方法返回声明Constructor对象对应构造方法的类的Class对象。
package test;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class clazz=null;
clazz = Student.class;//通过使用类名.class获取Class类实例
try {
Constructor constructor = clazz.getDeclaredConstructor(String name);//获取有参构造方法的实例化对象
clazz = constructor.getDeclaringClass();//获取构造方法所在类的Class对象
System.out.println(constructor.getName());//打印构造方法所在类的Class对象的类名
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、获取构造方法访问控制符:int getModifiers()
该方法以整数形式返回Constructor对象表示的构造函数的修饰符。
package test;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class clazz=null;
clazz = Student.class;
try {
Constructor constructor = clazz.getDeclaredConstructor(String name);
int mod = constructor.getModifiers();//获取以整数形式表示的访问控制符
String result = Modifier.toString(mod);//将访问控制符从整数类型变为字符串类型
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、获取构造方法的名字:String getName()
该方法以字符串形式返回Constructor对象所表示得构造方法的名称
package test;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class clazz=null;
clazz = Student.class;
try {
Constructor constructor = clazz.getDeclaredConstructor(String name);
System.out.println(constructor.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
4、获取构造方法参数列表:Class<?>[ ] getParameterTypes()
该方法返回由Constructor对象所表示的构造方法的形参类型对应Class对象组成的数组此 。如果构造方法没有参数,则数组长度为0。
package test;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class clazz=null;
clazz = Student.class;
try {
Constructor constructor = clazz.getDeclaredConstructor(String name);
Class [] clazzs = constructor.getParameterTypes();//获取构造方法的参数列表
for (Class zz : clazzs) {//使用加强循环遍历参数列表
System.out.println(zz.getName());//打印参数类型
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用反射调用构造方法
使用newInstance(Object... initargs)创建声明该构造方法的新(上转型)对象。
initargs为传入该构造方法中的参数,如果该构造方法没有参数,则可设定为null或一个长度为0的数组。
package test;
import java.lang.reflect.Constructor;
public class Test3 {
public static void main(String[] args) {
Class clazz = Student.class;
try {
Constructor constructor = clazz.getConstructor(String.class);
Object object = constructor.newInstance("Tom");//生成可以调用构造方法的上转型对象
Student stu = (Student)object;//对象下转型
stu.sleep();//调用方法
} catch (Exception e) {
e.printStackTrace();
}
}
}
如果构造方法使用private修饰那么就需要使用getDeclaredConstructor()方法创建构造方法对象,并且需要使用构造方法对象.setAccessible(boolean flag)方法,设定调用构造函数时忽略访问权限的影响(true表示忽略,false表示不忽略)
package test;
import java.lang.reflect.Constructor;
public class Test3 {
public static void main(String[] args) {
Class clazz = Student.class;
try {
Constructor constructor = clazz.getDeclaredConstructor(Integer.class);
constructor.setAccessible(true);
Object object = constructor.newInstance(2019111);//生成可以调用构造方法的上转型对象
Student stu = (Student)object;//对象下转型
stu.say();//调用方法
} catch (Exception e) {
e.printStackTrace();
}
}
}