今日重点: 反射 什么是反射 Class类对象获取方式 Field(get/set) Method(invoke) Constructor(newInstance) 内省 BeanInfo readMethod writeMethod
反射
在程序运行期间,可以动态获取类中定义的属性和方法以及构造方法的机制(思想)的实现。
反射的核心是Class类 程序中使用的类,每一个都有一个唯一对应的Class对象。
反射的API:FIeld Method Constructor(会拼写)。
面试题:API所在包名:java.lang.reflect
反射会破坏类的封装性 应用场景不同,通过场景说明,不能直接的说好不好
类的类对象
java中存储了类的内容,这个内容也因该是对象,java中每一个类都有一个内存,这每一块内存都是一个对象,这些对象记录了这些类中声明了哪些属性和方法以及构造方法,java将这些类抽象为一个class类
类对象获取
Class类的对象是不能new的
//获取类的类对象 面试题
//通过类名获取
Class clazz=EasyA.class;
//通过对象获取
clazz=new EasyA().getClass();
//通过Class方法的forName方法获取 传入全名
clazz=Class.forName("com.easy25.EasyColor");
System.out.println(clazz);
反射获取属性
java中用来记录类的属性的类叫做Field,使用类对象的getField或getDeclaredField方法获取类的单个属性,或者getFields或getDeclaredFields获得多个属性;注意:getField和getFields只能获取类中public声明的属性,getDeclaredField和getDeclaredFields可以获取所有属性。
使用:Field实例的get方法可以获取被反射类实例里对应属性具体的值,set方法可以对该种类的实例注入该属性的值,反射访问私有属性注入值时必须先获取访问权限,使用setAccessible传入true即可。
获取父类属性只能getSuperClass()获取父类类对象,然后获取;获取被子类重写的父类方法也一样。
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, IntrospectionException, InvocationTargetException {
//类的类对象中存储了类中定义的内容 属性 方法 构造方法
//获取类对象
Class c=Easy.class;
c=new Easy().getClass();
c=Class.forName("com.easy26.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);
//getField getFileds 只能获取类中public声明的属性
Field fCode=c.getDeclaredField("code");
Object objCode=fCode.get(easy);
System.out.println(objCode);
//设置code的值
fCode.set(easy, "9527");
System.out.println(easy.code);
Field fSex=c.getDeclaredField("sex");
fSex.set(easy, "塑料袋");
System.out.println(easy.sex);
//反射访问私有属性 必须先获取访问权限
Field fAddress=c.getDeclaredField("address");
fAddress.setAccessible(true);//设置访问权限
fAddress.set(easy, "USA");
System.out.println(fAddress.get(easy));
}
Modifier判断修饰符
用Modifier类的方法来判断方法、属性、构造方法被哪些修饰符修饰,步骤:获取要判断的属性的Field实例,获取Field实例的Modifier值,使用Modifier静态方法判断。
//举例判断是否使用static修饰
Field f=c.getDeclaredField("name");
int fmod=f.getModifiers();
boolean bool=Modifier.isStatic(fmod);
System.out.println(bool);
通过反射获取实例
举例代码:
package com.easy25;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Practice extends F{
public String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Practice [name=" + name + ", sex=" + sex + "]"+"super.salary:"+super.salary;
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
Class clazz=Practice.class;
Field[] farr=clazz.getDeclaredFields();
Practice p=(Practice) clazz.newInstance();
for(Field fitem:farr) {
System.out.println(fitem.getName());
if(fitem.getName().equals("name")) {
fitem.set(p, "张三");
}else if(fitem.getName().equals("sex")) {
fitem.set(p, "男");
}else {
fitem.set(p, "100");
}
}
Class fclazz=clazz.getSuperclass();
farr=fclazz.getDeclaredFields();
for(Field fitem:farr) {
fitem.set(p, "100");
}
System.out.println(p);
Method[] marr=clazz.getDeclaredMethods();
for(Method mitem:marr) {
if(mitem.getName().contains("get")) {
System.out.println(mitem.getName());
System.out.println(mitem.invoke(p));
}
}
/*
* BeanInfo bif=Introspector.getBeanInfo(clazz);
PropertyDescriptor[] pd=bif.getPropertyDescriptors();
for(PropertyDescriptor item:pd) {
if(!item.getName().equals("class")) {
System.out.println(item.getName());
Method read=item.getReadMethod();
Method write=item.getWriteMethod();
write.invoke(p, "111");
System.out.println(read.invoke(p));
}
}
*/
System.out.println(p);
}
}
class F{
public String salary;
public String getSalary() {
System.out.println("salary:"+salary);
return salary;
}
public void setSalary(String salary) {
this.salary = salary;
}
}
反射获取方法
反射获取方法getMethod(和属性一样,只能获取public方法),其他要用getDeclaredMethod,需要传入方法名,带参需要传入参数列表对应的类对象列表。
使用: method.invoke(对象,参数列表);也是可能有返回值,类型是Object
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//获取类对象
Class<Easy> c=Easy.class;
//加<Easy>j=就不用强转,泛型原因
Easy easy=c.newInstance();
//反射获取方法 Method
//获取public方法,其他要用c.getDeclaredMethod
Method ma=c.getMethod("methodA");
//调用方法 对象.方法名()
//反射 method.invoke(对象)
Object b=ma.invoke(easy);
System.out.println(b);
//需要传参
Method mb=c.getMethod("methodB",int.class,int.class);
mb.invoke(easy, 23,45);
}
反射获取构造方法
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//反射获取构造方法
Class<Easy> c=Easy.class;
c.newInstance();//无参
//获取无参构造方法
Constructor<Easy> con=c.getConstructor();
con.newInstance();
//带参构造方法
con=c.getConstructor(String.class);
con.newInstance("张三");
}
内省
也是通过反射实现的 内省不会破坏封装性:底层是通过反射实现,内省获取属性的读方法和写方法(getter/setter)来获取和设置属性的内容,不会破坏类的封装性。
使用步骤:获取类对象对应的BeanInfo对象,调用getPropertyDescriptors方法获取属性描述器数组PropertyDescriptor[],调用数组内每一个PropertyDescriptor的getReadMethod/getWriteMethod方法获取读写的Method对象,使用invoke写入,read.invoke方法调用的是类的getter方法,write.invoke方法调用的是类的setter方法
内省可以直接获得本类和父类的所有getter和setter方法,不需要获取父类类对象然后注入
Class c=Easy.class;
//获取BeanInfo
BeanInfo bi=Introspector.getBeanInfo(c);
//获取属性的写的方法和读的方法 setter/getter
PropertyDescriptor[] pds=bi.getPropertyDescriptors();
String pname=pds[0].getName();//获取属性名字
System.out.println(pname);
//这里要明确是什么类型传入什么类型参数
Method read=pds[0].getReadMethod();//该属性对应的getter方法
Method write=pds[0].getWriteMethod();//该属性对应的Setter方法
//obj.setName("");
//write.invoke(obj,"");
write.invoke(easy, "张三");