欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文帶你深入了解Java泛型

 更新時(shí)間:2022年08月17日 11:40:13   作者:小牛呼嚕嚕  
Java?泛型(generics)是?Jdk?5?中引入的一個(gè)新特性,?泛型提供了編譯時(shí)類型安全檢測(cè)機(jī)制,?該機(jī)制允許程序員在編譯時(shí)檢測(cè)到非法的類型。本文將通過(guò)示例詳解Java泛型的定義與使用,需要的可以參考一下

什么是Java泛型

Java 泛型(generics)是 Jdk 5 中引入的一個(gè)新特性, 泛型提供了編譯時(shí)類型安全檢測(cè)機(jī)制, 該機(jī)制允許程序員在編譯時(shí)檢測(cè)到非法的類型。

比如 ArrayList<String> list= new ArrayList<String>() 這行代碼就指明了該 ArrayList 對(duì)象只能 存儲(chǔ)String類型,如果傳入其他類型的對(duì)象就會(huì)報(bào)錯(cuò)。

讓我們時(shí)光回退到Jdk5的版本,那時(shí)ArrayList內(nèi)部其實(shí)就是一個(gè)Object[] 數(shù)組,配合存儲(chǔ)一個(gè)當(dāng)前分配的長(zhǎng)度,就可以充當(dāng)“可變數(shù)組”:

public class ArrayList {
    private Object[] array;
    private int size;
    public void add(Object e) {...}
    public void remove(int index) {...}
    public Object get(int index) {...}
}

我們來(lái)舉個(gè)簡(jiǎn)單的例子,

ArrayList list = new ArrayList();
list.add("test");
list.add(666);

我們本意是用ArrayList來(lái)裝String類型的值,但是突然混進(jìn)去了Integer類型的值,由于ArrayList底層是Object數(shù)組,可以存儲(chǔ)任意的對(duì)象,所以這個(gè)時(shí)候是沒(méi)啥問(wèn)題的,但我們不能只存不用啊,我們需要把值給拿出來(lái)使用,這個(gè)時(shí)候問(wèn)題來(lái)了:

for(Object item: list) {
    System.out.println((String)item);
}

結(jié)果:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

由于我們需要String類型的值,我們需要把ArrayList的Object值強(qiáng)制轉(zhuǎn)型,但是之前混進(jìn)去了Integer ,雖然編譯階段通過(guò)了,但程序的運(yùn)行結(jié)果會(huì)以崩潰結(jié)束,報(bào)ClassCastException異常

為了解決這個(gè)問(wèn)題,在Jdk 5版本中就引入了泛型的概念,而引入泛型的很大一部分原因就是為了解決我們上述的問(wèn)題,允許程序員在編譯時(shí)檢測(cè)到非法的類型。不是同類型的就不允許在一塊存放,這樣也避免了ClassCastException異常的出現(xiàn),而且因?yàn)槎际峭活愋?,也就沒(méi)必要做強(qiáng)制類型轉(zhuǎn)換了。

我們可以把ArrayList 變量參數(shù)化:

public class ArrayList<T> {
    private T[] array;//我們 假設(shè) ArrayList<T>內(nèi)部會(huì)有個(gè)T[] array  
    private int size;
    public void add(T e) {...}
    public void remove(int index) {...}
    public T get(int index) {...}
}

其中T叫類型參數(shù) ,T可以是任何class類型,現(xiàn)在ArrayList我們可以如下使用:

// 存儲(chǔ)String的ArrayList
ArrayList<String> list = new ArrayList<String>();
list.add(666);//編譯器會(huì)在編譯階段發(fā)現(xiàn)問(wèn)題,從而提醒開(kāi)發(fā)者

泛型其本質(zhì)是參數(shù)化類型,也就是說(shuō)數(shù)據(jù)類型 作為 參數(shù),解決不確定具體對(duì)象類型的問(wèn)題。

泛型的使用

泛型一般有三種使用方式,分別為:泛型類、泛型接口、泛型方法,我們簡(jiǎn)單介紹一下泛型的使用

泛型類

//此處T可以隨便寫為任意標(biāo)識(shí),常見(jiàn)的如T、E、K、V等形式的參數(shù)常用于表示泛型
//在實(shí)例化泛型類時(shí),必須指定T的具體類型
public class Generic<T>{

    private T key;

    public Generic(T key) {
        this.key = key;
    }

    public T getKey(){
        return key;
    }
}

如何實(shí)例化泛型類:

Generic<Integer> genericInteger = new Generic<Integer>(666);
Generic<String> genericStr = new Generic<String>("hello");

泛型接口

//定義一個(gè)泛型接口
public interface Generator<T> {
    public T method();
}

//實(shí)現(xiàn)泛型接口,不指定類型
class GeneratorImpl<T> implements Generator<T>{
    @Override
    public T method() {
        return null;
    }
}

//實(shí)現(xiàn)泛型接口,指定類型
class GeneratorImpl<T> implements Generator<String>{
    @Override
    public String method() {
        return "hello";
    }
}

泛型方法

public class GenericMethods {
    public <T> void f(T x){
        System.out.println(x.getClass().getName());
    }
    public static void main(String[] args) {
        GenericMethods gm = new GenericMethods();
        gm.f("啦啦啦");
        gm.f(666);
    }
}

結(jié)果:

java.lang.String
java.lang.Integer

泛型的底層實(shí)現(xiàn)機(jī)制

ArrayList源碼解析

通過(guò)上文我們知道,為了讓ArrayList存取各種數(shù)據(jù)類型的值,我們需要把ArrayList模板化,將變量的數(shù)據(jù)類型 給抽象出來(lái),作為類型參數(shù)

public class ArrayList<T> {
    private T[] array;// 我們以為ArrayList<T>內(nèi)部會(huì)有個(gè)T[] array
    private int size;
    public void add(T e) {...}
    public void remove(int index) {...}
    public T get(int index) {...}
}

但當(dāng)我們查看Jdk8 的ArrayList源碼,底層數(shù)組還是Object數(shù)組:transient Object[] elementData;那ArrayList為什么還能進(jìn)行類型約束和自動(dòng)類型轉(zhuǎn)換呢?

什么是泛型擦除

我們?cè)倏匆粋€(gè)經(jīng)典的例子:

public class genericTest {
    public static void main(String [] args) {
        String str="";
        Integer param =null;

        ArrayList<String> l1 = new ArrayList<String>();
        l1.add("aaa");
        str = l1.get(0);

        ArrayList<Integer> l2 = new ArrayList<Integer>();
        l2.add(666);
        param = l2.get(0);


        System.out.println(l1.getClass() == l2.getClass());
        
    }
}

結(jié)果竟然是true,ArrayList.class 和 ArrayList.class 應(yīng)該是不同的類型。通過(guò)getClass()方法獲取他們的類的信息,竟然是一樣的。我們來(lái)查看這個(gè)文件的class文件:

public class genericTest {
    public genericTest() {
    }

    public static void main(String[] var0) {
        String var1 = "";
        Integer var2 = null;
        ArrayList var3 = new ArrayList();//泛型被擦擦了
        var3.add("aaa");
        var1 = (String)var3.get(0);
        ArrayList var4 = new ArrayList();//泛型被擦擦了
        var4.add(666);
        var2 = (Integer)var4.get(0);
        System.out.println(var3.getClass() == var4.getClass());
    }
}

我們?cè)趯?duì)其反匯編一下:

$ javap -c genericTest

????: ?????????genericTest????com.zj.demotest.test5.genericTest
Compiled from "genericTest.java"
public class com.zj.demotest.test5.genericTest {
  public com.zj.demotest.test5.genericTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String
       2: astore_1
       3: aconst_null
       4: astore_2
       5: new           #3                  // class java/util/ArrayList
       8: dup
       9: invokespecial #4                  // Method java/util/ArrayList."<init>":()V
      12: astore_3
      13: aload_3
      14: ldc           #5                  // String aaa
      16: invokevirtual #6                  // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
      19: pop
      20: aload_3
      21: iconst_0
      22: invokevirtual #7                  // Method java/util/ArrayList.get:(I)Ljava/lang/Object;
      25: checkcast     #8                  // class java/lang/String
      28: astore_1
      29: new           #3                  // class java/util/ArrayList
      32: dup
      33: invokespecial #4                  // Method java/util/ArrayList."<init>":()V
      36: astore        4
      38: aload         4
      40: sipush        666
      43: invokestatic  #9                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      46: invokevirtual #6                  // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
      49: pop
      50: aload         4
      52: iconst_0
      53: invokevirtual #7                  // Method java/util/ArrayList.get:(I)Ljava/lang/Object;
      56: checkcast     #10                 // class java/lang/Integer
      59: astore_2
      60: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
      63: aload_3
      64: invokevirtual #12                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      67: aload         4
      69: invokevirtual #12                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      72: if_acmpne     79
      75: iconst_1
      76: goto          80
      79: iconst_0
      80: invokevirtual #13                 // Method java/io/PrintStream.println:(Z)V
      83: return
}

看第16、46處,add進(jìn)去的是原始類型Object;

看第22、53處,get方法獲得也是Object類型,String、Integer類型被擦出,只保留原始類型Object。

看25、55處,checkcast指令是類型轉(zhuǎn)換檢查 ,在結(jié)合class文件var1 = (String)var3.get(0);``var2 = (Integer)var4.get(0);我們知曉編譯器自動(dòng)幫我們強(qiáng)制類型轉(zhuǎn)換了,我們無(wú)需手動(dòng)類型轉(zhuǎn)換

經(jīng)過(guò)上面的種種現(xiàn)象,我們可以發(fā)現(xiàn),在類加載的編譯階段,泛型類型String和Integer都被擦除掉了,只剩下原始類型,這樣他們類的信息都是Object,這樣自然而然就相等了。這種機(jī)制就叫泛型擦除。

我們需要了解一下類加載生命周期:

詳情見(jiàn):詳解Java類加載器與雙親委派機(jī)制

泛型是和編譯器的約定,在編譯期對(duì)代碼進(jìn)行檢查的,由編譯器負(fù)責(zé)解析,JVM并無(wú)識(shí)別的能力,一個(gè)類繼承泛型后,當(dāng)變量存入這個(gè)類的時(shí)候,編譯器會(huì)對(duì)其進(jìn)行類型安全檢測(cè),當(dāng)從中取出數(shù)據(jù)時(shí),編譯器會(huì)根據(jù)與泛型的約定,會(huì)自動(dòng)進(jìn)行類型轉(zhuǎn)換,無(wú)需我們手動(dòng)強(qiáng)制類型轉(zhuǎn)換。

泛型類型參數(shù)化,并不意味這其對(duì)象類型是不確定的,相反它的對(duì)象類型 對(duì)于JVM來(lái)說(shuō),都是確定的,是Object或Object[]數(shù)組

泛型的邊界

來(lái)看一個(gè)經(jīng)典的例子,我們想要實(shí)現(xiàn)一個(gè)ArrayList對(duì)象能夠儲(chǔ)存所有的泛型:

ArrayList<Object> list = new ArrayList<String>();

但可以的是編譯器提示報(bào)錯(cuò):

明明 String是Object類的子類,我們可以發(fā)現(xiàn),泛型不存在繼承、多態(tài)關(guān)系,泛型左右兩邊要一樣別擔(dān)心,JDK提供了通配符?來(lái)應(yīng)對(duì)這種場(chǎng)景,我們可以這樣:

ArrayList<?> list = new ArrayList<String>();
list = new ArrayList<Integer>();

通配符<?>表示可以接收任意類型,此處?是類型實(shí)參,而不是類型形參。我們可以把它看做是String、Integer等所有類型的"父類"。是一種真實(shí)的類型。通配符還有:

  • 上邊界限定通配符,如<? extends E>;
  • 下邊界通配符,如<? super E>;

?:無(wú)界通配符

?是開(kāi)放限度最大的,可指向任意類型,但在對(duì)于其的存取上也是限制最大的:

  • 入?yún)⒑头盒拖嚓P(guān)的都不能使用, 除了null(禁止存入),比如ArrayList<?> list不可以添加任何類型,因?yàn)椴⒉恢缹?shí)際是哪種類型
  • 返回值和泛型相關(guān)的都只能用Object接收

extends 上邊界通配符

//泛型的上限只能是該類型的類型及其子類,其中Number是Integer、Long、Float的父類   
ArrayList<? extends Number> list = new ArrayList<Integer>();
ArrayList<? extends Number> list2 = new ArrayList<Long>();
ArrayList<? extends Number> list3 = new ArrayList<Float>();

list.add(1);//報(bào)錯(cuò),extends不允許存入

ArrayList<Long> longList = new ArrayList<>();
longList.add(1L);
list = longList;//由于extends不允許存入,list只能重新指向longList

Number number = list.get(0);  // extends 取出來(lái)的元素(Integer,Long,Float)都可以轉(zhuǎn)Number

extends指向性被砍了一半,只能指向子類型和父類型,但方法使用上又適當(dāng)放開(kāi)了:

  • 值得注意的是:這里的extends并不表示類的繼承含義,只是表示泛型的范圍關(guān)系
  • extends不允許存入,由于使用extends ,比如ArrayList<? extends Number> list可以接收Integer、Long、Float,但是泛型本質(zhì)是保證兩邊類型確定,這樣的話在程序運(yùn)行期間,再存入數(shù)據(jù),編譯器可無(wú)法知曉數(shù)據(jù)的類型,所以只能禁止了。
  • 但為什么ArrayList<? extends Number> list可以重新指向longList來(lái)變向地"存儲(chǔ)"值,那是因?yàn)?code>ArrayList<Long> longList = new ArrayList<>();這邊的泛型已經(jīng)約束兩邊的類型了,編譯器知曉longList儲(chǔ)存的數(shù)據(jù)都是Long類型
  • 但extends允許取出,取出來(lái)的元素可以往邊界類型轉(zhuǎn)
  • extends中可以指定多個(gè)范圍,實(shí)行泛型類型檢查約束時(shí),會(huì)以最左邊的為準(zhǔn)。

super 下邊界通配符

//泛型的下限只能是該類型的類型及其父類,其中Number是Integer、Long、Float的父類   
ArrayList<? super Integer> list = new ArrayList<Integer>();
ArrayList<? super Integer> list2 = new ArrayList<Number>();
ArrayList<? super Integer> list3 = new ArrayList<Long>();//報(bào)錯(cuò)
ArrayList<? super Integer> list4 = new ArrayList<Float>();//報(bào)錯(cuò)

list2.add(123);//super可以存入,只能存Integer及其子類型元素
Object aa =  list2.get(0);//super可以取出,類型只能是Object

super允許存入編輯類型及其子類型元素,但取出元素只能為Object類型

PECS原則

泛型通配符的出現(xiàn),是為了獲得最大限度的靈活性。如果要用到通配符,需要結(jié)合業(yè)務(wù)考慮,《Effective Java》提出了:PECS(Producer Extends Consumer Super)

  • 需要頻繁往外讀取內(nèi)容(生產(chǎn)者Producer),適合用<? extends T>
  • 需要頻繁寫值(消費(fèi)者Consumer),適合用<? super T>:super允許存入子類型元素
  • ? 表示不確定的 java 類型,一般用于只接收任意類型,而不對(duì)其處理的情況

泛型是怎么擦除的

Java 編譯器通過(guò)如下方式實(shí)現(xiàn)擦除:

  • 用 Object 或者界定類型替代泛型,產(chǎn)生的字節(jié)碼中只包含了原始的類,接口和方法;
  • 在恰當(dāng)?shù)奈恢貌迦霃?qiáng)制轉(zhuǎn)換代碼來(lái)確保類型安全;
  • 在繼承了泛型類或接口的類中自動(dòng)產(chǎn)生橋接方法來(lái)保留多態(tài)性。

擦除類定義中的無(wú)限制類型參數(shù)

當(dāng)類定義中的類型參數(shù)沒(méi)有任何限制時(shí),在類型擦除中直接被替換為Object,即形如和<?>的類型參數(shù)都被替換為Object

擦除類定義中的有限制類型擦除

當(dāng)類定義中的類型參數(shù)存在限制(上下界)時(shí),在類型擦除中替換為類型參數(shù)的上界或者下界,
形如

  • <T extends Number><? extends Number>的類型參數(shù)被替換為Number,
  • <? super Number>被替換為Object

擦除方法定義中的類型參數(shù)

擦除方法定義中的類型參數(shù)原則和擦除類定義中的類型參數(shù)是一樣的,額外補(bǔ)充 擦除方法定義中的有限制類型參數(shù)的例子

橋接方法和泛型的多態(tài)

public class A<T>{
    public T get(T a){
        //進(jìn)行一些操作
        return a;
    }
}
public class B extends A<String>{
    @override
    public String get(String a){
        //進(jìn)行一些操作
        return a;
    }
}

由于類型擦出機(jī)制的存在,按理說(shuō)編譯后的文件在翻譯為java應(yīng)如下所示:

public class A{
    public Object get(Object a){
        //進(jìn)行一些操作
        return a;
    }
}
public class B extends A{
    @override
    public String get(String a){
        //進(jìn)行一些操作
        return a;
    }
}

但是,我們可以發(fā)現(xiàn) @override意味著B(niǎo)對(duì)父類A中的get方法進(jìn)行了重寫,但是依上面的程序來(lái)看,只是重載,依然可以執(zhí)行父類的方法,這和期望是不附的,也不符合java繼承、多態(tài)的特性。

重寫是子類對(duì)父類的允許訪問(wèn)的方法的實(shí)現(xiàn)過(guò)程進(jìn)行重新編寫, 返回值和形參都不能改變。即外殼不變,核心重寫!

重載(overloading) 是在一個(gè)類里面,方法名字相同,而參數(shù)不同。返回類型可以相同也可以不同。

為了解決這個(gè)問(wèn)題,java在編譯期間加入了橋接方法。編譯后再翻譯為java原文件其實(shí)是:

public class A{
    public Object get(Object a){
        //進(jìn)行一些操作
        return a;
    }
}
public class B extends A{
    @override
    public String get(String a){
        //進(jìn)行一些操作
        return a;
    }
    //橋接方法!!!
    public Object get(Object a){
        return get((String)a)
    }
}

橋接方法重寫了父類相同的方法,并且橋接方法中,最終調(diào)用了期望的重寫方法,并且橋接方法在調(diào)用目的方法時(shí),參數(shù)被強(qiáng)制轉(zhuǎn)換為指定的泛型類型。橋接方法搭起了父類和子類的橋梁。

橋接方法是伴隨泛型方法而生的,在繼承關(guān)系中,如果某個(gè)子類覆蓋了泛型方法,則編譯器會(huì)在該子類自動(dòng)生成橋接方法。所以我們實(shí)際使用泛型的過(guò)程中,無(wú)需擔(dān)心橋接方法。

泛型擦除帶來(lái)的限制與局限

泛型不適用基本數(shù)據(jù)類型

不能用類型參數(shù)代替基本類型(byte 、short 、int 、long、float 、 double、char、boolean)

比如, 沒(méi)有 Pair<double>, 只 有 Pair<Double>。 其原因是泛型擦除,擦除之后只有原始類型Object, 而 Object 無(wú)法存儲(chǔ) double等基本類型的值。

但Java同時(shí)有自動(dòng)拆裝箱特性,可以將基本類型裝箱成包裝類型,這樣就使用泛型了,通過(guò)中轉(zhuǎn),即可在功能上實(shí)現(xiàn)“用基本類型實(shí)例化類型化參數(shù)”。

數(shù)據(jù)類型封裝類
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

無(wú)法創(chuàng)建具體類型的泛型數(shù)組

List<Integer>[] l1 = new ArrayList<Integer>[10];// Error
List<String>[] l2 = new ArrayList<String>[10];// Error

上文我們知曉ArrayList,底層仍舊采用Object[],Integer,String類型信息都被擦除

借助無(wú)限定通配符 ?,可以創(chuàng)建泛型數(shù)組,但是涉及的操作都基本上與類型無(wú)關(guān)

List<?>[] l1 = new ArrayList<?>[10];

如果想對(duì)數(shù)組進(jìn)行復(fù)制操作的話,可以通過(guò)Arrays.copyOfRange()方法

public class TestArray {

    public static void main(String[] args) {
        Integer[] array = new Integer[]{2, 3, 1};
        Integer[] arrNew = copy(array);
    }

    private static <E> E[] copy(E[] array) {
        return Arrays.copyOfRange(array, 0, array.length);
    }
    
}

反射其實(shí)可以繞過(guò)泛型的限制

由于我們知曉java是通過(guò)泛型擦除來(lái)實(shí)現(xiàn)泛型的,JVM只能識(shí)別原始類型Object,所以我們只需騙過(guò)編譯器的校驗(yàn)即可,反射是程序運(yùn)行時(shí)發(fā)生的,我們可以借助反射來(lái)波騷操作

List<Integer> l1 = new ArrayList<>();
l1.add(111);
//l1.add("騷氣的我"); // 泛型會(huì)報(bào)錯(cuò)
try {
    Method method = l1.getClass().getDeclaredMethod("add",Object.class);
    method.invoke(l1,"騷氣的我 又出現(xiàn)了");
} catch (NoSuchMethodException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
}
for ( Object o: l1){
    System.out.println(o);
}

結(jié)果:

111
騷氣的我 又出現(xiàn)了

以上就是一文帶你深入了解Java泛型的詳細(xì)內(nèi)容,更多關(guān)于Java泛型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java、spring、springboot中整合Redis的詳細(xì)講解

    java、spring、springboot中整合Redis的詳細(xì)講解

    這篇文章主要介紹了java、spring、springboot中整合Redis的詳細(xì)講解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • SpringBoot統(tǒng)一處理功能實(shí)現(xiàn)的全過(guò)程

    SpringBoot統(tǒng)一處理功能實(shí)現(xiàn)的全過(guò)程

    最近在做項(xiàng)目時(shí)需要對(duì)異常進(jìn)行全局統(tǒng)一處理,主要是一些分類入庫(kù)以及記錄日志等,下面這篇文章主要給大家介紹了關(guān)于SpringBoot統(tǒng)一功能處理實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • Java時(shí)間復(fù)雜度、空間復(fù)雜度的深入詳解

    Java時(shí)間復(fù)雜度、空間復(fù)雜度的深入詳解

    對(duì)于一個(gè)算法,其時(shí)間復(fù)雜度和空間復(fù)雜度往往是相互影響的,當(dāng)追求一個(gè)較好的時(shí)間復(fù)雜度時(shí),可能會(huì)使空間復(fù)雜度的性能變差,即可能導(dǎo)致占用較多的存儲(chǔ)空間,這篇文章主要給大家介紹了關(guān)于Java時(shí)間復(fù)雜度、空間復(fù)雜度的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • Java實(shí)現(xiàn)將類數(shù)據(jù)逐行寫入CSV文件的方法詳解

    Java實(shí)現(xiàn)將類數(shù)據(jù)逐行寫入CSV文件的方法詳解

    這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)將類數(shù)據(jù)逐行寫入CSV文件,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,需要的可以借鑒一下
    2022-11-11
  • SpringBoot 項(xiàng)目添加 MDC 日志鏈路追蹤的執(zhí)行流程

    SpringBoot 項(xiàng)目添加 MDC 日志鏈路追蹤的執(zhí)行流程

    日志鏈路追蹤就是將一個(gè)標(biāo)志跨線程進(jìn)行傳遞,在一般的小項(xiàng)目中也就是在你新起一個(gè)線程的時(shí)候,或者使用線程池執(zhí)行任務(wù)的時(shí)候會(huì)用到,比如追蹤一個(gè)用戶請(qǐng)求的完整執(zhí)行流程,本文給大家介紹SpringBoot MDC 日志鏈路追蹤的代碼,感興趣的朋友一起看看吧
    2021-06-06
  • Java實(shí)現(xiàn)基于token認(rèn)證的方法示例

    Java實(shí)現(xiàn)基于token認(rèn)證的方法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)基于token認(rèn)證的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 淺談java實(shí)現(xiàn)背包算法(0-1背包問(wèn)題)

    淺談java實(shí)現(xiàn)背包算法(0-1背包問(wèn)題)

    本篇文章主要介紹了淺談java實(shí)現(xiàn)背包算法(0-1背包問(wèn)題) ,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • Java volatile關(guān)鍵字原理剖析與實(shí)例講解

    Java volatile關(guān)鍵字原理剖析與實(shí)例講解

    volatile是Java提供的一種輕量級(jí)的同步機(jī)制,Java?語(yǔ)言包含兩種內(nèi)在的同步機(jī)制:同步塊(或方法)和?volatile?變量,本文將詳細(xì)為大家總結(jié)Java volatile關(guān)鍵字,通過(guò)詳細(xì)的代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • Java?Spring?boot實(shí)現(xiàn)生成二維碼

    Java?Spring?boot實(shí)現(xiàn)生成二維碼

    大家好,本篇文章主要講的是Java?Spring?boot實(shí)現(xiàn)生成二維碼,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-02-02
  • 分析Java設(shè)計(jì)模式之組合模式

    分析Java設(shè)計(jì)模式之組合模式

    組合模式是一種對(duì)象的行為模式。將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。它的本質(zhì)是統(tǒng)一葉子對(duì)象和組合對(duì)象。它的目的是讓客戶端不再區(qū)分操作的是組合對(duì)象還是葉子對(duì)象,而是以一個(gè)統(tǒng)一的方式來(lái)操作
    2021-06-06

最新評(píng)論