一.理解反射
反射机制是用来描述所有的类
Class 描述类本身 Field 描述属性 Method描述方法 Construtor描述类构造方法 package描述类的包 Annotion 描述类中的注解(注解可以放在方法,参数,类上面,方法上等)
二.反射的基本使用
1.基本操作:
/**
* @author Seven 测试的实体类
*
*/
public class Person {
public String name;
private int age;
public void eat(String food) {
System.out.println("person eat " + food);
}
private void eat() {
System.out.println("person eat something!");
}
@MyAnnotation({"小明","12"})
public Person() {
System.out.println("constructor");
}
public Person(String constructor) {
System.out.println("constructor:" + constructor);
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
/**
* @author Seven 测试反射当中的一些方法
*
*/
public class TsReflect {
public static void main(String[] args) {
try {
// 关于类的一些操作
Class clz = Class.forName("com.ts.annotionandreflect.Person");
System.out.println(clz.getModifiers()); // 获取类的修饰符
System.out.println(clz.getName());// 获取类全名
System.out.println(clz.getSimpleName());// 获取类名
Package p = clz.getPackage();
System.out.println(p.getName());// 获取类包名
Class clzSuper = clz.getSuperclass();// 获取超类
System.out.println(clzSuper.getName());
Class[] clzInterface = clz.getInterfaces();// 获取类的实现接口
Person object = (Person) clz.newInstance();// 相当于调用类的默认无参数构造方法 如果方法重写过 可能会引起异常
// 关于属性的一些操作
Field fieldName = clz.getField("name");// 获取公有属性,包含父类的属性
fieldName.getModifiers();// 属性的修饰符
fieldName.getType();// 属性的类型
fieldName.getName();// 属性名
fieldName.set(object, "field"); // 给属性赋值
String name = (String) fieldName.get(object);
System.out.println(name);
// 所有属性
Field fieldAge = clz.getDeclaredField("age");// 获取所有属性,只能获取本类的属性
fieldAge.getModifiers();// 属性的修饰符
fieldAge.getType();// 属性的类型
fieldAge.getName();// 属性名
fieldAge.setAccessible(true); // 表示私有属性可直接被操作
fieldAge.set(object, 12); // 给属性赋值
int age = (Integer) fieldAge.get(object);
System.out.println(age);
// 关于方法的一些操作
Method method = clz.getMethod("eat", String.class); // 获取公有的方法 自己或父类
method.getModifiers();// 方法的修饰符
method.getReturnType();// 方法的发返回值类型
method.getName();// 获取方法名
method.getParameterTypes(); // 获取方法的参数列表类型
method.getExceptionTypes(); // 返回方法的抛出异常类型
method.invoke(object, "foot");
Method method1 = clz.getDeclaredMethod("eat"); // 获取所有方法 只能是本类的方法
method1.setAccessible(true);// 表示私有方法可直接被操作
method1.invoke(object);
// 构造方法
Constructor constructor = clz.getConstructor(String.class);
constructor.getModifiers();// 方法的修饰符
constructor.getName();// 获取方法名
constructor.getParameterTypes(); // 获取方法的参数列表类型
constructor.getExceptionTypes(); // 返回方法的抛出异常类型
Object objectCons = constructor.newInstance("construct"); // 生成对象
Constructor constructor1 = clz.getConstructor();
Object objectCons1 = constructor1.newInstance(); // 生成对象
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2.利用反射提供一个生成对象的方法达到控制反转的效果:
/**
* @author Seven 利用反射来生成无逻辑功能的实体对象,不用在去new一个对象
*
*/
public class TsReflectPerson {
private String name;
public void setName(String name) {
System.out.println("name:"+name);
}
/**
* @param clz 所需生成的类的类对象
* @return 返回clz类对应的对象 IOC控制反转 如果还要注入信息叫DI(依赖注入它的前提是有IOC)
*/
public static Object getBean(Class clz) {
Object object=null;
try {
object= clz.newInstance();
//做个DI 注入信息
Field[] fields=clz.getDeclaredFields();
for (Field field : fields) {
String fieldName=field.getName();
StringBuilder sb=new StringBuilder("set").append(fieldName.substring(0,1).toUpperCase()).append(fieldName.substring(1));
Method setMethod=clz.getMethod(sb.toString(),field.getType());
setMethod.invoke(object, "12");//可以把信息放到文件中 读取进去
}
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return object;
}
public static void main(String[] args) {
System.out.println(getBean(TsReflectPerson.class));
}
}
三.理解注解
Annotation(注解)
1.可以写在类、属性、方法、构造方法、参数前面,一般是@xxx[{信息}]
2.作用:
a.注释说明作用,比如:@Deprecated 表示已过时的api;
b.用来做代码的检测和验证 比如:@override
c.可以携带信息(内容)只能携带基本数据类型 String 枚举 、注解类型、或数组类型(以上类型的数组) @SuppressWarnings(“unused”) 表示定义变量从未被使用
3.自定义注解:
@Retention(RetentionPolicy.RUNTIME)//元注解 定义注解存在的作用域 比如这里的运行时的作用域
@Target({ElementType.FIELD,ElementType.LOCAL_VARIABLE,ElementType.CONSTRUCTOR}) //元注解 定义注解放置的位置 比如这里能放到属性中
public @interface MyAnnotation {
// @Inherited 也是元注解 表示注解可以被继承
// @Documented 文档类型的元注解 表示能被文档记录
//注解的方法必须有返回值 返回值类型必须是基本数据类型 String 枚举 、注解类型、或数组类型(以上类型的数组)
String[] value(); //方法没有参数 方法的作用是把信息给别人 如果只有一个方法名叫value 使用时可以省略方法名
}
四.注解的使用(反射配合使用,利用注解反射生成对象)
public class TsAnnotation {
public static void main(String[] args) throws Exception {
// 解析AnnotationPerson类的注解 需要用到反射技术 注解的一般使用
// 1.获取class对象
Class clz = Person.class;
// 2.获取属性
Field field = clz.getDeclaredField("name");
// 3.获取属性上的注解对象
Annotation myTsAnnotation = field.getAnnotation(MyAnnotation.class);
// 4.获取注解的class对象
Class clzAnnotation = myTsAnnotation.getClass();
// 5.获取注解的方法
Method method = clzAnnotation.getMethod("value");
// 6.执行注解方法,获取传递的信息
String[] strs = (String[]) method.invoke(myTsAnnotation);
for (String string : strs) {
System.out.println(string);
}
System.out.println(getBean("com.ts.annotionandreflect.AnnotationPerson"));
}
/**
* @param clzName
* @return 通过注解反射的技术来获取对象
* @throws Exception
*/
public static Object getBean(String clzName) throws Exception {
Object object = null;
Class clz=Class.forName(clzName);
// clz.newInstance();
Constructor con=clz.getConstructor();
object=con.newInstance();
//获取注解中的携带信息 给对象赋值
Annotation annotation=con.getAnnotation(MyAnnotation.class);
Class annotationClass=annotation.getClass();
Method method=annotationClass.getMethod("value");
String[] strs=(String[]) method.invoke(annotation);
//获取类属性的set方法
Field[] fields = clz.getDeclaredFields();
for (int i=0; i<fields.length; i++) {
String fieldName=fields[i].getName();
StringBuilder sb=new StringBuilder("set").append(fieldName.substring(0,1).toUpperCase()).append(fieldName.substring(1));
Method setMethod=clz.getMethod(sb.toString(), fields[i].getType());
System.out.println(setMethod.getName()+","+strs[i]);
//转换属性类型
setMethod.invoke(object,fields[i].getType().getConstructor(String.class).newInstance(strs[i]));
}
//
return object;
}
}