今日重点: 反射 什么是反射 Class类对象获取方式 Field(get/set) Method(invoke) Constructor(newInstance) 内省 BeanInfo readMethod writeMethod
一、反射
在Java中,反射是指程序在运行时动态地检测、获取和操作类、对象、方法和属性的能力。通过反射,我们可以在运行时获取任意一个类的信息,包括类的名称、方法、字段等,并且可以在运行时创建对象、调用方法和访问属性。
反射:在程序运行期间,可以动态获取类中定义的属性和方法以及构造方法的机制(思想)的实现 反射的核心是Class类 程序中使用的类,每一个都有一个唯一对应的Class对象 反射的API:Field Method Constructor API所在包名:java.lang.reflect 反射会破坏类的封装性 通过场景说明(没有绝对的好坏,要看具体情况)
有对象前必须先有类, static来修饰类的属性和方法 在Java中存储了类的内容,这个内容也应该是一个对象 java中每一个类都有一个内存,这每一个内存都是一个对象 这些对象记录了这些类中声明那些属性和方法以及构造方法 java将这些类抽象为一个类型叫Class类
1、Class类
Class类的对象是不能new的 该类的对象中存储了类中定义的内容 属性/方法/构造方法
获取类的类对象 有3种方式
通过类名获取类对象
Class clazz= EasyClassA.class;
通过对象获取类对象
clazz=new EasyClassA().getClass();
通过Class方法的forName方法获取
clazz=Class.forName("com.easy7_25.EasyColor");
2、获取类中的属性
Java中用来记录类的属性的类 叫做Field
fName变量指向的对象就是Easy类中的name属性
Field fName=c.getField("name");
获取某一个Easy类对象的name属性的值
Object objectName=fName.get(easy);
注入该属性的值
fName.set(easy,"李四");
getField getFields 只能获取类中的public声明的属性
非public属性可以用getDeclaredField()来获取 getDeclaredField即获取定义的属性
Field fCode=c.getDeclaredField("code");
fCode.set(easy,"10001");
Object objCode=fCode.get(easy);//通过反射获取easy对象的code属性的值
Field fSex=c.getDeclaredField("sex");
fSex.set(easy,"女");
获取父类的属性 调用类对象的getSuperclass方法通过子类的类对象创建父类的类对象 获取属性大致与子类相同
Class<?> super = c.getSuperclass();
反射访问私有属性 必须先获取访问权限 访问当前权限外的属性都需先获取权限 权限通过setAccessible方法设置 置true即可
Field fAddress=c.getDeclaredField("address");
fAddress.setAccessible(true);
fAddress.set(easy,"青岛");
完整代码:
public class EasyClassB {
public static void main(String[] args) throws ClassNotFoundException,
NoSuchFieldException, IllegalAccessException {
//类的类对象中存储了类中定义的内容 属性 方法 构造方法
//获取类对象
Class c=Easy.class;
c=new Easy().getClass();
c=Class.forName("com.easy7_26.Easy");
//获取类的属性
//Java中用来记录类的属性的类 叫做Field
//fName变量指向的对象就是Easy类中的name属性
Field fName=c.getField("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);
System.out.println("------------------");
//getField getFields 只能获取类中的public声明的属性
Field fCode=c.getDeclaredField("code");
fCode.set(easy,"10001");
Object objCode=fCode.get(easy);//通过反射获取easy对象的code属性的值
System.out.println(objCode);
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));
}
}
class Easy {
public String name;
protected String code;
String sex;
private String address;
static int maxage;
public static final transient String test=null;
public Easy(){}
public Easy(String name){
this.name=name;
}
}
3、用反射设置对象的属性例子
通过反射获取实例 创建相应类的对象
T t=tClass.newInstance();//通过类对象中的无参构造方法创建对象
public class EasyClassC {
public static <T> T getInstance(Class<T> tClass, Map values) throws
InstantiationException, IllegalAccessException {
//通过反射获取实例 创建相应类的对象
T t=tClass.newInstance();//通过对象类中的无参构造方法创建对象
//通过反射获取类中定义的属性
Field[] farr=tClass.getDeclaredFields();
//System.out.println(Arrays.toString(farr));
for (Field fitem:farr){
//获取属性的名字
String fname=fitem.getName();
//获取该属性在Map中的键值对 属性对应的值
Object value=values.get(fname);
//设置属性访问权限
fitem.setAccessible(true);
//注入
fitem.set(t,value);
}
return t;
}
public static void main(String[] args) throws
InstantiationException, IllegalAccessException {
Map map=new HashMap<>();
map.put("code","C1001");
map.put("name","张三");
map.put("sex","女");
Student stu=getInstance(Student.class,map);
System.out.println(stu);
}
}
class Student{
private String code;
private String name;
private String sex;
@Override
public String toString() {
return "Student{" +
"code='" + code + '\'' +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
4、 获取类中的方法
获取public方法getMethod() getDeclaredMethod获取无权限方法
Method ma=c.getMethod("methodA");
Method mb=c.getMethod("methodB",int.class,int.class);
调用方法 对象.方法名() 面向对象 method.invoke(对象) 反射
invoke的返回值都是Object
ma.invoke(easy);
mb.invoke(easy,23,45);
完整代码:
public class EasyClassD {
public static void main(String[] args) throws NoSuchMethodException,
InstantiationException, IllegalAccessException, InvocationTargetException {
//获取类对象
Class<Easy> c= Easy.class;
//反射获取方法 Method
Easy easy=(Easy) c.newInstance();
//获取public方法 getDeclaredMethod获取无权限方法
Method ma=c.getMethod("methodA");
//调用方法 对象.方法名()
//method.invoke(对象) 反射
ma.invoke(easy);
Method mb=c.getMethod("methodB",int.class,int.class);
//easy.methodB(12,34)
mb.invoke(easy,23,45);
}
}
public class Easy {
public String name;
protected String code;
String sex;
private String address;
static int maxage;
public static final transient String test=null;
public Easy(){}
public Easy(String name){
this.name=name;
}
public void methodA(){
System.out.println("methodA");
}
public void methodB(int a,int b){
System.out.println("methodB");
System.out.println("两个参数分别为:"+a+","+b);
}
}
5、获取构造方法
(1)无参构造
类对象.newInstance() 先Constructor<Easy> con=c.getConstructor(); 再con.newInstance();
以上两种均可
(2)有参构造
Constructor<Easy> con=c.getConstructor(String.class);
Easy a=con.newInstance("张三");
只有这一种, 传入的参数是可变参数
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);
Easy a=con.newInstance("张三");
//System.out.println(a.name);
}
}
6、 修饰符
使用Modifier的方法判断方法、属性、构造方法的修饰符
Field f=c.getDeclaredField("test");
int fmod=f.getModifiers();
System.out.println(fmod);
boolean bool=Modifier.isStatic(fmod);
System.out.println(bool);
二、内省
也是通过反射来实现的 内省不会破坏封装性
1、 获取BeanInfo
BeanInfo bi=Introspector.getBeanInfo(c);
其中c是类对象
2、 获取属性的写方法和读方法 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方法
3、创建对象并调用获取的方法
Easy easy=c.newInstance();
write.invoke(easy,"张三");