如何应对Android面试官->Retrofit中注解、反射、动态代理、手写实现

Retrofit核心源码分析(一)- 注解解析和动态代理 Retrofit是目前Android平台上比较流行的网络请求框架之一,它提供了一种简洁、灵活的方式来处理HTTP请求和响应。Retrofit的设计目的是使网络请求的代码更加容易编写和阅读,同时还提供了许多有用的特性,如注解解析、动态代理等。在本文中,我们将对Retrofit的注解解析和动态代理进行详细的分析。 阅读详情

注解 反射 可以查看上一章的讲解 如何应对Android面试官->Java中的注解、反射、手写ButterKnife核心实现

代理模式

静态代理 

代理模式类图

静态代理主要分三个角色:抽象角色、真实角色、代理角色 

 抽象角色:指代理角色和真实角色对外提供的公共方法,一般为一个接口; 

public interface Message { 
    void message(); 
}

真实角色:需要实现抽象角色接口,定义了真实角色索要实现的业务逻辑,以便代理角色调用,也是真正的业务逻辑在此;

 public class Alvin implements Message { 
    public void message() { // } 
} 

代理角色:需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑来实现抽象方法,并可以附加自己的操作,将统一流程控制放到代理角色中处理; 

 通过代理,把调用者对真实对象的调用隔离了起来;  

public class Agent implements Message() { 
    private Message message; 
    public Agent(Message message) { 
        this.message = message; 
    } 
    public void message() { 
        // before(); 
        message.message(); 
        after(); 
    } 
    private void before() { } 
    private void after() { } 
} 

静态代理模式的实际应用

网络请求框架的封装

隔离层就是我们的代理对象,而真实对象就是我们的封装层,当我们发起网络请求的时候,业务并不需要关心具体使用的是哪个网络框架来发起请求,只需要操作隔离层的 HttpRequest 就行,当我们需要用 Volley 的时候,就只需要把我们的 Volley 的封装层实现赋值给隔离层的 HttpRequest 即可,那么就会使用 Volley 发起网络请求,如果要切换到 OkHttp,那么就只需要创建 OKHttp 的实现并赋值给隔离层的 HttpReqeust 即可;

动态代理

通过一个代理类,来实现全部的代理功能;在运行时再创建代理类和其实例,因此显然效率更低。要完成这个场景,需要在运行期动态创建一个Class。JDK提供了Proxy 来完成这件事;

基本使用

抽象角色

interface Api {
    void test(String passName);
}

真实角色

class ApiImpl implements Api {
    @Override    public void test(String passName) {
        System.out.println("真实实现:" + passName);
    }
}

创建真实实例角色

ApiImpl impl = new ApiImpl();

JDK动态代理实现

Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] {Api.class}, new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        return Method.invoke(impl, args);
    }
})

实际上, Proxy.newProxyInstance 会创建一个 Class,与静态代理不同,这个 Class 不是由具体的 .java 源文件编译而来,即没有真正的文件,只是在内存中按照 Class 格式生成了一个Class。

动态代理的原理

Android SDK 中的 Proxy.java 中的具体实现

final Class<?> [] intfs = interfaces.clone(); // 对接口进行了一个拷贝,获取了一个 Class 对象的集合;
Class<?> cl = getProxyClass0(loader, intfs); // 获取一个 class
final Constructor<?> cons = cl.getConstuctor(constructorParams); // 获取这个 class 的构造函数
cons.newInstance(new Object[]{h}); // 对这个 class 进行实例化

所以:newProxyInstance() 返回的是一个 class 对象;

那么,这个 Class<?> cl 是怎么来的? 它里面的代码是什么样的呢?

那么这个 .class 的实例对象是怎么生成的?

这里要额外提到一点 类的生命周期

class 是由 javac 把 .java 文件编译成 .class,是一个实实在在存在的文件,存放在我们的硬盘中,而 动态代理 帮我们生成了一个 .class 是没有这个文件的,而是直接在内存中 一份实例化对象。

通过 ProxyGenerator.generateProxyClass 生成

String var23 = var16 + "$Proxy" + var19;
byte[] var22 = ProxyGenerator.generateProxyClass(var23, var2, var17);
try {    
    return Proxy.defineClass0(var1, var23, var22, 0, var22.length);
} catch (ClassFormatError var14) {    
    throw new IllegalArgumentException(var14.toString());
}

也就是说,我们将 byte[] var22 这个数组写入到一个文件中,就可以看到 动态代理 帮我们生成的 class 实例对象 都有哪些内容

String name = Api.class.getName()+"$Proxy0";
//生成代理指定接口的Class数据
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{Api.class});
FileOutputStream fos = new FileOutputStream("lib/" + name+".class");
fos.write(bytes);fos.close();

生成的文件中可以查看我们的代理类

在初始化时,获得method 备用。而这个代理类中所有方法的实现变为:

这里的 h 其实就是 InvocationHandler 接口,所以我们在使用动态代理时,传递的InvocationHandler 就是一个监听,在代理对象上执行方法,都会由这个监听回调出来。

手写Retrofit实现

Retrofit 核心实现主要分为四部分注解、Retrofit、ServiceMethod、Parameter

Retrofit的核心实现主要是 动态代理、注解解析、构建请求参数、封装Call.Factory发起网络请求。

Retorfit时序图如下:

注解

手写只实现了 @POST、@GET、@QUERY、@FIELD

@Target(METHOD)
@Retention(RUNTIME)
public @interface POST {    
    String value() default "";
}
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {    
    String value() default "";
}
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Query {    
    String value();
}
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Field {    
    String value();
}

动态代理 MyRetrofit

OKHttp 发起网络请求,主要依靠的就是 Call.Factory HttpUrl

Call.Factory 提供了newCall方法用来发起请求,HttpUrl 用来构建请求参数和请求方式

MyRetrofit 也参考 Retorfit 采用 建造者模式实现,主要用来让调用方传递构建的 Call.Factory 和 HttpUrl,以及动态代理创建代理对象,调用 ServiceMethod 用来解析注解并封装请求参数;

public class MyRetrofit {    
    // 参考 Retrofit 的实现,也增加一层缓存
    final Map<Method, ServiceMethod> serviceMethodCache = new ConcurrentHashMap<>();    
    // 使用 OKhttp 提供的 Call.Factory
    final Call.Factory callFactory;  
    // 使用 OKHttp 提供的 HttpUrl      
    final HttpUrl baseUrl;
    
    MyRetrofit(Call.Factory callFactory, HttpUrl baseUrl) {                this.callFactory = callFactory;        
        this.baseUrl = baseUrl;    
    }
    
    // 参考 Retrofit 的动态代理  
    public <T> T create(final Class<T> service) {        
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service},                
            new InvocationHandler() {                    
            @Override                    
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                        
                //解析这个method 上所有的注解信息                        
                ServiceMethod serviceMethod = loadServiceMethod(method);                        
                //args:                        
                return serviceMethod.invoke(args);                    
            }                
        });    
    }  
      
    private ServiceMethod loadServiceMethod(Method method) {        
        //先不上锁,避免synchronized的性能损失        
        ServiceMethod result = serviceMethodCache.get(method);        
        if (result != null) 
            return result;        
        //多线程下,避免重复解析,        
        synchronized (serviceMethodCache) {            
            result = serviceMethodCache.get(method);            
            if (result == null) {                
                result = new ServiceMethod.Builder(this, method).build();                
                serviceMethodCache.put(method, result);            
            }        
        }        
        return result;    
    }
    
    /**     
      * 构建者模式,将一个复杂对象的构建和它的表示分离,可以使使用者不必知道内部组成的细节。     
      */    
    public static final class Builder {        
        private HttpUrl baseUrl;        
        //Okhttp->OkhttClient        
        private okhttp3.Call.Factory callFactory;  
        //null        
        public Builder callFactory(okhttp3.Call.Factory factory) {            
            this.callFactory = factory;            
            return this;        
        }        
        
        public Builder baseUrl(String baseUrl) {            
            this.baseUrl = HttpUrl.get(baseUrl);            
            return this;        
        }        
        
        public MyRetrofit build() {            
            if (baseUrl == null) {                
                throw new IllegalStateException("Base URL required.");            
            }            
            okhttp3.Call.Factory callFactory = this.callFactory;            
            if (callFactory == null) {                
                callFactory = new OkHttpClient();            
            }            
            return new EnjoyRetrofit(callFactory, baseUrl);        
        }    
    }
}

ServiceMethod

用来解析注解,记录请求类型,参数、完整地址

public class ServiceMethod {    
    private final Call.Factory callFactory;    
    private final String relativeUrl;    
    private final boolean hasBody;    
    private final ParameterHandler[] parameterHandler;    
    private FormBody.Builder formBuild;    
    HttpUrl baseUrl;    
    String httpMethod;    
    HttpUrl.Builder urlBuilder;    
    public ServiceMethod(Builder builder) {        
        baseUrl = builder.enjoyRetrofit.baseUrl;        
        callFactory = builder.enjoyRetrofit.callFactory;        
        httpMethod = builder.httpMethod;        
        relativeUrl = builder.relativeUrl;        
        hasBody = builder.hasBody;        
        parameterHandler = builder.parameterHandler;        
        //如果是有请求体,创建一个okhttp的请求体对象        
        if (hasBody) {            
            formBuild = new FormBody.Builder();        
        }    
    }    

    public Object invoke(Object[] args) {        
        /**         
          * 1  处理请求的地址与参数         
          */        
        for (int i = 0; i < parameterHandler.length; i++) {            
            ParameterHandler handlers = parameterHandler[i];            
            // handler内本来就记录了key,现在给到对应的value            
            handlers.apply(this, args[i].toString());        
        }        
        //获取最终请求地址        
        HttpUrl url;        
        if (urlBuilder == null) {            
            urlBuilder = baseUrl.newBuilder(relativeUrl);        
        }        
        url = urlBuilder.build();        
        //请求体        
        FormBody formBody = null;        
        if (formBuild != null) {            
            formBody = formBuild.build();        
        }        
        Request request = new Request.Builder().url(url).method(httpMethod, formBody).build();        
        return callFactory.newCall(request);    
    }    
    
    // get请求,把 k-v 拼到 url 里面    
    public void addQueryParameter(String key, String value) {        
        if (urlBuilder == null) {            
            urlBuilder = baseUrl.newBuilder(relativeUrl);        
        }        
        urlBuilder.addQueryParameter(key, value);    
    }    

    // Post,把 k-v 放到 请求体中    
    public void addFiledParameter(String key, String value) {        
        formBuild.add(key, value);    
    }    

    public static class Builder {        
        private final MyRetrofit enjoyRetrofit;        
        private final Annotation[] methodAnnotations;        
        private final Annotation[][] parameterAnnotations;        
        ParameterHandler[] parameterHandler;        
        private String httpMethod;        
        private String relativeUrl;        
        private boolean hasBody;        
        
        public Builder(MyRetrofit enjoyRetrofit, Method method) {            
            this.enjoyRetrofit = enjoyRetrofit;            
            //获取方法上的所有的注解            
            methodAnnotations = method.getAnnotations();            
            //获得方法参数的所有的注解 (一个参数可以有多个注解,一个方法又会有多个参数)            
            parameterAnnotations = method.getParameterAnnotations();        
        }        

        public ServiceMethod build() {            
            /**             
              * 1 解析方法上的注解, 只处理POST与GET             
              */            
            for (Annotation methodAnnotation : methodAnnotations) {                
                if (methodAnnotation instanceof POST) {                    
                    //记录当前请求方式                    
                    this.httpMethod = "POST";                    
                    //记录请求url的path                    
                    this.relativeUrl = ((POST) methodAnnotation).value();
                    // 是否有请求体                    
                    this.hasBody = true;                
                } else if (methodAnnotation instanceof GET) {                    
                    this.httpMethod = "GET";                    
                    this.relativeUrl = ((GET) methodAnnotation).value();                    
                    this.hasBody = false;                
                }
                // 待处理其他注解            
            }            
            /**             
              * 2 解析方法参数的注解             
              */            
            int length = parameterAnnotations.length;            
            parameterHandler = new ParameterHandler[length];            
            for (int i = 0; i < length; i++) {                
                // 一个参数上的所有的注解                
                Annotation[] annotations = parameterAnnotations[i];                
                // 处理参数上的每一个注解                
                for (Annotation annotation : annotations) {                    
                    //todo 可以加一个判断:如果httpMethod是get请求,现在又解析到 Filed 注解,可以提示使用者使用 Query 注解                    
                    if (annotation instanceof Field) {                        
                        //得到注解上的value: 请求参数的key                        
                        String value = ((Field) annotation).value();                        
                        parameterHandler[i] = new ParameterHandler.FiledParameterHandler(value);                    
                    } else if (annotation instanceof Query) {                        
                        String value = ((Query) annotation).value();                        
                        parameterHandler[i] = new ParameterHandler.QueryParameterHandler(value);                    
                    }                
                }            
            }            
            return new ServiceMethod(this);        
        }    
    }
}

ParameterHandler

QUERY、FIELD 请求参数封装,桥接到 HttpUrl 的addQueryParameter formBuild.add 

public abstract class ParameterHandler {    
    abstract void apply(ServiceMethod serviceMethod, String value);    
    static class QueryParameterHandler extends ParameterHandler {        
        String key;        
        public QueryParameterHandler(String key) {            
            this.key = key;        
        }        
        //serviceMethod: 回调        
        @Override        
        void apply(ServiceMethod serviceMethod, String value) {            
            serviceMethod.addQueryParameter(key,value);        
        }    
    }  
      
    static class FiledParameterHandler extends ParameterHandler {        
        String key;        
        public FiledParameterHandler(String key) {            
            this.key = key;        
        }        
        @Override        
        void apply(ServiceMethod serviceMethod, String value) {            
            serviceMethod.addFiledParameter(key,value);        
        }    
     }
}

简历润色

简历中可写上:深度理解 Retofit 实现原理,理解 注解、反射、动态代理,可手写 Retofit 核心实现

下一章预告

带你玩转多线程;

欢迎三连

来都来了,点个关注、点个赞吧~~

Retrofit框架分析(二):注解、反射以及动态代理,Retrofit框架动态代理的源码分析 Retrofit框架分析(二):反射、泛型以及动态代理,手写Retrofit框架注解是什么,为什么出现反射是什么,为什么出现2.1. 使用反射实现ButterKnife的一个小功能:为TextView赋值动态代理,和Retrofit有什么关系?Retrofit框架动态代理的源码分析。 阅读详情

相关推荐

Android 网络框架之Retrofit源码解析,2021年阿里+腾讯+快手offer都已拿到

基础请求URL: public class BaseRequest { public static final String BaseURL = “https://fanyi.youdao.com/”; } Retrofit的使用: // Retrofit 实例的创建 Retrofit retrofit = new Retrofit.Builder() .baseUrl(BaseRequest.BaseURL) .addConverterFactory(GsonConverterFactory.create

m0_64603776的博客 771

Retrofit中的动态代理

retrofit中的动态代理

qq_36356379的博客 2548

注解&反射(三)【实战--Android View IOC框架的两种实现方案】

控制反转(Inversion of Control,英文缩写为IoC),把创建对象的权利交给框架,是框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。 说完概念定义,IOC好像就是把new 对象的权利交由框架去实现,这样Java代码中就不必要那么多的new操作了。仅此而已吗?NO、NO、NO,Android中我们经常会使用BindView框架,为什么使用它呢?因为它让我们省去了很多findVi.

itbird的专栏 2299

动态代理以及Retrofit的原理

Retrofit:Retrofit是一个RESTful的HTTP网络请求的封装,网络请求的工作本质是OkHttp完成的。代理模式就是通过引入代理对象去帮助真实对象完成一些事情,防止直接访问目标对象给系统带来不必要的复杂性。原理:jdk实现的动态代理只能代理接口,对接口进行了一下拷贝,生成出来的代理对象会实现对应的接口,把代理模式写死,真实对象和被代理对象都要实现固定的接口才能实现代理模式。通过接收方法上的注解来区别实现的什么请求方法,然后识别请求参数的注解来区别。缺点:每个代理只能为一个代理来服务,

池鱼 923

国产平替NeuroSky?实测金牛座TGAM脑电模块,从Arduino到Python的完整数据采集指南

本文详细介绍了国产金牛座TGAM脑电模块的完整使用流程,包括硬件连接、数据采集和Python分析。通过Arduino和Python的实战案例,展示了如何从脑电波传感器获取并解析专注度、放松度等数据,适用于专注力训练和脑机接口开发。

weixin_30735745的博客 576

Oasys安装教程

在基环境下执行然后去 C:\Users.condarc打开 .condarc这个文件 删除干净里面的东西。

weixin_44254178的博客 1297

如何应对Android面试官->Java中的注解、反射、手写ButterKnife核心实现

Target(ElementType.TYPE) // 声明注解作用域@Retention(RetentionPolicy.CLASS) // 声明注解的生命周期 存在时间// 可以定义默认值@interface 关键字来声明一个注解;使用 @BindPath 作用在类上面的时候,需要指定 value 的值, key 的值可以不用指定,因为有默认值;// 当使用 value 关键字的时候,可以不用指定value作为 key 来赋值。

IT_Android的博客 1158

MCP详解:手把手教你理解和如何使用各种开源MCP服务

MCP 作为一种开放协议,为 AI 模型与外部世界的连接提供了标准化的解决方案。它不仅降低了开发门槛,还极大地扩展了 AI 应用的边界。无论是开发者还是普通用户,都可以通过 MCP 更高效地利用 AI 技术,实现更多智能化的功能。

王哥儿聊AI的博客 6057

制作自己的 @OnClick、@OnLongClick(告别 setOnClickListener,使用注解、反射和动态代理)

本文利用注解和反射的巧妙结合,在运行时进行事件和 View 的绑定,实现一个运行时的事件绑定注解框架。以 @OnClick 和 @OnLongClick 为例,读者跟着文章一步步将实现自己的运行时的事件绑定注解。

李斯维的博客空间 1251

【推荐系统】推荐算法:冷启动-召回-粗排-精排-重排 解读

【推荐系统】推荐算法:冷启动-召回-粗排-精排-重排 解读

Danger的博客 3761

ardupilot开发 --- mavlink签名加密 篇

ardupilot开发 --- mavlink签名加密

记录老板的每次pua,分享领导每天的毒鸡汤... 1237

Android注解及反射实战--手写ButterKnife

Android注解及反射实战–手写ButterKnife Android进阶系列 知识点总结,整理也是学习的过程,如有错误,欢迎批评指出。 本文内容涉及到注解,反射,动态代理等知识点,对这部分不太熟悉的可以看看以下文章 Java反射以及在Android中的使用 代理模式以及在Android中的使用 Java注解基础介绍及使用 一、前言 本篇内容主要是对前面注解,反射及动态代理知识点的实战,...

Evan的博客 402

KVM — 与 QEMU 和 Libvirt 的关系

目录目录 前言 KVM QEMU KVM 与 QEMU qemu-kvm Libvirt Libvirt 在 OpenStack 中的应用前言如果是刚开始接触虚拟机技术的话, 对上述的概念肯定会有所混淆, 傻傻的分不清. 尤其在看虚拟化技术文档时导致理解能力下降, 所以在开始学习虚拟化技术之前对这些概念有一个整体的认识和清晰的理解, 就显得很有必要了.KVMKVM(Kernel-basedVirtu

烟云的计算 5739

用注解、反射、动态代理实现ButterKnife功能

ButterKnife的实现需要先熟悉注解、反射、动态代理,不熟悉的小伙伴可以去看这三篇文章: Java注解 Java反射 动态代理 下面我们就来看一下ButterKnife的实现: ButterKnife相信大家都会用,它能通过注解帮我们绑定布局文件中的控件,能通过注解帮我们设置view的click事件 今天我们除了实现这两个功能还要实现通过注解代替setContentView(R.layout.xxx)功能 1.通过注解实现setContentView功能 思路:定义一个MyConten

Allence的博客 2392

PCL 均匀采样【2026最新版】

根据输入点云数据创建一个微小的三维立方体集合,然后计算每个三维立方体的重心;由于该重心点不一定是原始点云中的点,直接用该点来表示立方体内所有的点会丢失原始点云的细小特征;所以使用k最近邻搜索寻找距离重心点最近的原始点来代替重心点。

点云侠的博客 41万+

UG NX二次开发(C#)-外部模式-批量删除某些图层中的体对象和曲线对象

在 UG NX中,有时需要批量删除某文件夹下多个.prt文件中固定一些图层中的体对象和曲线对象,这时如果采用手动逐个打开模型,并选择针对的图层删除,即耗时也容易遗漏,因此采用外部模式来处理比较方便。本文介绍批量删除某些图层中的体对象和曲线对象。

GimiGimmy 3035

注解+反射+动态代理实现View点击事件绑定

一、一些感想 其实在工作的过程中,我一直感觉自己的java基础还是很薄弱的,所以不得不重新看看java基础,其实注解在Android应用实在很广泛,它让代码简介,并且解耦,提高了很多开发效率。为了巩固对基础知识的理解,所以干脆使用注解+反射+动态代理实现View的点击事件绑定功能,加深印象。在整个实现过程中要求的知识点还是比较多,首先要熟悉Android View点击事件,当然如果对注解不了解,那...

zhuhuitao 661

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

使用注解、APT和反射+动态代理在Android中实现语法检查、视图绑定和事件注入

首先,我们定义一个自定义注解@NonEmpty,用于标记不允许为空的字段。接下来,我们实现一个自定义Lint规则,检查标记为@NonEmpty的字段是否为空。首先,创建一个类来定义Lint规则。创建文件// 检查字段是否为空的逻辑 return false;// 这里可以加入具体的逻辑,比如检查字段是否为null或空字符串 } }// 检查字段是否为空的逻辑 return false;

weixin_37600397的博客 1182

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

1.2 注解反射与动态代理

目录1.2 注解反射与动态代理1.2.1 反射1.获取class 对象 3种 方式(1)对象**.**getClass() 方法(2)类**.**class 语法(3)Class**.**forName()2.class 对象的方法3. 类的实例化4.Constructor5.Field 成员变量的介绍6.Method反射(1)获取成员方法的函数(2)调用成员方法(3)无参数成员方法调用(4)有一个参数的成员方法调用(5)有多个参数的成员方法调用(6)关于内部类的调用(7)关于成员变量的调用(8).invo

朝花夕拾 1397

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

利用反射、注解、动态代理实现,onClick的注入

@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface OnClick { int[] value(); } @OnClick({R.id.tv1,R.id.tv2}) public void onClick(View view){ switch (view.getId()) { case R.id.tv1 : ...

kaikai510的博客 581

【13】注解反射动态代理实现控件事件注入

(1)一个人只要自己不放弃自己,整个世界也不会放弃你. (2)天生我才必有大用 (3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟. (4)做难事必有所得 (5)精神乃真正的刀锋 (6)战胜对手有两次,第一次在内心中. (7)好好活就是做有意义的事情. (8)亡羊补牢,为时未晚 (9)科技领域,没有捷径与投机取巧。 (10)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~ 注解反射动态代理实现控件事件注入 文章目录注解反射动态代理实现控件事件注入1.实现思路2.定义事件类型.

青风百草 466

动态代理+注解+反射实现View的点击事件绑定

个人博客 http://www.milovetingting.cn 动态代理+注解+反射实现View的点击事件绑定 代理模式是给对象提供一个代理对象,由代理对象来控制原对象的引用。代理模式分为静态代理和动态代理。 静态代理 定义接口 public interface Player { void play(); } 定义具体的实现类 public class PlayerImpl ...

milovetingting的专栏 460

Java反射,注解,以及动态代理

Java反射,注解,以及动态代理 基础 最近在准备实习面试,被学长问到了Java反射,注解和动态代理的内容,发现有点自己有点懵,这几天查了很多资料,就来说下自己的理解吧【如有错误,望指正】 Java反射 首先,我们得弄清一个,什么是反射(Reflection)。简单的来说,反射就是让我们在程序运行的时候能够查看到类的信息,获取并调用类的任意方法和属性。 在Java...

weixin_30449453的博客 218

注解反射&动态代理的封装

注解反射&动态代理的封装1、自定义注解&动态代理的简单实现2、代理优化封装 1、自定义注解&动态代理的简单实现 需求场景: 通过自定义注解方式,实现按钮的点击效果,和长按效果 我们先写两个按钮 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://sc

半身风雪 388

安卓反射和动态代理浅析

提纲 java反射基础 反射在Android中的应用 Java动态代理 动态代理在Android的应用 java反射基础 相关定义和简单调用 java反射官方说明链接 Java允许程序在运行时透过Reflection APIs加载一个运行时才得知名称的class,获得其完整结构,包括其modifiers(诸如public, static 等)、superclass(例如Obje...

WHHGARSKY的博客 760

Java进阶之注解和反射及动态代理

前言 一、 二、

qq_33613491的博客 471
上一篇: 如何应对Android面试官->Java中的注解、反射、手写ButterKnife核心实现
下一篇: 如何应对Android面试官->线程与进程、手写ThreadLocal
老A说
博客等级 码龄14年 1181粉丝 85原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值