反射:
反射是动态语言的关键,反射机制运行java在执行期间,借助Reflection提供的API取得任何类的内部信息,
并能直接操作任意对象的内部属性与方法
本文只是自学菜鸟的一些总结,菜得很,希望大佬的指正和纠错
供以下程序操作的Person类
package java1;
@MyAnnotatino(value = "hi")
public class Person extends Creature<String> implements Comparable<String>,Myinterface{
private String name;
int age;
public int id;
@MyAnnotatino(value = "abc")
public Person() {
}
@MyAnnotatino
private Person(String name){
this.name = name;
}
@MyAnnotatino
public String getName() {
return name;
}
private String show(String nation){
System.out.println("我的国籍是" + nation);
return nation;
}
public void setName(String name) {
this.name = name;
}
@MyAnnotatino
public int getAge() {
return age;
}
@MyAnnotatino(value = "hi")
public void setAge(int age) {
this.age = age;
}
public String display(String interests){
return interests;
}
@Override
public void myvoid() {
System.out.println("一个人");
}
@Override
public int compareTo(String o) {
return 0;
}
public static void main(String[] args) {
ReflectionTest.Person p1 = new ReflectionTest.Person();
System.out.println();
}
private static void showDesc(){
System.out.println("我是一个人");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
'}';
}
}
通过反射调用运行时类的属性
其实通过反射调用运行时类的各种属性的步骤都是一样的,只是各个方法名不同。
以获取类中的属性为例:
Class clazz = Person.class;
//获取所有属性结构:getFields
Field[] field = clazz.getFields();
for (Field f:field){
System.out.println(f);
}
//getDeclaredFiels:获取运行时类自己声明过的属性,不考虑权限,不包含父类中声明的属性
Field[] declaredFields = clazz.getDeclaredFields();
//用增强for循环输出
for (Field f:declaredFields){
System.out.println(f);
}
通过反射获取运行时类的各种权限修饰符,方法,注解等等
其实步骤和上面是一样的,只是有一些细微的差距
//获取权限修饰符
Class clazz = Class.forName("java1.Person");
Field[] df = clazz.getDeclaredFields();
for (Field f:df){
//权限修饰符:getModifiers,获取权限修饰符,int类型:0:default,1:public,2:private,3:protected
//将int型权限修饰符变为字符串形式:Modifier.toString
System.out.println(Modifier.toString(f.getModifiers()));
//数据类型:getType
System.out.println(f.getType().getName());
//变量名:getname:获取变量名
System.out.println(f.getName());
//获取方法声明的注解,形参列表,异常,形参名等
Class<Person> clazz = Person.class;
Method[] me = clazz.getDeclaredMethods();
for (Method m:me){
//getAnnotations:获得当前方法的所有注解
Annotation[] ann = m.getAnnotations();
for (Annotation a:ann){
System.out.println("注解为"+a);
}
System.out.println(Modifier.toString(m.getModifiers()) );
//返回值类型returnType:返回型类型的名字:getName
Class<?> returnType = m.getReturnType();
System.out.println(returnType.getName());
//方法名:getName:通常情况方法名后会配合形参列表
System.out.print(m.getName());
System.out.print("(");
//形参列表:获取形参类型方法:getParameterTypes
//获取形参名:
Class<?>[] types = m.getParameterTypes();
if (!(types == null&& types.length == 0)){
for (int i= 0;i<types.length;i++){
//获取形参名,如果形参是最后一个,就不加逗号
if (i == types.length-1){
System.out.print(types[i].getName()+"args_"+i);
break;
}
System.out.print(types[i].getName()+"args_"+i+",");
}
System.out.print(")");
//抛出的异常:getExceptionTypes
Class<?>[] ex = m.getExceptionTypes();
if (!(ex == null&&ex.length ==0)){
System.out.println("throws");
for (int i =0;i<ex.length;i++){
if (i == ex.length-1){
System.out.println(ex[i].getName());
break;
}
System.out.println(ex[i].getName() + "i");
}
}
}
//
System.out.println("*********");
}
}
}
通过反射操作运行时类的属性,方法
操作属性方法时,一般使用getdeclared的相关方法,因为此类方法可以调用任何权限修饰符的方法属性
其中的关键方法为:setAccessible(),将形参填入true时,就可以保证属性和方法的修改和访问
public void Test2() throws Exception {
Class<Person> clazz = Person.class;
Person p = clazz.newInstance();
//getDeclaredField(String name)
Field name = clazz.getDeclaredField("name");
//为了避免出现非法访问的情况,必须在设置之前进行setAccessible方法,保证当前属性是可访问的
name.setAccessible(true);//保证当前属性时可访问的
name.set(p,"ljy"); //此时出现IllegalAccessException:非法访问,即文件找到了但是没有权限访问
System.out.println(name.get(p));
}
总结
通过反射操作运行时类中的属性方法步骤其实都是一样的
1.获取运行时类的class。
2.创建运行时类的对象(供非static的结构使用)
3.调用目标类型的get或getdeclared方法
4.需要操作时,为了确保可访问,调用setAccessible方法
5.调用set,get等方法进行操作