反射,就是加载类,并解剖出类的各个组成部分,指的是我们可以于运行时加载、探知、使用编译期间完全未知的
classes,反射在做框架时会需要用到,比如给你个配置文件,需要你运行一个地址里的class的某个方法,此时就不能用传统方法去实例化和调用方法,就可以用反射来解决。
(1)反射类的
构造函数。有getConstructor(Class<?>... parameterTypes) 和getDeclaredConstructor(Class<?>... parameterTypes) 两个方法,前者得到的是public构造函数,而后者得到的是private构造函数。
//测试得到构造函数
@Test
public void test1(){
try {
//加载Person类
Class class1=Class.forName("cn.itcast.reflect.Person");
//反射Person类的无参构造 public Person(){}
Constructor constuctor=class1.getConstructor(null);
//根据无参构造函数实例化对象
Person p=(Person) constuctor.newInstance(null);
//得到私有构造函数 private Person(String name,int age){}
Constructor constuctor1=class1.getDeclaredConstructor(String.class,int.class);
constuctor1.setAccessible(true);//暴力反射,得到类的私有方法
//不能访问,除非constuctor1.setAccessible(true)
Person p1=(Person) constuctor1.newInstance("name",21);
} catch (Exception e) {
e.printStackTrace();
}
}
(2)反射类的方法。有getMethod(String name, Class<?>... parameterTypes) 和getDeclaredMethod(String name, Class<?>... parameterTypes) 。
@Test
public void test2() throws Exception{
Person p=new Person();
Class class1=Class.forName("cn.itcast.reflect.Person");
//得到方法 ,第一个参数传入方法名,后一个参数传入方法需要传入的参数类型public void test(){}
Method method1=class1.getMethod("test", null);
//执行方法,传入对象和参数
method1.invoke(p, null);
//得到方法 public void test(String name){}
Method method2=class1.getMethod("test", String.class);
//执行方法
method2.invoke(p, "name");
//得到方法 private void test(int num){}
Method method3=class1.getDeclaredMethod("test", int.class);
//获得权限
method3.setAccessible(true);
method3.invoke(p, 3);
}
(3)反射类的main方法。class1.getMethod("main", String[].class)。不过这里有个地方需要注意。就是调用invoke方法传参是如果method.invoke(null,new String[]{"1","2"}),这样写会报传参个数
异常的
错误,因为JDK会把数组拆开,这样就会有多个String,就会报错。
@Test
public void test3() throws Exception{
Class class1=Class.forName("cn.itcast.reflect.Person");
Method method=class1.getMethod("main", String[].class);
//将数组包装起来,两种方法
method.invoke(null,new Object[]{new String[]{"1","2"}});
method.invoke(null,(Object)new String[]{"1","2"});
}
(4)反射类的字段。方法getField(String name) 。
@Test
public void test4() throws Exception{
Person p=new Person();
Class class1=Class.forName("cn.itcast.reflect.Person");
//得到name字段
Field field1=class1.getField("name");
//得到字段类型
Class type=field1.getType();
if(type.equals(String.class)){
String name=(String) field1.get(p);
System.out.println(name);
}
//设置字段值
field1.set(p, "bbbb");
System.out.println(p.name);
}
内省,内省是sun公司为了操作javabean属性而开发出来的,javabean就是将功能、处理、值、数据库访问和其他任何可以用java代码创造的对象进行打包,就是封装。为写成javabean,类必须是具体的和公共的,并且具有无参数的
构造器。比如下面就是一个javabean。
public class Student {
private String name;
private int age;
private int examid;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getExamid() {
return examid;
}
public void setExamid(int examid) {
this.examid = examid;
}
public void getGrade(){
}
}
这个javabean拥有5个属性,bean拥有属性有get或set方法决定,并且每个类都有继承父类的class属性。有两种方法javabean操作属性。
(1)可以通过java.beans 类 Introspector的getBeanInfo(Class<?> beanClass)
得到对象的属性,并通过 java.beans
接口 BeanInfo的getPropertyDescriptors()
得到属性描述器。
(2)通过java.beans 类PropertyDescriptor。
//得到属性
@Test
public void test1() throws Exception{
BeanInfo info1=Introspector.getBeanInfo(Person.class);
//可以去除父类属性
BeanInfo info2=Introspector.getBeanInfo(Person.class,Object.class);
PropertyDescriptor[] pds1 =info1.getPropertyDescriptors();//得到属性描述器
PropertyDescriptor[] pds2 =info2.getPropertyDescriptors();//得到属性描述器
for(PropertyDescriptor pd: pds1){
System.out.println(pd.getName());//得到属性名称
}
for(PropertyDescriptor pd: pds2){
System.out.println(pd.getName());//得到属性名称
}
}
//操纵属性
@Test
public void test2() throws Exception{
Person p=new Person();
PropertyDescriptor pd=new PropertyDescriptor("name",Person.class);
System.out.println(pd.getPropertyType());//得到属性的类型
Method method1=pd.getWriteMethod();//得到set方法
method1.invoke(p, "aaa");//执行p的set方法
System.out.println(p.getName());
Method method2=pd.getReadMethod();//得到get方法
System.out.println(method2.invoke(p, null));
}