反射
可以理解为是解剖class对象的一个技术,能解剖class对象的成员变量、成员方法、构造方法。使用反射可以让代码变的更通用,更灵活。
下面是类加载到内存的大致过程
万物皆对象
- Class文件有Class对象,描述Class对象的类叫做Class类
- 成员变量有Field对象,描述Field对象的类叫做Field类
- 成员方法有Method对象,描述Method对象的类叫做Method类
- 构造方法有Constructor对象,描述Constructor对象的类叫做Constructor类
想要使用反射,首先我们需要获取Class对象
获取Class对象
反射获取Class对象有三种方法,下面依次介绍,首先创建一个Person类
public class Person {
private String name;
private Integer age;
public Person() {
}
private Person(Integer age,String name){ //私有构造
this.age = age;
this.name = name;
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 调用Object中的getClass方法:Class <?> getClass()
public class GetClass {
@Test
public void get1()throws Exception{
Person person = new Person();
Class<? extends Person> Class1 = person.getClass();
}
}
- 不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class
public class GetClass {
@Test
public void get1()throws Exception{
Class<Person> Class1 = Person.class;
}
}
- Class类中的静态方法:static Class<?> forName(String className) className传递的是类的全限定名(包名.类名)
public class GetClass {
@Test
public void get1()throws Exception{
Class<?> Class1 = Class.forName("test.Person");
}
}
因为其参数为String,所以这种方法也可以和properties文件结合使用。
public class Main {
public static void main(String[] args)throws Exception {
Properties properties = new Properties();
FileInputStream in = new FileInputStream("module1\\properties");
properties.load(in);
String className = properties.getProperty("className");
System.out.println(className);
Class<?> Class1 = Class.forName(className);
System.out.println("Class1 = " + Class1);
}
}
利用反射获取Class对象中的构造方法
Class类中的方法:
Constructor<?>[] getConstructors()
:获取所有public的构造方法
public class Main {
public static void main(String[] args) {
Class<Person> Class1 = Person.class; //获取Class对象
Constructor<?>[] constructors = Class1.getConstructors(); //获取所有public的构造
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
}
}
利用反射获取空参公有构造并创建对象
Constructor<T> getConstructor(Class<?>... parameterTypes)
:获取指定的public的构造。其中的 parameterTypes为可变参数,可以传递0个或者多个参数。如果获取的是空参构造,参数不用写。如果获取的是有参构造,参数写参数类型的class对象
Constructor类中的方法:T newInstance(Object...initargs)
创建对象,initargs传递的是构造方法的实参。如果根据无参构造new对象,initargs不写了,如果根据有参构造new对象,initargs传递实参 。
public class Main {
public static void main(String[] args)throws Exception {
Class<Person> Class1 = Person.class; //获取Class对象
Constructor<Person> constructor = Class1.getConstructor();
System.out.println("constructor = " + constructor);
Person person = constructor.newInstance(); //好比是Person person = new Person()
System.out.println(person);//好比是直接输出对象名,默认调用toString
}
}
利用反射获取有参公有构造并创建对象
public class Main {
public static void main(String[] args)throws Exception {
Class<Person> aClass = Person.class; //获取Class对象
Constructor<Person> constructor = aClass.getConstructor(String.class, Integer.class);
System.out.println("constructor = " + constructor);
Person person = constructor.newInstance("张三", 66); //创建对象,好比是Person person = new Person("张三",66)
System.out.println(person);//好比是直接输出对象名,默认调用toString
}
}
利用反射获取私有构造(暴力反射)
Constructor<?>[] getDeclaredConstructors()
获取所有构造方法,包括private
public class Main {
public static void main(String[] args) {
Class<Person> Class1 = Person.class;
Constructor<?>[] dc = Class1.getDeclaredConstructors();
for (Constructor<?> constructor : dc) {
System.out.println(constructor);
}
}
}
从运行结果可以看到,私有的也拿到了。
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
获取指定构造,包括private。parameterTypes为参数类型的class对象- Constructor有一个父类叫做AccessibleObject ,里面有一个方法
void setAccessible(boolean flag)
能修改访问权限,flag为true表示解除私有权限
以下是获取指定构造
public class Main {
public static void main(String[] args) throws Exception{
Class<Person> Class1 = Person.class;
Constructor<Person> dc = Class1.getDeclaredConstructor(Integer.class, String.class);
System.out.println("dc = " + dc);
dc.setAccessible(true);//解除私有权限->暴力反射
Person person = dc.newInstance(66,"张三");
System.out.println(person);
}
}
利用反射获取Class对象中的成员方法
Class类中方法:
Method[] getMethods()
:获取所有public的方法,包括父类中的public方法。
public class Main {
public static void main(String[] args) throws Exception{
Class<Person> Class1 = Person.class;
Method[] methods = Class1.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
利用反射获取指定的公有方法
Class类中的方法:
Method getMethod(String name, Class<?>... parameterTypes)
:获取指定的public的成员方法,name传递方法名,parameterTypes:方法参数类型的class对象
Method对象中的方法:
Object invoke(Object obj, Object... args)
:执行方法,obj根据构造new出来的对象,args方法实参,如果有参数,直接传递实参,否则不用传。返回值Object接收被执行方法的返回值,如果方法没有返回值就不用接收。
public class Main {
public static void main(String[] args) throws Exception{
Class<Person> Class1 = Person.class;
Constructor<Person> constructor = Class1.getConstructor();
Person person = constructor.newInstance(); //创建对象
Method setName = Class1.getMethod("setName", String.class);
setName.invoke(person,"张三"); //相当于person.setName("张三")
System.out.println(person);//好比调用toString方法
}
}
还有另一种利用空参构造创建对象的快捷方式,不过jdk17已经不建议使用了
public class Main {
public static void main(String[] args) throws Exception {
Class<Person> Class1 = Person.class;
Person person = Class1.newInstance(); //创建对象
//获取有参方法
Method setName = Class1.getMethod("setName", String.class);
setName.invoke(person, "张三"); //相当于person.setName("张三")
System.out.println(person);//好比调用toString方法
//获取无参方法
Object o = getName.invoke(person); //好比是person.getName()
System.out.println(o);
}
}
利用反射获取私有方法
Method[] getDeclaredMethods()
:获取所有的成员方法,包括private的
public class Main {
public static void main(String[] args) throws Exception {
Class<Person> Class1 = Person.class;
Method[] dm = Class1.getDeclaredMethods();
for (Method method : dm) {
System.out.println(method);
}
}
}
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
:获取执行成员方法,包括private,name传递方法名,parameterTypes是方法参数类型的class对象
void setAccessible(boolean flag)
:解除私有权限
public class Person {
private void test(){
System.out.println("hhhhhhhhhhhhhh");
}
}
public class Main {
public static void main(String[] args) throws Exception {
Class<Person> Class1 = Person.class;
Constructor<Person> constructor = Class1.getConstructor();
Person person = constructor.newInstance();
Method method = Class1.getDeclaredMethod("test");
method.setAccessible(true);
method.invoke(person);
}
}
利用反射获取Class对象中的成员变量
获取所有属性
Class类中的方法:
Field[] getFields()
:获取所有public的属性
public class Person {
private String name;
public Integer age;
}
public class Main {
public static void main(String[] args) throws Exception {
Class<Person> Class1 = Person.class;
Field[] fields = Class1 .getFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
Field[] getDeclaredFields()
:获取所有属性,包括priavte的。
public class Main {
public static void main(String[] args) throws Exception {
Class<Person> Class1 = Person.class;
Field[] df = Class1.getDeclaredFields();
for (Field field : df) {
System.out.println(field);
}
}
}
获取指定属性
Class类中的方法:
Field getField(String name)
获取指定public的属性
Field getDeclaredField(String name)
:获取指定属性,包括priavte的
Field类中的方法:
void set(Object obj,Object value)
:为属性赋值,相当于javabean中的set方法,obj代表对象,value代表赋予的值
Object get(Object obj)
:获取属性值,obj是对象
获取指定public的属性
public class Main {
public static void main(String[] args) throws Exception {
Class<Person> Class1 = Person.class;
Person person = Class1.newInstance();
Field age = Class1.getField("age");
age.set(person,10);//调用set方法为public属性赋值
System.out.println(age.get(person));//调用get方法获取public属性值,相当于javabean中的get方法
}
}
获取指定属性,包括priavte的
public class Main {
public static void main(String[] args) throws Exception {
Class<Person> Class1 = Person.class;
Person person = Class1.newInstance();
Field name = Class1.getDeclaredField("name");
name.setAccessible(true);//解除私有权限
name.set(person,"张三");//调用set方法为属性赋值
System.out.println(name.get(person));//调用get方法获取属性值 -> 相当于javabean中的get方法
}
}