最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java Retrofit源碼層深入分析

 更新時間:2023年01月13日 09:28:51   作者:AllenC6  
這篇文章主要介紹了Java Retrofit源碼層分析,Retrofit是一個RESTful的HTTP網(wǎng)絡(luò)請求框架的封裝,網(wǎng)絡(luò)請求的工作本質(zhì)上是OkHttp完成,而Retrofit僅負(fù)責(zé)網(wǎng)絡(luò)請求接口的封裝

提醒:看的過程一定要自己點開源碼,跟著一步步走,只看容易懵逼

一、自己對Retrofit的理解

Retrofit的中文翻譯是改造,改造什么呢?

我認(rèn)為是對OkHttp的使用、RxJava的使用進(jìn)行改造。

具體體現(xiàn)在哪里?

在使用OkHttp請求前:

1.用注解統(tǒng)一配置網(wǎng)絡(luò)請求頭和請求參數(shù)

2.通過動態(tài)代理統(tǒng)一獲取注解的請求頭和請求參數(shù)然后一致組裝適配成請求的request,交給okHttp進(jìn)行請求

使用OkHttp結(jié)果返回后:

1.線程切換

線程切換分為兩種一種是用Retrofit默認(rèn)的,另一種是使用RxJava

2.把返回的數(shù)據(jù)json適配成javabean

簡單總結(jié),Retrofit就是為了讓OkHttp、RxJava使用的更加簡潔的一個封裝

二、Retrofit的簡單使用

沒有添加RxJava

class RetrofitActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //初始化一個Retrofit對象
        val retrofit = Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .client(OkHttpClientProvider.client()) // 這個OkHttpClientProvider.client()是我自己封裝的,就是簡單提供一個OkHttpClient
            .build()
        //創(chuàng)建出GitHubApiService這個GitHubApiService的動態(tài)代理對象service 
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一個Okhttp的請求 Call 對象repos 
        val repos = service.listRepos("octocat")
        //調(diào)用 enqueue 方法在回調(diào)方法里處理結(jié)果
        repos.enqueue(object : Callback<List<Repo>?> {
            override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
                                t.printStackTrace()
            }
            override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) {
                "response.code() = ${response.code()}".logE()
            }
        })
    }
}
//自己定義的 API 請求接口
interface GitHubApiService {
    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String?): Call<List<Repo>>
}

三、請求前Retrofit所做的工作

以統(tǒng)一的方式為網(wǎng)絡(luò)請求準(zhǔn)備各種參數(shù)

(1).Retrofit的創(chuàng)建,把BaseUrl、OkHttpClient和Gson的實例保存在Retrofit對象中

Retrofit.Builder()的build()方法:

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

首先看這個callFactory,因為我們已經(jīng).client(OkHttpClientProvider.client())方法設(shè)置了我們的okhttpclient,所以這里callFactory不為null:

    public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }
    public Builder callFactory(okhttp3.Call.Factory factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }

我們沒有添加CallbackExecutor(這個看名字就知道是用來處理返回值的),所以這里用的是默認(rèn)的:

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}

記住這個CallbackExecutor,后面會用到

接下來重點看:

List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

這個很重要,我們沒有調(diào)用addCallAdapterFactory方法另外添加AdapterFactory,所以這里第一句的this.adapterFactories是一個空集合,之后調(diào)用add方法添加了一個默認(rèn)的platform.defaultCallAdapterFactory(callbackExecutor),這個很重要需要記住。

接下來把我們的Gson解析器添加到了converterFactories中

最后創(chuàng)建了Retrofit對象,把上面的對象都維護(hù)在了Retrofit中,這些都是網(wǎng)絡(luò)請求需要的工具。

(2).用注解來表示請求頭和請求的參數(shù)等

如果不知道注解的本質(zhì)的小伙伴點擊傳送門:

Java 注解

看一下 注解的具體使用:

    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String?): Call<List<Repo>>

這個就是注解提供的請求方式、請求地址、請求參數(shù)等,這個是接口類中的一個方法,后面這個接口類會被動態(tài)代理來代理這個接口。

(3).用動態(tài)代理來把Retrofit和代理接口的方法上的請求信息,組裝成一個OkHttp的請求

如果不知道動態(tài)代理本質(zhì)的小伙伴點擊傳送門:

Java動態(tài)代理與靜態(tài)代理

使用動態(tài)代理,組裝請求的代碼:

        //創(chuàng)建出GitHubApiService這個GitHubApiService的動態(tài)代理對象service 
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一個Okhttp的請求 Call 對象repos 
        val repos = service.listRepos("octocat")

看Retrofit的create方法:

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
......
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

可以看到就是創(chuàng)建了一個動態(tài)代理,動態(tài)代理的作用就是代理類的任何一個方法的調(diào)用,都會走這個動態(tài)代理的invoke方法,即service.listRepos("octocat")的調(diào)用會走這個invoke方法。

下面我們具體分析,動態(tài)代理的invoke方法如何把各種請求的信息,組裝成一個OkHttpCall的:

ServiceMethod<Object, Object> serviceMethod =

(ServiceMethod<Object, Object>) loadServiceMethod(method);

這個ServiceMethod是一個重點,它是真正執(zhí)行把所有的請求信息,拼成一個Okhttp的請求Call的類:

  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    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;
  }

這里有一個緩存,serviceMethodCache是一個ConcurrentHashMap來緩存serviceMethod。

然后是ServiceMethod的創(chuàng)建,主要看build方法:

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
......
      responseConverter = createResponseConverter();
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
......
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
......
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
......
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
......
      return new ServiceMethod<>(this);
    }

可以看出來,這里都在把之前的注解、請求參數(shù)、請求地址等解析出來,存到serviceMethod中:

  ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
  }

這個ServiceMethod大家現(xiàn)在不用細(xì)看它,知道它是解析了我們之前統(tǒng)一用注解格式表示的請求信息,后保存在了自己serviceMethoed的對象中。后面用到的時候,大家自然能體會到。

然后回到動態(tài)代理的invoke方法:

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

這個OkHttpCall就是具體發(fā)出請求的類,它持有serviceMethod,這里我們先不分析它,繼續(xù)往下看:

return serviceMethod.callAdapter.adapt(okHttpCall);

這里就和我們調(diào)用的地方聯(lián)系起來了,這個return的是一個okHttp的call:

        //創(chuàng)建出GitHubApiService這個GitHubApiService的動態(tài)代理對象service 
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一個Okhttp的請求 Call 對象repos ???注意這里變化了
        val repos = serviceMethod.callAdapter.adapt(okHttpCall)

注意上面service.listRepos("octocat")等于動態(tài)代理調(diào)用invoke方法的返回值即:

serviceMethod.callAdapter.adapt(okHttpCall)

那我們重點分析:

serviceMethod.callAdapter.adapt(okHttpCall)

首先這個serviceMethod.callAdapter是什么:

callAdapter是在serviceMethod中的build方法中賦值的:

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
......
    }
    private CallAdapter<T, R> createCallAdapter() {
......
      try {
        //noinspection unchecked
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }
  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }
  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
......
    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
......
  }

上面是整個callAdapter的調(diào)用鏈,最后是:

adapterFactories.get(i).get(returnType, annotations, this);

這句確定的CallAdapter:

adapterFactoris之前我們提到過要記住的,在Retrofit的build方法中:

List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

上面分析了,adapterFactories中只有platform.defaultCallAdapterFactory(callbackExecutor),這一個CallAdapter,adapterFactories.get(i)就是獲取platform.defaultCallAdapterFactory(callbackExecutor)的。

接下來看platform.defaultCallAdapterFactory(callbackExecutor)是什么:

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

所以我們得到結(jié)論,adapterFactories.get(i)是new ExecutorCallAdapterFactory(callbackExecutor)

注意我們要的是adapterFactories.get(i).get(returnType, annotations, this),所以我們要看ExecutorCallAdapterFactory的get方法:

  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }
      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

返回的是:

new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }
      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };

所以:

serviceMethod.callAdapter是adapterFactories.get(i).get(returnType, annotations, this)是上面這段代碼new CallAdapter

那我們要分析的serviceMethod.callAdapter.adapt(okHttpCall),所以我們要的是new CallAdapter的adaptger方法:它返回的是new ExecutorCallbackCall<>(callbackExecutor, call)

這里要注意,這兩個參數(shù):

callbackExecutor是我們上面提到過的處理返回值的:

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}

call是:

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

好現(xiàn)在我們知道了:

        //創(chuàng)建出GitHubApiService這個GitHubApiService的動態(tài)代理對象service 
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一個Okhttp的請求 Call 對象repos ???注意這里變化了
        val repos = serviceMethod.callAdapter.adapt(okHttpCall)

其實是:

        //創(chuàng)建出GitHubApiService這個GitHubApiService的動態(tài)代理對象service 
        val service = retrofit.create(GitHubApiService::class.java)
        //返回一個Okhttp的請求 Call 對象repos ???注意這里變化了
        Call repos = new ExecutorCallbackCall<>(callbackExecutor, call)

到這里我們分析了第三小節(jié)的題目:如何用動態(tài)代理來把Retrofit和代理接口的方法上的請求信息組裝成一個OkHttp的請求

(4).發(fā)起請求的調(diào)用鏈細(xì)節(jié)

我們知道發(fā)起請求的代碼:

        val service = retrofit.create(GitHubApiService::class.java)
        //返回一個Okhttp的請求 Call 對象repos 
        val repos = service.listRepos("octocat")
        //調(diào)用 enqueue 方法在回調(diào)方法里處理結(jié)果
        repos.enqueue(object : Callback<List<Repo>?> {
            override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
                                t.printStackTrace()
            }
            override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) {
                "response.code() = ${response.code()}".logE()
            }
        })

這里的repos已經(jīng)分析了是ExecutorCallbackCall,調(diào)用的enqueue方法,接下來我們來看調(diào)用鏈ExecutorCallbackCall的enqueue方法:

    final Executor callbackExecutor;
    final Call<T> delegate;
    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
 @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }
        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

首先我們已經(jīng)知道構(gòu)造方法的兩個參數(shù)是什么:

delegate 是OkHttpCall

callbackExecutor是platform.defaultCallbackExecutor();

然后我們繼續(xù)看delegate即OkHttpCall的enqueue方法(上面提到的掠過的OkhttpCall這里用到了):

  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");
    okhttp3.Call call;
    Throwable failure;
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          //?? 重點
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }
    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }
    if (canceled) {
      call.cancel();
    }
    //?? 重點
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        //?? 重點
        callSuccess(response);
      }
      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

上面我們標(biāo)記了三個重點:

1.第一個重點call = rawCall = createRawCall();

  private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

這里用到了上面提到了serviceMethod,之前我們已經(jīng)總結(jié),它是保存了所有請求需要的信息和請求需要的工具,這里就要使用了:

Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);

就這兩句,先把保存的請求頭和參數(shù)等信息,拼湊成OkHttpClient需要的Request,然后調(diào)用serviceMethod.callFactory.newCall(request),這個serviceMethod.callFactory就是我們之前設(shè)置的OkHttpClient,調(diào)用的它的newCall方法,得到一個OkHttp的Call請求對象,其實是RealCall對象

2.第二個重點call.enqueue(new okhttp3.Callback() {}

這是調(diào)用的OkHttpClient的enqueue方法,所以我們之前總結(jié)Retrofit就是對OkHttp請求之前和之后的工作的封裝,使其有一致、簡單、可復(fù)用等等。

3.第三個重點callSuccess(response);

     private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

callback.onResponse(OkHttpCall.this, response);,這個callback是之前delegate調(diào)用enqueue方法時的參數(shù):

    final Executor callbackExecutor;
    final Call<T> delegate;
    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
 @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }
        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

注意這個callback是delegate.enqueue方法的參數(shù),不是外層enqueue方法的callback,所以這個回調(diào)執(zhí)行的這個callback的onResponse方法代碼:

callbackExecutor.execute(new Runnable() {
  @Override public void run() {
    if (delegate.isCanceled()) {
      // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
    } else {
      callback.onResponse(ExecutorCallbackCall.this, response);
    }
  }
});

callbackExecutor之前提到過是platform.defaultCallbackExecutor():

    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }

可以看到就是把Runnable來交給handler執(zhí)行,實現(xiàn)的線程切換

到這里發(fā)起請求的調(diào)用邏輯分析清楚了。

到此這篇關(guān)于Java Retrofit源碼層深入分析的文章就介紹到這了,更多相關(guān)Java Retrofit內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java調(diào)用接口如何獲取json數(shù)據(jù)解析后保存到數(shù)據(jù)庫

    Java調(diào)用接口如何獲取json數(shù)據(jù)解析后保存到數(shù)據(jù)庫

    這篇文章主要介紹了Java調(diào)用接口如何獲取json數(shù)據(jù)解析后保存到數(shù)據(jù)庫問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java工作隊列代碼詳解

    Java工作隊列代碼詳解

    這篇文章主要介紹了Java工作隊列代碼詳解,涉及Round-robin 轉(zhuǎn)發(fā),消息應(yīng)答(messageacknowledgments),消息持久化(Messagedurability)等相關(guān)內(nèi)容,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • Java如何基于DOM解析xml文件

    Java如何基于DOM解析xml文件

    這篇文章主要介紹了Java如何基于DOM解析xml文件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • Java中List轉(zhuǎn)字符串的5種方法解析

    Java中List轉(zhuǎn)字符串的5種方法解析

    在Java中將一個List轉(zhuǎn)換為字符串有多種方法,下面這篇文章主要給大家介紹了關(guān)于Java中List轉(zhuǎn)字符串的5種方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • Spring?中的?Service?有多個實現(xiàn)類如何注入(多種方式)

    Spring?中的?Service?有多個實現(xiàn)類如何注入(多種方式)

    這篇文章主要介紹了Spring?中的?Service?有多個實現(xiàn)類如何注入,本文通過多種方式結(jié)合實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • Java中數(shù)組轉(zhuǎn)換為列表的兩種實現(xiàn)方式(超簡單)

    Java中數(shù)組轉(zhuǎn)換為列表的兩種實現(xiàn)方式(超簡單)

    本文介紹了在Java中將數(shù)組轉(zhuǎn)換為列表的兩種常見方法使用Arrays.asList和Java8的Stream API,Arrays.asList方法簡單易用,但返回的列表是固定大小的;而使用Stream API可以實現(xiàn)更靈活的操作,如過濾和映射,根據(jù)具體需求選擇合適的方法,感興趣的朋友一起看看吧
    2025-03-03
  • Java?Selenium實現(xiàn)修改打開頁面窗口大小

    Java?Selenium實現(xiàn)修改打開頁面窗口大小

    Selenium是一個強大的自動化測試工具,支持多種編程語言和瀏覽器,本文將詳細(xì)介紹如何使用Java?Selenium來修改打開頁面窗口的大小,需要的可以參考下
    2025-01-01
  • Java字符串拼接新方法 StringJoiner用法詳解

    Java字符串拼接新方法 StringJoiner用法詳解

    在本篇文章中小編給大家分享的是一篇關(guān)于Java字符串拼接新方法 StringJoiner用法詳解,需要的讀者們可以參考下。
    2019-09-09
  • Spring框架應(yīng)用的權(quán)限控制系統(tǒng)詳解

    Spring框架應(yīng)用的權(quán)限控制系統(tǒng)詳解

    在本篇文章里小編給大家整理的是關(guān)于基于Spring框架應(yīng)用的權(quán)限控制系統(tǒng)的研究和實現(xiàn),需要的朋友們可以學(xué)習(xí)下。
    2019-08-08
  • 如何使用Docker部署Java項目

    如何使用Docker部署Java項目

    在接觸了docker后,干什么都想用docker來弄,這篇文章主要給大家介紹了關(guān)于如何使用Docker部署Java項目的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07

最新評論

甘泉县| 曲靖市| 周至县| 台南县| 沁水县| 台安县| 靖安县| 乌鲁木齐市| 扶风县| 神农架林区| 杭锦旗| 珲春市| 玉溪市| 荆门市| 同心县| 福清市| 璧山县| 曲松县| 布尔津县| 闽侯县| 嘉定区| 银川市| 于都县| 右玉县| 华宁县| 班戈县| 门源| 鹤岗市| 杭锦后旗| 嘉善县| 田东县| 新营市| 济南市| 敖汉旗| 治多县| 龙江县| 化隆| 渭南市| 延庆县| 宜城市| 老河口市|