(1)获取Class类对象——描述.class字节码文件
每个类被加载之后,系统就会为该类生成一个对应的Class对象。通过该Class对象就可以访问到JVM中的这个类。
在Java程序中获得Class对象通常有如下三种方式:
//第一种方式 通过Class类的静态方法——forName()来实现
class1 = Class.forName("com.lvr.reflection.Person");
//第二种方式 通过类的class属性
class1 = Person.class;
//第三种方式 通过对象getClass方法
Person person = new Person();
Class<?> class1 = person.getClass();
(2)类成员变量的反射
Field[] allFields = class1.getDeclaredFields();//获取class对象的所有属性
Field[] publicFields = class1.getFields();//获取class对象的public属性
Field ageField = class1.getDeclaredField("age");//获取class指定属性
Field desField = class1.getField("des");//获取class指定的public属性
(3)类成员方法的反射
Method[] methods = class1.getDeclaredMethods();//获取class对象的所有声明方法
Method[] allMethods = class1.getMethods();//获取class对象的所有public方法 包括父类的方法
Method method = class1.getMethod("info", String.class);//返回次Class对象对应类的、带指定形参列表的public方法
Method declaredMethod = class1.getDeclaredMethod("info", String.class);//返回次Class对象对应类的、带指定形参列表的方法
(4)类构造方法的反射
Constructor<?>[] allConstructors = class1.getDeclaredConstructors();//获取class对象的所有声明构造函数
Constructor<?>[] publicConstructors = class1.getConstructors();//获取class对象public构造函数
Constructor<?> constructor = class1.getDeclaredConstructor(String.class);//获取指定声明构造函数
Constructor publicConstructor = class1.getConstructor(String.class);//获取指定声明的public构造函数
//第一种方式 Class对象调用newInstance()方法生成
Object obj = class1.newInstance();
//第二种方式 对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成
Constructor<?> constructor = class1.getDeclaredConstructor(String.class);//获取指定声明构造函数
obj = constructor.newInstance("hello");
// 生成新的对象:用newInstance()方法
Object obj = class1.newInstance();
//首先需要获得与该方法对应的Method对象
Method method = class1.getDeclaredMethod("setAge", int.class);
//开启调用该方法的权限
method.setAccessible(true);
//调用指定的函数并传递参数
method.invoke(obj, 28);
//生成新的对象:用newInstance()方法
Object obj = class1.newInstance();
//获取age成员变量
Field field = class1.getField("age");
//将obj对象的age的值设置为10
field.setInt(obj, 10);
//获取obj对象的age的值
field.getInt(obj);
第七章 设计模式 —— 动态代理
public class LogHandler implements InvocationHandler {
// 目标对象
private Object targetObject;
//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
public Object newProxyInstance(Object targetObject){
this.targetObject=targetObject;
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
//根据传入的目标返回一个代理对象
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
@Override
//关联的这个实现类的方法被调用时将被执行
/*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start-->>");
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
Object ret=null;
try{
/*原对象方法调用前处理日志信息*/
System.out.println("satrt-->>");
//调用目标方法
ret=method.invoke(targetObject, args);
/*原对象方法调用后处理日志信息*/
System.out.println("success-->>");
}catch(Exception e){
e.printStackTrace();
System.out.println("error-->>");
throw e;
}
return ret;
}
}
// 接口
public interface UserManager{
public void addUser(String userId, String userName);
public void delUser(String userId) ;
public String findUser(String userId) ;
public void modifyUser(String userId, String userName) ;
}
// 实现类(委托类)
public class UserManagerImpl implements UserManager {
@Override
public void addUser(String userId, String userName) {
System.out.println("UserManagerImpl.addUser");
}
@Override
public void delUser(String userId) {
System.out.println("UserManagerImpl.delUser");
}
@Override
public String findUser(String userId) {
System.out.println("UserManagerImpl.findUser");
return "张三";
}
@Override
public void modifyUser(String userId, String userName) {
System.out.println("UserManagerImpl.modifyUser");
}
}
public class Client {
public static void main(String[] args){
LogHandler logHandler=new LogHandler();
UserManager userManager=(UserManager)logHandler.newProxyInstance(new UserManagerImpl());
// 获取动态代理对象
userManager.addUser("1111", "张三"); // 调用动态代理的addUser方法,该调用会转发到logHandler的invoke上,从而达到动态代理的效果
}
}
可以看到,我们可以通过LogHandler代理不同类型的对象,如果我们把对外的接口都通过动态代理来实现,那么所有的函数调用最终都会经过invoke函数的转发,因此我们就可以在这里做一些自己想做的操作,比如日志系统、事务、拦截器、权限控制等。这也就是AOP(面向切面编程)的基本原理。
AOP(AspectOrientedProgramming):将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码—解耦。
应用一:简单工厂创建对象
public class BasicFactory {
private BasicFactory(){}
private static BasicFactory bf = new BasicFactory();
private static Properties pro = null;
static{
pro = new Properties();
try{
//通过类加载器加载配置文件
pro.load(new FileReader(BasicFactory.class.getClassLoader().
getResource("config.properties").getPath()));
}catch (Exception e) {
e.printStackTrace();
}
}
public static BasicFactory getFactory(){
return bf;
}
//使用泛型获得通用的对象
public <T> T newInstance(Class<T> clazz){
String cName = clazz.getSimpleName(); //获得字节码对象的类名
String clmplName = pro.getProperty(cName); //根据字节码对象的类名通过配置文件获得类的全限定名
try{
return (T)Class.forName(clmplName).newInstance(); //根据类的全限定名创建实例对象
}catch (Exception e) {
throw new RuntimeException(e);
}
}
}
应用二:过滤符合输入关键字的数据
public class ListFilter<T> {
/**
* 过滤ArrayList中的关键字数据
* @param models 网络获取到的数据列表
* @param query 过滤关键字
* @param propertyName 泛型的数据过滤项
* @return 返回过滤后的数据
*/
public ArrayList<T> filter(ArrayList<T> models, String query, String propertyName) {
ArrayList<T> filteredModelList = null;
//实例化这个类赋给o
try {
query = query.toLowerCase();
filteredModelList = new ArrayList<>();
for (T model : models) {
final String text = getClassInfo(model,model.getClass().getName(),propertyName).toLowerCase();
if (text.contains(query)) {
filteredModelList.add(model);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return filteredModelList;
}
/**
* 获取类的属性值
* @param obj 类实例
* @param classNameString 类名
* @param propertyNameString 获取的属性名
* @return 属性值
*/
private String getClassInfo(Object obj,String classNameString,String propertyNameString) {
String returnString="";
try{
Class classInfo = Class.forName(classNameString);
if(!(classInfo.isInstance(obj))){
L.e("传入的java实例与配置的java对象类型不符!");
return returnString;
}
Field field = classInfo.getDeclaredField(propertyNameString);
field.setAccessible(true);
returnString=field.get(obj).toString();
}catch(Exception e){
e.printStackTrace();
}
return returnString;
}
}
导致反射效率慢的因素及解决:
注解(元数据)是一种代码级别的说明。是JDK 5.0 后引入的新特性。注解作为程序的元数据嵌入到程序中,声明在类、成员变量、成员方法等前面,用来对这些元素进行说明,注释。注解可以被解析工具/编译工具解析。
Annotation的作用可分为3类:
Class<ReflectTest> reflectTestClass = ReflectTest.class; // 1.通过反射获取字节码文件对象
Pro an = reflectTestClass.getAnnotation(Pro.class); // 2.调用getAnnotation(class)获取注解对象
String className = an.className();
String methodName = an.methodName(); // 3.调用注解对象中定义的抽象方法,获取返回值(返回值即注解信息)
注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler 的invoke方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java 常量池。
元注解
public @interface 注解名称{
... 属性列表
}
// 举例
@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotataion{
String name();
String website() default "hello";
int revision() default 1;
}
public class AnnotationDemo {
// 当注解中有成员变量时,若没有默认值,需要在使用注解时,指定成员变量的值。
@MyAnnotataion(name="lvr", website="hello", revision=2)
public void demo(){
System.out.println("I am demo method");
}
}
public class AnnotationParser {
public static void main(String[] args) throws SecurityException, ClassNotFoundException {
String clazz = "com.lvr.annotation.AnnotationDemo";
Method[] demoMethod = AnnotationParser.class
.getClassLoader().loadClass(clazz).getMethods();
for (Method method : demoMethod) {
if (method.isAnnotationPresent(MyAnnotataion.class)) {
MyAnnotataion annotationInfo = method.getAnnotation(MyAnnotataion.class);
System.out.println("method: "+ method);
System.out.println("name= "+ annotationInfo.name() +
" , website= "+ annotationInfo.website()
+ " , revision= "+annotationInfo.revision());
}
}
}
}
Pro.java
//注解配置文件:描述需要执行的类名和方法名
@Target ({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro{
String className();
String methodName();
}
ReflectTest.java
public class ReflectTest{
public static void main(String[] args) throws Exception{
// 前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法
// 1. 解析注解
// 1.1 获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
// 2.获取上边的注解对象,起始就是在内存中生成了一个注解接口的子类实现对象
// public class ProImpl implements Pro{
// public String className(){
// return "cn.itcast.annotation.Demo1";
// }
// public String methodName(){
// return "show";
// }
// }
Pro an = reflectTestClass.getAnnotation(Pro.class);
// 3.调用注解对象中定义的抽象方法,获取返回值
String className = an.className();
String methodName = an.methodName();
// 4. 加载该类进内存
Class cls = Class.forName(className);
// 5. 创建对象
Object obj = cls.newInstance();
// 6. 获取方法对象
Method method = cls.getMethod(methodName);
// 7. 执行方法
method.invoke(obj);
}
public class Person {
private Bike mBike;
private Car mCar;
private Train mTrain;
public Person(){
mBike = new Bike();
// mCar = new Car();
// mTrain = new Train();
}
public void goOut(){
System.out.println("出游");
mBike.drive();
// mCar.drive();
// mTrain.drive();
}
public static void main(String ... args){
//TODO:
Person person = new Person();
person.goOut();
}
}
public class Person {
private Driveable mDriveable;
public Person2(Driveable driveable){
this.mDriveable = driveable;
}
public void goOut(){
System.out.println("出门啦");
mDriveable.drive();
// mCar.drive();
// mTrain.drive();
}
public static void main(String ... args){
//TODO:
Person2 person = new Person2(new Car());
person.goOut();
}
}
public interface DepedencySetter {
void set(Driveable driveable);
}
public class Person2 implements DepedencySetter {
//接口方式注入
@Override
public void set(Driveable driveable) {
this.mDriveable = mDriveable;
}
private Driveable mDriveable;
//构造函数注入
public Person2(Driveable driveable){
this.mDriveable = driveable;
}
//setter 方式注入
public void setDriveable(Driveable mDriveable) {
this.mDriveable = mDriveable;
}
public void goOut(){
System.out.println("出门啦");
mDriveable.drive();
//mCar.drive();
// mTrain.drive();
}
public static void main(String ... args){
//TODO:
Person2 person = new Person2(new Car());
person.goOut();
}
}
ButterKnife:是视图注入中相对简单易懂的开源框架,其优势在于:
@InjectView(R.id.listview)
ListView mListview;
@OnItemClick(R.id.listview)
public void onItemClick(int position){
Toast.makeText(getBaseContext(), "item"+position, Toast.LENGTH_SHORT).show();
}