Java OkHttp框架源码深入解析

目录
  • 1.OkHttp发起网络请求
    • 可以通过OkHttpClient发起一个网络请求
    • 通过Retrofit发起一个OkHttp请求
  • 2.OkHttp的连接器

1.OkHttp发起网络请求

可以通过OkHttpClient发起一个网络请求

//创建一个Client,相当于打开一个浏览器
 OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
 //创建一个请求。
        Request request = new Request.Builder()
                .url("http://www.baidu.com")
                .method("GET",null)
                .build();
    //调用Client 创建一个Call。
        Call call = okHttpClient.newCall(request);
        //Call传入一个回调函数,并加入到请求队列。
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });
}

通过Retrofit发起一个OkHttp请求

 Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://www.baidu.com/")
                .build();
        NetInterface netInterface = retrofit.create(NetInterface.class);
        Call<Person> call = netInterface.getPerson();
        call.enqueue(new Callback<Person>() {
            @Override
            public void onResponse(Call<Person> call, Response<Person> response) {
            }
            @Override
            public void onFailure(Call<Person> call, Throwable t) {
            }
 });

以上两种方式都是通过call.enqueue() 把网络请求加入到请求队列的。

这个call是RealCall的一个对象。

 public void enqueue(Callback responseCallback) {
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

这里有两个判断条件

runningAsyncCalls.size() < maxRequests如果运行队列数量大于最大数量,

runningCallsForHost(call) < maxRequestsPerHost并且访问同一台服务器的请求数量大于最大数量,请求会放入等待队列,否则加入运行队列,直接执行。

//等待队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//运行队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//运行队列数量最大值
private int maxRequests = 64;
//访问不同主机的最大数量
private int maxRequestsPerHost = 5;
dispatcher.java
 synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

接下来看这行代码executorService().execute(call);

executorService()拿到一个线程池实例,

  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;

execute(call)执行任务,发起网络请求。

 //AsyncCall.java
 @Override protected void execute() {
       try {
       //这个方法去请求网络,会返回Respose
        Response response = getResponseWithInterceptorChain();
        //请求成功,回调接口
         responseCallback.onResponse(RealCall.this, response);
       }catch(Exceptrion e){
            //失败回调
         responseCallback.onFailure(RealCall.this, e);
       }finally {
          //从当前运行队列中删除这个请求
          client.dispatcher().finished(this);
      }
 }

getResponseWithInterceptorChain()

这行代码,使用了设计模式中的责任链模式。

 //这个方法命名:通过拦截器链,获取Response
  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
     // 这个我们自己定义的拦截器。
    interceptors.addAll(client.interceptors());
    //重试和重定向拦截器
    interceptors.add(retryAndFollowUpInterceptor);
    //请求头拦截器
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //缓存拦截器
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //连接拦截器
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    //访问拦截器
    interceptors.add(new CallServerInterceptor(forWebSocket));
    //拦截器责任链
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
    //执行拦截器集合中的拦截器
    return chain.proceed(originalRequest);
  }

责任链模式中,链条的上游持有下游对象的引用。这样能够保证在链条上的每一个对象,都能对其符合条件的任务进行处理。

但是在上面的拦截器构成责任链中,是把拦截器,放在了一个集合中。

第一个参数interceptors 是一个拦截器的集合。

第五个参数0是集合的index,RealInterceptorChain就是根据这个索引值+1,

对chain.proceed方法循环调用,进行集合遍历,并执行拦截器中定义的方法的。

这个责任链模式,并没有明确的指定下游对象是什么,而是通过集合index值的变化,动态的指定的。

 Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0......)
   chain.proceed(originalRequest);
   public Response proceed(Request request,...){
    //构建一个index+1的拦截器链
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
                connection, index + 1,....);
        //拿到当前的拦截器
        Interceptor interceptor = interceptors.get(index);
        //调用拦截器intercept(next)方法,
        //在这个方法中继续调用realChain.proceed(),从而进行循环调用,index索引值再加1.
        Response response = interceptor.intercept(next);
 }

2.OkHttp的连接器

1)RetryAndFollowUpInterceptor:重试和重定向拦截器

public Response intercept(Chain chain){
      while (true) {
        Response response;
          try {
          //创建StreamAllocation对象,这个对象会在连接拦截器中用到
            StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
                  createAddress(request.url()), call, eventListener, callStackTrace);
              this.streamAllocation = streamAllocation;
             调用责任链下游拦截器
             response = realChain.proceed(request, streamAllocation, null, null);
            } catch (RouteException e) {
                 // The attempt to connect via a route failed. The request will not have been sent.
                 路由异常,请求还没发出去。
                 这样这个recover(),如果返回的是false,则抛出异常,不再重试
                 如果返回的是true,则执行下面的continue,进行下一次while循环,进行重试,重新发起网络请求。
                 if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
                   throw e.getFirstConnectException();
                 }
                 releaseConnection = false;
                continue;
             } catch (IOException e) {
                 // An attempt to communicate with a server failed. The request may have been sent.
                 请求已经发出去了,但是和服务器连接失败了。
                 这个recover()返回值的处理逻辑和上面异常一样。
                 boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
                 if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
                 releaseConnection = false;
                 continue;
               }
             } finally {//finally是必定会执行到的,不管上面的catch中执行的是continue还是thow
                // We're throwing an unchecked exception. Release any resources.
                if (releaseConnection) {
                  streamAllocation.streamFailed(null);
                  streamAllocation.release();
                }
              }
             在这个重试拦截器中,okhttp的做法很巧妙。先是在外面有一个while循环,如果发生异常,
             会在recover方法中对异常类型进行判断,如果不符合属于重试,则返回false,并thow e,结束while循环。
             如果符合重试的条件,则返回true,在上面的catch代码块中执行continue方法,进入下一个while循环。
            //如果请求正常,并且返回了response,则会进行重定向的逻辑判断
            followUpRequest在这个方法中会根据ResponseCode,状态码进行重定向的判断,
            Request followUp;
                 try {
                   followUp = followUpRequest(response, streamAllocation.route());
                 } catch (IOException e) {
                   streamAllocation.release();
                   throw e;
                 }
                 如果flolowUp 为null,则不需要重定向,直接返回response
                 if (followUp == null) {
                   if (!forWebSocket) {
                     streamAllocation.release();
                   }
                   return response;
                 }
                  如果flolowUp 不为null,则进行重定向了请求
               如果重定向次数超过MAX_FOLLOW_UPS=20次,则抛出异常,结束while循环
              if (++followUpCount > MAX_FOLLOW_UPS) {
                     streamAllocation.release();
                     throw new ProtocolException("Too many follow-up requests: " + followUpCount);
                   }
                   if (followUp.body() instanceof UnrepeatableRequestBody) {
                     streamAllocation.release();
                     throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
                   }
                   if (!sameConnection(response, followUp.url())) {
                     streamAllocation.release();
                     //从重定向请求中拿到url,封装一个新的streamAllocation对象,
                     streamAllocation = new StreamAllocation(client.connectionPool(),
                         createAddress(followUp.url()), call, eventListener, callStackTrace);
                     this.streamAllocation = streamAllocation;
                   } else if (streamAllocation.codec() != null) {
                     throw new IllegalStateException("Closing the body of " + response
                         + " didn't close its backing stream. Bad interceptor?");
                   }
                   //将重定向请求赋值给request 进入下一个重定向的请求的while循环,继续走上面的while循环代码
                   request = followUp;
                   priorResponse = response;
                 }
 }
   //只有这个方法返回值为false都不进行重试。
   private boolean recover(IOException e, StreamAllocation streamAllocation,
       boolean requestSendStarted, Request userRequest) {
     streamAllocation.streamFailed(e);
     // The application layer has forbidden retries.
     应用层禁止重试。可以通过OkHttpClient进行配置(默认是允许的)
     if (!client.retryOnConnectionFailure()) return false;
     // We can't send the request body again.
     if (requestSendStarted && userRequest.body() instanceof UnrepeatableRequestBody) return false;
     // This exception is fatal. 致命的异常
     判断是否属于重试的异常
     if (!isRecoverable(e, requestSendStarted)) return false;
     // No more routes to attempt.
     没有更多可以连接的路由线路
     if (!streamAllocation.hasMoreRoutes()) return false;
     // For failure recovery, use the same route selector with a new connection.
     return true;
   }
  只有这个方法返回false,都不进行重试。
 private boolean isRecoverable(IOException e, boolean requestSendStarted) {
   // If there was a protocol problem, don't recover.
   出现了协议异常,不再重试
   if (e instanceof ProtocolException) {
     return false;
   }
   // If there was an interruption don't recover, but if there was a timeout connecting to a route
   // we should try the next route (if there is one).
   requestSendStarted为false时,并且异常类型为Scoket超时异常,将会进行下一次重试
   if (e instanceof InterruptedIOException) {
     return e instanceof SocketTimeoutException && !requestSendStarted;
   }
   // Look for known client-side or negotiation errors that are unlikely to be fixed by trying
   // again with a different route.
   如果是一个握手异常,并且证书出现问题,则不能重试
   if (e instanceof SSLHandshakeException) {
     // If the problem was a CertificateException from the X509TrustManager,
     // do not retry.
     if (e.getCause() instanceof CertificateException) {
       return false;
     }
   }

2)BridgeInterceptor 桥拦截器:连接服务器的桥梁,主要是在请求头中设置一些参数配置

如:请求内容长度,编码,gzip压缩等。

public Response intercept(Chain chain) throws IOException {
     Request userRequest = chain.request();
     Request.Builder requestBuilder = userRequest.newBuilder();
     RequestBody body = userRequest.body();
    if (body != null) {
      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }
      ..................
    }
    在请求头中添加gizp,是否压缩
  boolean transparentGzip = false;
     if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
       transparentGzip = true;
       requestBuilder.header("Accept-Encoding", "gzip");
     }
    //cookies
     List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
     if (!cookies.isEmpty()) {
       requestBuilder.header("Cookie", cookieHeader(cookies));
     }
     调用责任链中下一个拦截器的方法,网络请求得到的数据封装到networkResponse中
     Response networkResponse = chain.proceed(requestBuilder.build());
    对cookie进行处理
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
    如果设置了gzip,则会对networkResponse进行解压缩。
     if (transparentGzip
            && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
            && HttpHeaders.hasBody(networkResponse)) {
          GzipSource responseBody = new GzipSource(networkResponse.body().source());
          Headers strippedHeaders = networkResponse.headers().newBuilder()
              .removeAll("Content-Encoding")
              .removeAll("Content-Length")
              .build();
          responseBuilder.headers(strippedHeaders);
          String contentType = networkResponse.header("Content-Type");
          responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
        }
    return responseBuilder.build();
}

3)CacheInterceptor缓存拦截器

public Response intercept(Chain chain){
   //  this.cache = DiskLruCache.create(fileSystem, directory, 201105, 2, maxSize);
    这个缓存在底层使用的是DiskLruCache
    //以request为key从缓存中拿到response。
     Response cacheCandidate = cache != null
            ? cache.get(chain.request()): null;
     long now = System.currentTimeMillis();
     //缓存策略
     CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
     Request networkRequest = strategy.networkRequest;
     Response cacheResponse = strategy.cacheResponse;
   // If we're forbidden from using the network and the cache is insufficient, fail.
   //如果请求和响应都为null,直接返回504
   if (networkRequest == null && cacheResponse == null) {
     return new Response.Builder()
         .request(chain.request())
         .protocol(Protocol.HTTP_1_1)
         .code(504)
         .message("Unsatisfiable Request (only-if-cached)")
         .body(Util.EMPTY_RESPONSE)
         .sentRequestAtMillis(-1L)
         .receivedResponseAtMillis(System.currentTimeMillis())
         .build();
   }
   // If we don't need the network, we're done.
   //如果请求为null,缓存不为null,则直接使用缓存。
       if (networkRequest == null) {
         return cacheResponse.newBuilder()
             .cacheResponse(stripBody(cacheResponse))
             .build();
       }
     Response networkResponse = null;
        try {
          //调用责任链下一个拦截器
          networkResponse = chain.proceed(networkRequest);
        } finally {
        }
      Response response = networkResponse.newBuilder()
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
     // Offer this request to the cache.
     //将响应存入缓存。
      CacheRequest cacheRequest = cache.put(response);
}

4)ConnectInterceptor 连接拦截器。当一个请求发出,需要建立连接,然后再通过流进行读写。

public Response intercept(Chain chain) throws IOException {
     RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    //在重定向拦截器中创建,
    StreamAllocation streamAllocation = realChain.streamAllocation();
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    //从连接池中,找到一个可以复用的连接,
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
   // RealConnection 中封装了一个Socket和一个Socket连接池
    RealConnection connection = streamAllocation.connection();
    //调用下一个拦截器
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
//遍历连接池
RealConnection get(Address address, StreamAllocation streamAllocation, Route route) {
    assert (Thread.holdsLock(this));
    for (RealConnection connection : connections) {
      if (connection.isEligible(address, route)) {
        streamAllocation.acquire(connection, true);
        return connection;
      }
    }
    return null;
  }
  public boolean isEligible(Address address, @Nullable Route route) {
    // If this connection is not accepting new streams, we're done.
    if (allocations.size() >= allocationLimit || noNewStreams) return false;
    // If the non-host fields of the address don't overlap, we're done.
    if (!Internal.instance.equalsNonHost(this.route.address(), address)) return false;
    // If the host exactly matches, we're done: this connection can carry the address.
    从连接池中找到一个连接参数一致且并未占用的连接
    if (address.url().host().equals(this.route().address().url().host())) {
      return true; // This connection is a perfect match.
  }

5)CallServerInterceptor 请求服务器拦截器

/** This is the last interceptor in the chain. It makes a network call to the server. */
这是责任链中最后一个拦截器,这个会去请求服务器。
 public Response intercept(Chain chain) throws IOException {
      RealInterceptorChain realChain = (RealInterceptorChain) chain;
      HttpCodec httpCodec = realChain.httpStream();
      StreamAllocation streamAllocation = realChain.streamAllocation();
      RealConnection connection = (RealConnection) realChain.connection();
      Request request = realChain.request();
      //将请求头写入缓存
      httpCodec.writeRequestHeaders(request);
      return response;

到此这篇关于Java OkHttp框架源码深入解析的文章就介绍到这了,更多相关Java OkHttp框架内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Java中的OkHttp JSONP爬虫

    目录 什么是JSOUP 什么是OkHttp 爬虫需要掌握的技术 需要的依赖 JSON入门Demo JSOUP常用方法 使用JSOUP 方式连接 User-Agent(随机) 后台爬虫的三大问题 selenium+phantomjs(维护中…内容重新整理) 什么是JSOUP JSOUP 是一款Java 的HTML解析器,可直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据. 官网 jsoup实现了WHATWG

  • Java中的OkHttp使用教程

    目录 什么是OKHttp OkHttp基本使用 添加依赖 OkHttp工具类 使用案例 发送get请求 发送Post请求 发送异步请求 什么是OKHttp 一般在Java平台上,我们会使用Apache HttpClient作为Http客户端,用于发送 HTTP 请求,并对响应进行处理.比如可以使用http客户端与第三方服务(如SSO服务)进行集成,当然还可以爬取网上的数据等.OKHttp与HttpClient类似,也是一个Http客户端,提供了对 HTTP/2 和 SPDY 的支持,并提供了连接

  • java 中OkHttp的使用方法及实例

    java  中OkHttp的使用方法及实例 概述 准备研究Retrofit,而它是依赖OkHttp的,所以先使用一下OkHttp,不深究源码,只探究使用方法.以后有机会再翻查源码. 在进行之前,首先需要2个jar包,其中一个是okHttp的jar包,github上可以下载,另一个是它的依赖包,这个很关键,没有它,项目就无法运行. OkHttp请求的2种方式 不难猜测,涉及到网络请求,那么无非2种方式,一种是使用回调,另一种则是开启子线程执行. 第一种:开启子线程执行 OkHttpClient c

  • SpringBoot Java后端实现okhttp3超时设置的方法实例

    目录 前言 导入 okhttp3方法简介 两种版本超时设置用法 总结 前言 okhttp是一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司开发.OkHttp 是一个默认高效的 HTTP 客户端.OkHttp3是Java和Android都能用,Android还有一个著名网络库叫Volley,那个只有Android能用. okttp3的github官方地址是:官方地址 HTTP/2 支持允许对同一主机的所有请求共享一个套接字. 连接池减少了请求延迟(如果 HTTP/

  • Java OkHttp框架源码深入解析

    目录 1.OkHttp发起网络请求 可以通过OkHttpClient发起一个网络请求 通过Retrofit发起一个OkHttp请求 2.OkHttp的连接器 1.OkHttp发起网络请求 可以通过OkHttpClient发起一个网络请求 //创建一个Client,相当于打开一个浏览器 OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); //创建一个请求. Request request = new Request.Bui

  • Java集合框架源码分析之LinkedHashMap详解

    LinkedHashMap简介 LinkedHashMap是HashMap的子类,与HashMap有着同样的存储结构,但它加入了一个双向链表的头结点,将所有put到LinkedHashmap的节点一一串成了一个双向循环链表,因此它保留了节点插入的顺序,可以使节点的输出顺序与输入顺序相同. LinkedHashMap可以用来实现LRU算法(这会在下面的源码中进行分析). LinkedHashMap同样是非线程安全的,只在单线程环境下使用. LinkedHashMap源码剖析 LinkedHashM

  • Android音视频开发Media FrameWork框架源码解析

    目录 一.Media FrameWork背景 二.Media Framework“路线图” 2.1 代理端 2.2 服务端 2.2.1 Source 2.2.2 Decoder 2.2.3 Renderer 2.2.4 Foundation 2.3 OMX端 2.4 Kernel端 三.media播放的流程 四.Media FrameWork源码分析 一.Media FrameWork背景 Media Framework (媒体函数库):此函数库让Android 可以播放与录制许多常见的音频与视

  • Laravel框架源码解析之模型Model原理与用法解析

    本文实例讲述了Laravel框架源码解析之模型Model原理与用法.分享给大家供大家参考,具体如下: 前言 提前预祝猿人们国庆快乐,吃好.喝好.玩好,我会在电视上看着你们. 根据单一责任开发原则来讲,在laravel的开发过程中每个表都应建立一个model对外服务和调用.类似于这样 namespace App\Models; use Illuminate\Database\Eloquent\Model; class User extends Model { protected $table =

  • Laravel框架源码解析之入口文件原理分析

    本文实例讲述了Laravel框架源码解析之入口文件原理.分享给大家供大家参考,具体如下: 前言 提升能力的方法并非使用更多工具,而是解刨自己所使用的工具.今天我们从Laravel启动的第一步开始讲起. 入口文件 laravel是单入口框架,所有请求必将经过index.php define('LARAVEL_START', microtime(true)); // 获取启动时间 使用composer是现代PHP的标志 require __DIR__.'/../vendor/autoload.php

  • Laravel框架源码解析之反射的使用详解

    本文实例讲述了Laravel框架源码解析之反射的使用.分享给大家供大家参考,具体如下: 前言 PHP的反射类与实例化对象作用相反,实例化是调用封装类中的方法.成员,而反射类则是拆封类中的所有方法.成员变量,并包括私有方法等.就如"解刨"一样,我们可以调用任何关键字修饰的方法.成员.当然在正常业务中是建议不使用,比较反射类已经摒弃了封装的概念. 本章讲解反射类的使用及Laravel对反射的使用. 反射 反射类是PHP内部类,无需加载即可使用,你可以通过实例化 ReflectionClas

  • Java Lambda 表达式源码解析

    Java Lambda 源码分析 问题: Lambda 表达式是什么?JVM 内部究竟是如何实现 Lambda 表达式的?为什么要这样实现? 一.基本概念 1.Lambda 表达式 下面的例子中,() -> System.out.println("1") 就是一个 Lambda 表达式.Java 8 中每一个 Lambda 表达式必须有一个函数式接口与之对应.Lambda 表达式就是函数式接口的一个实现. @Test public void test0() { Runnable

  • java中CopyOnWriteArrayList源码解析

    目录 简介 继承体系 源码解析 属性 构造方法 add(Ee)方法 add(intindex,Eelement)方法 addIfAbsent(Ee)方法 get(intindex) remove(intindex)方法 size()方法 提问 总结 简介 CopyOnWriteArrayList是ArrayList的线程安全版本,内部也是通过数组实现,每次对数组的修改都完全拷贝一份新的数组来修改,修改完了再替换掉老数组,这样保证了只阻塞写操作,不阻塞读操作,实现读写分离. 继承体系 public

  • Java CountDownLatch的源码硬核解析

    目录 前言 介绍和使用 例子 概述 实现思路 源码解析 类结构图 await() 实现原理 countDown()实现原理 前言 对于并发执行,Java中的CountDownLatch是一个重要的类,简单理解, CountDownLatch中count down是倒数的意思,latch则是“门闩”的含义.在数量倒数到0的时候,打开“门闩”, 一起走,否则都等待在“门闩”的地方. 为了更好的理解CountDownLatch这个类,本文通过例子和源码带领大家深入解析这个类的原理. 介绍和使用 例子

  • Java HashTable与Collections.synchronizedMap源码深入解析

    目录 一.类继承关系图 二.HashTable介绍 三.HashTable和HashMap的对比 1.线程安全 2.插入null 3.容量 4.Hash映射 5.扩容机制 6.结构区别 四.Collections.synchronizedMap解析 1.Collections.synchronizedMap是怎么实现线程安全的 2.SynchronizedMap源码 一.类继承关系图 二.HashTable介绍 HashTable的操作几乎和HashMap一致,主要的区别在于HashTable为

随机推荐