反射
1. 反射的前提条件:
必须先有类,类的内容才能被反射处理。
-类的属性和方法必须使用 static进行修饰,才能被反射访问。
2. 类的内容也是一个对象:
在 Java 中,每个类都有一块内存空间,这块内存空间就是一个对象。
这个对象记录了该类中声明的属性、方法和构造方法等信息。
3. Java 中的 Class 类:
Java 将上述类的抽象概念,统一封装到了 Class类中。
通过 `Class` 类,我们可以获取类的各种信息,并进行动态调用。
Class类的对象是不能new
4. 反射的作用:
反射技术可以让程序在运行时动态获取类的信息,并动态调用类的属性和方法。
这种动态性使得程序更加灵活和可扩展。
5. 反射的使用场景:
动态加载类并创建对象
动态调用类的方法
获取类的属性和方法
动态代理
获取类的类对象
public static void main(String[] args) throws ClassNotFoundException {
//通过类名获取类对象
Class clazz = EasyClassA.class;
//通过对象获取类对象
clazz =new EasyClassA().getClass();
//通过class方法的forName方法获取
clazz=Class.forName("day725.EasyColor");
System.out.println(clazz);
//类的类对象中存储了类中定义的内容 属性|方法|构造方法
}
获取类对象的三种方式:
Easy.class
new Easy().getClass()
Class.forName("day726.Easy")
获取公有属性:
c.getField("name") 获取公有属性 name
fName.get(easy) 获取 easy 对象的 name 属性值
fName.set(easy, "李智") 设置 easy 对象的 name 属性值
获取私有属性:
c.getDeclaredField("code") 获取私有属性 code
fCode.set(easy, "10001") 设置 easy 对象的 code 属性值
fCode.get(easy) 获取 easy 对象的 code 属性值
访问私有属性的权限控制:
fsex.set(easy, "女") 设置 easy 对象的 sex 属性值
fAddress.setAccessible(true) 先设置访问权限,才能获取和设置 address 属性值
获取所有公有属性:
c.getFields() 获取类中所有公有属性
import java.lang.reflect.Field;
public class EasyClassB {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
//类的类对象中存储了类中定义的内容
//获取类中的属性
Class c=Easy.class;
c=new Easy().getClass();
c=Class.forName("day726.Easy");
//获取类对象
//Java中用来记录 类的属性的类叫做Field
//fName变量指向的对象就是Easy类中的name属性
Field fName=c.getField("name");
//可以获取某一个Easy对象的name属性值
Easy easy=new Easy();
easy.name="张赞";
System.out.println(easy.name);
//可以获取某一个Easy类的对象的name属性的值
Object objectName=fName.get(easy);
System.out.println(objectName+"----");
//注入该属性的值
fName.set(easy,"李智");
System.out.println(easy.name);
//getFiled getFields 只能获取类中public声明出来的属性
Field fCode=c.getDeclaredField("code");
//设置code属性的值
fCode.set(easy,"10001");
Object objectCode=fCode.get(easy);
System.out.println(objectCode);
Field fsex=c.getDeclaredField("sex");
Field fAddress=c.getDeclaredField("address");
fsex.set(easy,"女");
//反射访问私有属性 必须先获取访问权限
fAddress.setAccessible(true);
fAddress.set(easy,"青岛");
System.out.println(fAddress.get(easy));
//getFields()
//
}
}
反射定义及API
反射:在程序运行期间,可以动态获取类中定义的属性和方法以及构造方法的机制(思想)的实现
反射的核心是Class类 程序中使用的类,每一个都有一个唯一对应的Class对象
反射的API:Field Method Constructor
反射会破坏类的封装性
public class EasyClassC {
public static <T> T getInstance(Class<T> clazz, Map values) throws InstantiationException, IllegalAccessException {
//通过反射获取实例 创建对象
clazz.newInstance();//通过类中的无参构造方法创建对象
T t = clazz.newInstance();
//通过反射获取类中定义的属性
Field[] farr= clazz.getDeclaredFields();
// System.out.println(Arrays.toString(farr));
for (Field f : farr) {
//获取属性的名字
String fname = f.getName();
//获取该属性在Map中的键值对 属性对相应的值
Object value = values.get(fname);
//设置属性访问权限
f.setAccessible(true);
f.set(t, value);
}
return t;
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Map map = new HashMap();
map.put("code","c293");
map.put("name","二发");
map.put("sex","女");
Student stu= getInstance(Student.class,map);
System.out.println(stu);
}
}
class Student{
private String name;
private String sex;
private String code;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", code='" + code + '\'' +
'}';
}
}
取和调用类的方法的方法。
获取类对象:
Class<Easy> c = Easy.class;
创建类的实例:
Easy easy = c.newInstance();
获取公有方法:
Method ma = c.getMethod("methodA");
ma.invoke(easy); 通过 invoke() 方法调用 methodA() 方法
获取带参数的公有方法:
Method mb = c.getMethod("methodB", int.class, int.class);
mb.invoke(easy, 23, 65); 通过 invoke() 方法调用 methodB() 方法, 并传入参数
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.util.Arrays;
public class EasyClassE {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IntrospectionException {
//反射获取构造方法
Class<Easy> c=Easy.class;
c.newInstance();//调用无参构造方法
//获取无参构造方法
Constructor<Easy> con= c.getConstructor();
con.newInstance();
con=c.getConstructor(String.class);
con.newInstance("饿哦");
//修饰符 使用Modifier的方法判断方法属性和构造方法的修饰符
Field f=c.getDeclaredField("test");
int fmod=f.getModifiers();
System.out.println(fmod);
boolean bool= Modifier.isStatic(fmod);
System.out.println(bool);
//内省 也是通过反射来实现的 内省不会破坏封装性
//内省 :底层是通过反射实现,内省获取属性的读方法和写方法(getter/setter)来获取和设置属性的内容,不会破坏类的封装性
//获取BeanInfo
BeanInfo bi=Introspector.getBeanInfo(c);
//获取写的方法和读的方法 setter/getter
PropertyDescriptor[] pds= bi.getPropertyDescriptors();
System.out.println(Arrays.toString(pds));
String pName= pds[0].getName();//获取该属性的名字
System.out.println("name"+pName);
Method read=pds[0].getReadMethod(); //获取该属性的getter方法
Method write= pds[0].getWriteMethod();//获取该属性的setter方法
//obj.setName("张三");//面向对象
//write.invoke(obj,"张三");//反射
Easy easy=c.newInstance();
write.invoke(easy,"张三");
}
}
1. 反射获取类的构造方法
- `Constructor<Easy> con = c.getConstructor();`
- `con.newInstance();` 使用构造方法创建实例
2. 获取修饰符信息
- `Field f = c.getDeclaredField("test");`
- `int fmod = f.getModifiers();`
- `boolean bool = Modifier.isStatic(fmod);`
3. 使用内省技术
- `BeanInfo bi = Introspector.getBeanInfo(c);`
- `PropertyDescriptor[] pds = bi.getPropertyDescriptors();`
- 获取属性的读写方法(`getReadMethod()`和`getWriteMethod()`)
4. 通过内省的方式访问和设置属性值
- `Method read = pds[0].getReadMethod();`
- `Method write = pds[0].getWriteMethod();`
- `write.invoke(easy, "张三");` 使用反射调用 setter 方法设置属性值
总结:
1. 反射可以用于获取类的构造方法、属性和方法的信息。
2. 内省基于反射实现,可以更方便地访问和设置类的属性,不会破坏类的封装性。
3. 反射和内省在框架开发、动态代码生成等场景下非常有用,可以提高代码的灵活性和可扩展性。