反射是框架设计的灵魂
(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))
1.什么是反射
Java反射是指在程序运行时对类、方法、属性等进行动态获取和操作的机制,可以使得程序在运行时,根据类的名称、方法名、属性名等来动态调用类的方法、创建类的实例、修改类的属性值等。通过反射,Java程序可以在运行时获取类信息,创建对象、调用方法,以及获取和修改属性值等。
Java反射的主要API是反射包(java.lang.reflect),其中包含了如下一些重要的类和接口:
- Class类:封装了表示类或接口的信息;
- Constructor类:封装了类的构造函数信息;
- Field类:封装了类的属性信息;
- Method类:封装了类的方法信息;
- Modifier类:提供了访问权限修饰符的常量。
2.java类类的三种使用
java类类介绍
Java类加载器(Class Loader)是Java虚拟机(JVM)的一个重要组成部分,负责动态地将Java类(.class文件)的字节码加载到内存中并产生Class对象。Java类加载器可以将一个类加载到内存之后,对类进行初始化(执行静态代码块和静态变量赋值操作)、验证、链接(将类与其他类或接口进行关联)等操作,最终将Java类对象提供给应用程序使用
使用场景一:
//括号里存储的路径是实体类的路径
Class c1 = Class.forName("com.yuan.fanshe.Student");
使用场景二:
Student s = new Student();
Class c2 = s.getClass();
使用场景三:
Class c3 = Student.class;
3.反射实例化
反射实例化是指使用反射机制在运行时动态地创建一个类的实例对象。它使得开发者可以在不知道具体类型的情况下创建类的实例,或者动态地构建对象。通过反射实例化,我们可以在编写代码时不确定实际需要创建哪种具体类型的对象,这种方式能够让代码更加灵活和可扩展。
1.在Java中,反射实例化的过程可以分为以下三个步骤:
-
1.获取Class对象:通过Class.forName()或者类名.class的方式获取需要实例化的类的Class对象。
-
2.调用Class对象的newInstance()方法:该方法会创建一个该类的对象,并返回该对象的引用。
-
3.强制类型转换:由于newInstance()方法返回的是Object类型,所以我们需要将其强制转换为需要的类型。
2.学生实体类
package com.yuan.fanshe;
public class Student {
private String sid;
private String sname;
public Integer age;
static{
System.out.println("加载进jvm中!");
}
public Student() {
super();
System.out.println("调用无参构造方法创建了一个学生对象");
}
public Student(String sid) {
super();
this.sid = sid;
System.out.println("调用带一个参数的构造方法创建了一个学生对象");
}
public Student(String sid, String sname) {
super();
this.sid = sid;
this.sname = sname;
System.out.println("调用带二个参数的构造方法创建了一个学生对象");
}
@SuppressWarnings("unused")
private Student(Integer age) {
System.out.println("调用Student类私有的构造方法创建一个学生对象");
this.age = age;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public void hello() {
System.out.println("你好!我是" + this.sname);
}
public void hello(String name) {
System.out.println(name + "你好!我是" + this.sname);
}
@SuppressWarnings("unused")
private Integer add(Integer a, Integer b) {
return new Integer(a.intValue() + b.intValue());
}
}
3.案例
package com.yuan.fanshe;
import java.lang.reflect.Constructor;
public class demo2 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.yuan.fanshe.Student");//拿到类类
Student s1 = (Student) c1.newInstance();//无参数的
Constructor cr1 = c1.getConstructor(String.class);//拿到一个参数的方法
Student s2 = (Student) cr1.newInstance("张三");
Constructor cr2 = c1.getConstructor(String.class,String.class);//拿到两个参数的方法
Student s3 = (Student) cr2.newInstance("s001","张三");
Constructor cr4 = c1.getDeclaredConstructor(Integer.class);//拿到私有化一个参数的方法
cr4.setAccessible(true);//权限给ture
Student s4 = (Student) cr4.newInstance(18);
}
}
控制台打印:
4.反射动态方法调用
1.反射动态方法介绍
反射动态方法调用是指通过反射机制在运行时动态地调用一个对象的方法。这种方式可以让开发者在编写代码时不需要知道具体方法的名称和参数类型,从而使代码更加灵活和可扩展。
在Java中,反射动态方法调用主要通过下列API实现:
-
获取Class对象:通过Class.forName()或者类名.class的方式获取对应类的Class对象。
-
获取Method对象:使用Class对象的getDeclaredMethod()或getMethod()方法获取指定的方法对象。
设置方法访问权限:如果需要调用方法是私有方法,需要使用Method对象的setAccessible(true)方法,来打开该方法的访问权限。一般来说,应该尽量避免调用私有方法,因为这会破坏对象的封装性。
调用方法:使用Method对象的invoke()方法,传递需要调用的对象和方法的参数,即可动态地调用该方法。
2.案例
package com.yuan.fanshe;
import java.lang.reflect.Method;
/**
* 反射方法的调用
* @author yuanh
*
*/
public class demo3 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.yuan.fanshe.Student");
Student s1 = (Student) c1.newInstance();
Method m1 = c1.getMethod("hello");
Object i1 = m1.invoke(s1);//调用了hello无参数的方法
Method m2 = c1.getMethod("hello", String.class);
Object i2 = m2.invoke(s1, "张三");//调用了hello无参数的方法
Method m3 = c1.getDeclaredMethod("add",Integer.class,Integer.class);
m3.setAccessible(true);//给私有化的权限设置为true
Object i3 = m3.invoke(s1, 1,2);
System.out.println(i3);
}
}
控制台打印:
5.反射读写属性
1.反射读写属性介绍
射读写属性是指通过反射机制在运行时动态地获取和修改对象的属性值。这种方式可以让开发者在编写代码时不需要知道具体属性的名称和类型,从而使代码更加灵活和可扩展。
在Java中,反射读写属性主要通过下列API实现:
-
获取Class对象:通过Class.forName()或者类名.class的方式获取对应类的Class对象。
-
获取Field对象:使用Class对象的getDeclaredField()或getField()方法获取指定的属性对象。
-
设置属性访问权限:如果需要读写的属性是私有属性,需要使用Field对象的setAccessible(true)方法,来打开该属性的访问权限。一般来说,应该尽量避免读写私有属性,因为这会破坏对象的封装性。
-
读取属性值:使用Field对象的get()方法,传递需要读取属性值的对象,即可动态地获取该属性的值。
-
修改属性值:使用Field对象的set()方法,传递需要修改属性值的对象和修改后的值,即可动态地修改该属性的值。
2.案例
package com.yuan.fanshe;
import java.lang.reflect.Field;
/**
* 反射读写属性
* @author yuanh
*
*/
public class demo4 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.yuan.fanshe.Student");
Student s1 = (Student) c1.newInstance();
s1.age=18;
s1.setSid("s001");
s1.setSname("张三");
//写
Field field2 = c1.getDeclaredField("sname");
field2.setAccessible(true);
field2.set(s1, "李四");
//读
Field[] fields = c1.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
System.out.println(field.getName()+":"+field.get(s1));
}
}
}
打印输出:
6.总结
总之,Java反射机制可以使得Java程序具有更高的灵活性和可扩展性,但也需要注意反射对性能的影响,使用时需要权衡利弊。