前言
java中有一个十分重要的内容java反射思想,学好java反射,对于我们的后续开发以及看懂别人的代码至关重要,因此,打好反射的基础最重要。
目录
一、什么是反射机制
Java反射机制就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
静态编译:在编译时确定类型,绑定对象;
动态编译:在运行时确定类型,绑定对象;
二、java的反射机制的优缺点
优点:能够在运行时动态获取类的实例,提高灵活性;
缺点:使用反射性能较低,需要解析字节码,将内存中的对象进行解析;
相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)
三、如何通过java获取反射
1.- 类名.class属性
代码实例:
Class<Student> c1 = Student.class;
2.- 对象名.getClass()方法
代码实例:
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
3.- Class.forName(全类名)方法
代码实例
Class<?> c4 = Class.forName("com.Test.Student");
四、通过java反射能完成的操作
4.1、java反射获取构造方法对象并使用
Class类获取构造方法对象的方法
代码实例
package com.homework10.Constructor;
import java.lang.reflect.Constructor;
/**
* @author wang
* @packageName com.homework10.Constructor
* @className ConstructorTest
* @date 2021/11/9 17:52
*/
public class ConstructorTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
//加载类
Class<?> c = Class.forName("com.homework10.Constructor.Student");
//因为我的类中只有一个公共的无参构造方法,所以我这个构造方法调用的就是类中无参构造,且是公共的
Constructor<?> constructor = c.getConstructor();
System.out.println(constructor);//public com.homework10.Constructor.Student()
//这个地方举例的是获取指定的非公共的构造方法
Constructor<?> conName = c.getDeclaredConstructor(String.class);
System.out.println(conName);//private com.homework10.Constructor.Student(java.lang.String)
System.out.println("============");
//获取所有公共的构造方法的数组
Constructor<?>[] constructors = c.getConstructors();
for (Constructor consPublic : constructors) {
System.out.println(consPublic);
}//public com.homework10.Constructor.Student()
System.out.println("============");
//获取所有构造方法的数组
Constructor<?>[] constructors1 = c.getDeclaredConstructors();
for (Constructor constructor1 : constructors1) {
System.out.println(constructor1);
}
/*
protected com.homework10.Constructor.Student(java.lang.String,int,java.lang.String)
com.homework10.Constructor.Student(java.lang.String,int)
private com.homework10.Constructor.Student(java.lang.String)
public com.homework10.Constructor.Student()
*/
}
}
如果我们想要创建对象,给成员变量赋值,可以使用下面这个方法
例如我们可以这样
Constructor<?> conName = c.getDeclaredConstructor(String.class);
System.out.println(conName);//private com.homework10.Constructor.Student(java.lang.String)
Object obj = conName.newInstance("张飞");
System.out.println(obj);
但是注意我们的构造方法如果是非公共修饰的,就会报出一个错误
Exception in thread "main" java.lang.IllegalAccessException: Class com.homework10.Constructor.ConstructorTest can not access a member of class com.homework10.Constructor.Student with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Constructor.newInstance(Constructor.java:413)
at com.homework10.Constructor.ConstructorTest.main(ConstructorTest.java:26)
如果出现上述错误,就是因为我们在调用构造方法时,我们的构造方法是用private修饰的,那么此反射对象是无法被访问到,要想访问就得进行下面的操作。
暴力反射
方法(Constructor类下)
oid setAccessible(boolean flag) 将此反射对象的 accessible标志设置为指示的布尔值。
描述
将此反射对象的accessible标志设置为指示的布尔值。 值为true表示反射对象应该在使用Java语言访问控制时抑制检查。 值为false表示反射对象应该在使用Java语言访问控制时执行检查,并在类描述中指出变体。 呼叫者可以在C类中使用此方法,以使得能够访问declaring class declaring class D如果有以下任何一项):
如下所示:
Constructor<?> conName = c.getDeclaredConstructor(String.class);
System.out.println(conName);//private com.homework10.Constructor.Student(java.lang.String)
conName.setAccessible(true);
Object obj = conName.newInstance("张飞");
System.out.println(obj);
输出结果:
Student{name='张飞', age=0, address='null'}
4.2、java反射获取类的成员变量对象方法
Class类获取成员变量对象的方法
Field类用于给成员变量赋值的方法
示例代码
package com.homework10.Constructor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/**
* @author wang
* @packageName com.homework10.Constructor
* @className FieldTest
* @date 2021/11/9 23:37
*/
public class FieldTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//加载类
Class<?> c = Class.forName("com.homework10.Constructor.Student");
//实例化对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
Field nameField = c.getDeclaredField("name");
//这里与构造方法一直,private修饰的话就暴力反射一下
nameField.setAccessible(true);
nameField.set(obj,"张飞");
System.out.println(obj);
System.out.println(nameField);
//Student{name='张飞', age=0, address='null'}
//private java.lang.String com.homework10.Constructor.Student.name
//可以看到输出的name属性已经修改,那么其他的也是可以修改的。这里不做演示。
//那么通过方法反射得到的成员变量对象数组等操作与构造方法类似。
}
}
4.3、java获取成员方法对象的方法
Class类获取成员方法对象的方法
Method类用于执行方法的方法
该方法需要注意区别的是我们用于操作数组对象时,如果得到全部的成员方法数组,那么他是会的到所有的成员方法包括父类。
示例代码
Method[] methods = c.getMethods();
for(Method method : methods) {
System.out.println(method);
}
/*
public java.lang.String com.homework10.Constructor.Student.toString()
public java.lang.String com.homework10.Constructor.Student.method3(java.lang.String,int)
public void com.homework10.Constructor.Student.method2(java.lang.String)
public void com.homework10.Constructor.Student.method1()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
*/
获取指定成员方法对象的代码实例,公共的代码直接调用方法即可
//这里与获取指定成员变量对象一致,是需要写入方法名的,公共的成员方法不用
Method me = c.getDeclaredMethod("function");
//这里需要注意也是一样,要暴力反射,如果方法是非公共的。
me.setAccessible(true);
//obj对象是在开始创建过的
me.invoke(obj);
/*
方法内容:private void function() {
System.out.println("function");
}
输出结果:function
*/
五、总结,反射使用全步骤
1.通过一个全限类名创建一个对象
2.获取构造器对象,通过构造器new出一个对象
3.通过class对象获得一个属性对象
4.通过class对象获得一个方法对象
5.让方法执行
全过程示例代码:
package com.homework10.Constructor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author wang
* @packageName com.homework10.Constructor
* @className Test
* @date 2021/11/10 0:03
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//通过一个全限类名创建一个对象
Class<?> c = Class.forName("com.homework10.Constructor.Student");
//获取构造器对象,通过构造器new出一个对象,实例为空参构造,也可以实参,但我为了演示全过程,故为下面代码
Constructor con = c.getConstructor();
Object obj = con.newInstance();
//通过class对象获得一个属性对象
Field nameField = c.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj,"张飞");
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj,25);
Field addressField = c.getDeclaredField("address");
addressField.set(obj,"重庆市");
//通过class对象获得一个方法对象,这里用toString方法,本类异常均抛出,为了简化示例
Method m = c.getDeclaredMethod("toString");
//让方法执行
System.out.println(m.invoke(obj));
}
}
/*
输出结果
Student{name='张飞', age=25, address='重庆市'}
*/
附:Student类
package com.homework10.Constructor;
/**
* @author wang
* @packageName com.homework10.Constructor
* @className Student
* @date 2021/11/9 17:52
*/
public class Student {
//成员变量:一个私有,一个默认,一个公共
private String name;
int age;
public String address;
//构造方法:一个私有,一个默认,两个公共
public Student() {
}
private Student(String name) {
this.name = name;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
protected Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
//成员方法:一个私有,四个公共
private void function() {
System.out.println("function");
}
public void method1() {
System.out.println("method");
}
public void method2(String s) {
System.out.println("method:" + s);
}
public String method3(String s, int i) {
return s + "," + i;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
最后感谢各位观看,麻烦给个免费的点赞,谢谢支持哦,下期继续为大家分享java知识。