目录
1.反射的认识
2.反射和new的区别
3.反射的使用代码展示
4.反射优点和缺点
反射是Java语言的一种机制,它允许程序在运行时检查和操作类、方法、字段等信息,而不需要提前知道它们的具体定义。通过反射,我们可以在运行时动态地加载类、创建对象、调用方法以及访问和修改字段。
Java反射提供了以下核心类:
细说:
(1)Class类:代表Java中的类或接口。通过Class类,我们可以获取类的构造函数、方法、字段等信息。
(2)Constructor类:代表类的构造函数。通过Constructor类,我们可以创建对象。
(3)Method类:代表类的方法。通过Method类,我们可以调用方法。
(4)Field类:代表类的字段。通过Field类,我们可以访问和修改字段的值。
仅仅在实例化对象上效果无区别,接下来我会列举一些反射和new重要的区别(不阐述底层原理,只区分不同)
(1)首先new出来的对象我们无法访问其中的私有属性,但是通过反射出来的对象我们可以通过setAccessible()方法来访问其中的私有属性。
(2)new对象一定要知道类名(在不知道类名的情况下,你怎么去new?),但反射创建对象不需要知道类名也可以。
(3)new对象属于静态编译,也就是说当代码生成exe文件的时候会将所有模块都编译进去,当你启动这个exe文件的时候,所有模块就会进行一个加载的过程(初始化)
反射属于动态编译,编译过程中并不会将模块编译进去,这样初始化的时候就会减少负荷,只有在运行过程中,需要哪些模块的时候才进行调用.
我们先看看Class类中的相关方法
(1)常用获得类相关的方法
(2)常用获得类中属性相关的方法(以下方法返回值为Field相关)
(3) 获得类中注解相关的方法
(4)获得类中构造器相关的方法(以下方法返回值为Constructor相关)
(5) 获得类中方法相关的方法(以下方法返回值为Method相关)
在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的Class对象,然后通过Class对象的核心方法,达到反射的目的,即:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息
接下来展示代码需要导入的包:
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
3.1获得Class对象的三种方式
student类
class Student {
//私有属性name
private String name = "wang";
//公有属性age
public int age = 18;
//不带参数的构造方法
public Student(){
System.out.println("Student()");
}
private Student(String name,int age) {
this.name = name;
this.age = age;
System.out.println("Student(String,name)");
}
private void eat(){
System.out.println("i am eat");
}
public void sleep(){
System.out.println("i am pig");
}
private void function(String str) {
System.out.println(str);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Text类
public class Test {
/*
Class对象 只有一个
*/
public static void main(String[] args) {
Class> c1 = null;
try {
c1 = Class.forName("demo1.Student");
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class> c2 = Student.class;
Student student = new Student();
Class> c3 = student.getClass();
}
}
说明:
(1)直接通过 类名 .class 的方式得到 , 该方法最为安全可靠,程序性能更高这说明任何一个类都有一个隐含的静态成员变量 class(2) 通过 Class 对象的 forName() 静态方法来获取,用的最多,但可能抛出 ClassNotFoundException 异常, 注意这里是类的全路径,如果有包需要加包的路径
思考:
提问: 关于Text类
System.out.println(c1 == c2);
System.out.println(c1 == c3);答案:ture ture
因为:Class对象 只有一个 ,一个类在 JVM 中只会有一个 Class 实例
接下来我们开始使用反射,我们依旧反射上面的Student类,把反射的逻辑写到另外的类当中进行理解
以下均为简单操作,故不做过多说明。
3.2反射机制创建对象
代码:
public static void reflectNewInstance() {
Class> classStudent = null;
try {
classStudent = Class.forName("demo1.Student");
Student student = (Student)classStudent.newInstance();
System.out.println(student);
}catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
通过反射机制调用构造方法实例化java对象
代码:
public static void reflectPrivateConstructor() {
Class> classStudent = null;
try {
classStudent = Class.forName("demo1.Student");
//获得构造方法
Constructor> constructor = classStudent.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
Student student = (Student)constructor.newInstance("xiaoming",15);
System.out.println(student);
}catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
小结:
- 先获取到这个有参数的构造方法【用ClassgetDeclaredConstructor()方法获取】
- 调用构造方法new对象【用Constructor类的newInstance()方法new对象】
3.3通过反射机制访问一个java对象的属性
代码:
public static void reflectPrivateField() {
Class> classStudent = null;
try {
classStudent = Class.forName("demo1.Student");
Field field = classStudent.getDeclaredField("name");
field.setAccessible(true);
Student student = (Student)classStudent.newInstance();
field.set(student,"caocao");
System.out.println(student);
}catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
3.4通过反射机制调用一个对象的方法
代码:
public static void reflectPrivateMethod() {
Class> classStudent = null;
try {
classStudent = Class.forName("demo1.Student");
Method method = classStudent.getDeclaredMethod("function",String.class);
method.setAccessible(true);
Student student = (Student)classStudent.newInstance();
method.invoke(student,"我是一个反射的参数!");
}catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
优点:
(1)对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
(2)增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
(3)反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。
缺点:
(1)使用反射会有效率问题。会导致程序效率降低。具体参考这里:反射效率低的原因
(2)反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂
以上为我个人的小分享,如有问题,欢迎讨论!!!
都看到这了,不如关注一下,给个免费的赞