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

Java如何獲取List<String>中的String詳解

 更新時間:2022年02月22日 09:28:28   作者:raysonxin  
工作了這么長時間了,一直沒有記錄的習(xí)慣,以至于導(dǎo)致我即便是查過的東西總會忘記,下面這篇文章主要給大家介紹了關(guān)于Java如何獲取List<String>中String的相關(guān)資料,需要的朋友可以參考下

前言

在寫這篇文章之前,我?guī)缀鯖]有思路去定義這個問題。只是知道,List<String>是泛型,是接口List<T>的實現(xiàn),實例化以后只能存儲String類型的對象,僅此而已!

提到泛型,每個Java開發(fā)人員都比較熟悉。常見的List、Map<K,V>等;另外,我們在進(jìn)行工具類、公共包的開發(fā)時,也經(jīng)常使用泛型實現(xiàn)規(guī)范化、模板化的目標(biāo)。

問題場景

最近,在為新系統(tǒng)封裝公共包時遇到了一個與泛型有關(guān)的問題。在這里,結(jié)合實際場景討論一下。描述一下場景:封裝MQ中間件,統(tǒng)一MQ的消息訂閱與處理過程,統(tǒng)一MQ相關(guān)日志與監(jiān)控。

解決思路還是比較簡單的,整體由三個部分組成(如下圖所示):

  • IMessageSub:通過接口定義了需要訂閱的Topic、Tag、消費組,并提供消息處理入口;
  • MessageQueueListener:實現(xiàn)了RocketMQ的接口MessageListenerConcurrently,是真正的消費者,負(fù)責(zé)消息消費處理。
  • MqSubManager:負(fù)責(zé)完成IMessageSub Bean的發(fā)現(xiàn)(所有實現(xiàn)類均為Spring的Bean對象),并通過MessageQueueListener實現(xiàn)對MQ的最終訂閱。

通過這個圖,我們可以知道MessageQueueListener#consumeMessage負(fù)責(zé)接收消息,轉(zhuǎn)換為指定類型后,交給IMessageSub#processMessage進(jìn)行處理。IMessageSub<T>是一個泛型接口,consumeMessage需要把消息轉(zhuǎn)換為IMessageSub實例的所需實際類型(如下ConcreteMessageSub1示例的DemoMsg)。

public interface IMessageSub<T> {
?String getTopic();
? ? String getTag();
? ? String getConsumerGroup();
? ? void processMessage(MqEvent<DemoMsg> mqEvent);
}

@Component
public class ConcreteMessageSub1 implements IMessageSub<DemoMsg> {
?public String getTopic(){
? ? ?return "TOPIC_TEST"
? ? }
? ??
?public String getTag(){
? ? ?return "TAG_TEST";
? ? }
?public String getConsumerGroup(){
? ? ?return "CID_TEST"
? ? }
?public void processMessage(MqEvent<DemoMsg> mqEvent){
? ? ?// do something...
? ? }
}

public class MessageQueueListener implements MessageListenerConcurrently {

? ? private IMessageSub<?> messageSub;
? ??
? ? public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
? ? ?
? ? }
}

每個MessageQueueListener對象持有一個IMessageSub的實例messageSub,可能是DemoMsg、DemoMsg2等等,如何才能確定對象MessageQueueListener#messageSub的實際類型呢?

問題討論

我們知道,對于一個非泛型對象,只需要調(diào)用其getClass()方法就可以了。但是對于泛型對象,做同樣的操作,結(jié)果卻不是我們想要的。如下簡單示例:

public static void main(String[] args) {
    String str = "";
    System.out.println(str.getClass().getName());
    
    List<String> list=new ArrayList<>();
    System.out.println(list.getClass().getName());
}

輸出結(jié)果:

java.lang.String
java.util.ArrayList

泛型對象list的輸出結(jié)果是“java.util.ArrayList”,貌似跟String沒有關(guān)系了,怎么回事兒呢?這就涉及到Java泛型的實現(xiàn)原理了。

Java的泛型是一種偽泛型,是通過類型擦除(Type Erasure)實現(xiàn)的參數(shù)化類型(Parameterized Type),也就是說把所操作的數(shù)據(jù)類型作為參數(shù)的一種語法。具體的歷史背景就是:

Java在實現(xiàn)泛型機(jī)制時,為了避免新增泛型類型,直接把需要支持泛型的原始類型泛型化,比如:ArrayList變?yōu)锳rrayList。

這就需要,Java能夠?qū)崿F(xiàn)具備向前、向后兼容性的泛型,也就是說以前使用原始類型的代碼可以繼續(xù)被泛型使用,現(xiàn)在的泛型也可以作為參數(shù)傳遞給原始類型的代碼。

為了實現(xiàn)以上功能,Java 設(shè)計者將泛型完全作為了語法糖加入了新的語法中,也就是說泛型對于JVM來說是透明的,有泛型的和沒有泛型的代碼,通過編譯器編譯后所生成的二進(jìn)制代碼是完全相同的。編譯器在編譯過程中去除泛型的過程,被稱作類型擦除。

泛型的參數(shù)化類型本質(zhì)可以應(yīng)用在類、接口、方法,于是就產(chǎn)生了泛型類、泛型接口、泛型方法,可以說極大提升了Java代碼的靈活性。

考察大家一個小知識,我們天天使用或者見到泛型,如List<E>,你知道它的各個組成部分叫什么名字嗎?

  • List<E>中的E稱為類型參數(shù)變量,整個稱為List<E>泛型類型。
  • List<Integer>中的Integer稱為實際類型參數(shù),整個List<Integer>稱為參數(shù)化的類型ParameterizedType。

類型擦除確實保證了良好的兼容性,但是在很多場景下我們確實需要知道泛型對象的原始信息。比如“問題場景”中獲取泛型接口實現(xiàn)類對象的實際類型參數(shù)。

雖然在編譯期間編譯器擦除了泛型,但是在字節(jié)碼中仍然保留了與泛型有關(guān)的信息,這就使得我們可以通過反射來獲取泛型擦除前的原始信息。為了表達(dá)泛型類型聲明,Java提供了接口Type及其子類型。

通過這些API我們可以對泛型的原始信息了如指掌:

  • Class類:描述具體類型,比較常見,可通過getClass()獲取。
  • TypeVariable接口:描述類型變量(如:T extends Comparable<? super T> ),通過getClass().getTypeParameters()。
  • WildcardType接口:描述通配符 (如:? super T )。
  • ParameterizedType接口:描述泛型類或接口類型(如:Comparable<? super T>),可通過getClass().getGenericInterfaces()獲取后篩選。
  • GenericArrayType接口:描述泛型數(shù)組(如:T[])

解決方案

了解泛型的原理后,結(jié)合反射包提供的API,我們就很容易解決第一部分提出的問題了。

結(jié)合上面的示例,MessageQueueListener#messageSub是一個泛型接口對象,實際為IMessageSub<T>泛型接口的實現(xiàn)類(如ConcreteMessageSub1),我們的目標(biāo)就是獲取ConcreteMessageSub1實現(xiàn)泛型接口時指定的實際類型參數(shù)DemoMsg。所以,需要按照以下步驟進(jìn)行處理:

  • 獲取對象messageSub所屬類(如:ConcreteMessageSub1)實現(xiàn)的接口列表;
  • 僅保留接口列表中的描述泛型接口的參數(shù)化類型對象(ParameterizedType);
  • 在參數(shù)化類型對象中獲取類型為IMessageSub的描述對象,即我們需要的參數(shù)化類型對象;
  • 獲取該參數(shù)化類型對象的第一個實際類型參數(shù)(接口聲明只有一個泛型參數(shù))。

用代碼實現(xiàn)如下所示:

/**
?* 獲取消息執(zhí)行器范性類型
?*
?* @return 類型
?*/
private Type getExecutorGenericType(IEventProcessor eventProcessor) {
? ? try {
? ? ? ? Optional<Type> typeOptional = Arrays.stream(eventProcessor.getClass().getGenericInterfaces())
? ? ? ? ? ? .filter(type -> ParameterizedType.class.isAssignableFrom(type.getClass()))
? ? ? ? ? ? .map(type -> (ParameterizedType)type)
? ? ? ? ? ? .filter(parameterizedType -> IEventProcessor.class.getTypeName().equals(parameterizedType.getRawType().getTypeName()))
? ? ? ? ? ? .map(ParameterizedType::getActualTypeArguments)
? ? ? ? ? ? .filter(actualTypes -> actualTypes.length > 0)
? ? ? ? ? ? .map(actualTypes -> actualTypes[0])
? ? ? ? ? ? .findFirst();
? ? ? ? return typeOptional.orElse(null);
? ? } catch (Throwable cause) {

? ? }
? ? return null;
}

本文總結(jié)

依托于泛型提供的API,我們可以開發(fā)出靈活的工具及框架,也可以使我們的代碼更加簡潔高效。可以說,Java的泛型是一種“語法糖”。以復(fù)用性更強(qiáng)的方式來提高開發(fā)效率,幫助開發(fā)人員在編譯階段識別系統(tǒng)存在的安全隱患,以更強(qiáng)的約束力來保證代碼的健壯性。

本來只想簡單的介紹獲取參數(shù)化類型的方式,可是當(dāng)把問題展開的時候,才發(fā)現(xiàn)自己對泛型的體系認(rèn)識不夠,每天上下班路上一邊學(xué)習(xí),一邊記錄筆記。關(guān)于泛型,還有許多要去學(xué)習(xí)和了解的知識,大家一起進(jìn)步。

到此這篇關(guān)于Java如何獲取List&lt;String&gt;中的String的文章就介紹到這了,更多相關(guān)Java獲取List&lt;String&gt;中String內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java 中sleep() 和 wait() 的對比

    java 中sleep() 和 wait() 的對比

    這篇文章主要介紹了java 中sleep() 和 wait() 的對比的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Java創(chuàng)建數(shù)組的3種方式代碼舉例

    Java創(chuàng)建數(shù)組的3種方式代碼舉例

    數(shù)組是相同類型數(shù)據(jù)的有序集合,數(shù)組描述的是若干個相同類型的數(shù)據(jù)按照一定的先后次序排列組合而成,其中每一個數(shù)據(jù)稱為數(shù)組的元素,可以通過下標(biāo)進(jìn)行訪問,這篇文章主要給大家介紹了關(guān)于Java創(chuàng)建數(shù)組的3種方式,需要的朋友可以參考下
    2024-01-01
  • java并發(fā)編程專題(六)----淺析(JUC)Semaphore

    java并發(fā)編程專題(六)----淺析(JUC)Semaphore

    這篇文章主要介紹了java JUC)Semaphore的相關(guān)資料,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • 詳解Spring3.x 升級至 Spring4.x的方法

    詳解Spring3.x 升級至 Spring4.x的方法

    本篇文章主要介紹了詳解Spring3.x 升級至 Spring4.x的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • 在Java8中構(gòu)建Stream流的多種方式詳解

    在Java8中構(gòu)建Stream流的多種方式詳解

    當(dāng)我們處理集合數(shù)據(jù)時,往往需要對其進(jìn)行各種操作,如過濾、映射、排序、歸約等,在 Java 8 中引入的 Stream 流為我們提供了一種更加簡潔和靈活的方式來處理數(shù)據(jù),本文將介紹如何基于 Stream 構(gòu)建流,為你展示創(chuàng)建和操作流的多種方法
    2023-08-08
  • Java中二叉樹的先序、中序、后序遍歷以及代碼實現(xiàn)

    Java中二叉樹的先序、中序、后序遍歷以及代碼實現(xiàn)

    這篇文章主要介紹了Java中二叉樹的先序、中序、后序遍歷以及代碼實現(xiàn),一棵二叉樹是結(jié)點的一個有限集合,該集合或者為空,或者是由一個根節(jié)點加上兩棵別稱為左子樹和右子樹的二叉樹組成,需要的朋友可以參考下
    2023-11-11
  • 詳解SpringBoot?統(tǒng)一后端返回格式的方法

    詳解SpringBoot?統(tǒng)一后端返回格式的方法

    今天我們來聊一聊在基于SpringBoot前后端分離開發(fā)模式下,如何友好的返回統(tǒng)一的標(biāo)準(zhǔn)格式以及如何優(yōu)雅的處理全局異常,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2022-05-05
  • 分享40個Java多線程問題小結(jié)

    分享40個Java多線程問題小結(jié)

    多個線程共存于同一JVM進(jìn)程里面,所以共用相同的內(nèi)存空間,較之多進(jìn)程,多線程之間的通信更輕量級,本文給大家分享40個Java多線程問題小結(jié) 的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • Spring多數(shù)據(jù)源導(dǎo)致配置失效的解決

    Spring多數(shù)據(jù)源導(dǎo)致配置失效的解決

    這篇文章主要介紹了Spring多數(shù)據(jù)源導(dǎo)致配置失效的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java正則之貪婪匹配、惰性匹配

    Java正則之貪婪匹配、惰性匹配

    這篇文章主要介紹了Java正則之貪婪匹配、惰性匹配的相關(guān)資料,需要的朋友可以參考下
    2015-03-03

最新評論

江陵县| 凤冈县| 成都市| 石城县| 曲松县| 阿巴嘎旗| 全南县| 常州市| 门头沟区| 运城市| 秦皇岛市| 克山县| 谷城县| 安远县| 化隆| 南漳县| 盘山县| 津南区| 武穴市| 五寨县| 平昌县| 休宁县| 山丹县| 郯城县| 闻喜县| 永川市| 偃师市| 台江县| 务川| 雷波县| 阿鲁科尔沁旗| 涟源市| 墨脱县| 东平县| 安多县| 焦作市| 汉中市| 耿马| 河曲县| 泗阳县| 武宁县|