亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java中ArrayList實現(xiàn)原理及基本方法

 更新時間:2023年08月18日 09:41:26   作者:ycfxhsw  
這篇文章主要介紹了Java中ArrayList實現(xiàn)原理及基本方法,ArrayList是開發(fā)中非常常用的數(shù)據(jù)存儲容器之一,其底層是數(shù)組實現(xiàn)的,我們可以在集合中存儲任意類型的數(shù)據(jù),ArrayList是線程不安全的,擅長隨機訪問元素,插入和刪除較慢,需要的朋友可以參考下

1、ArrayList的數(shù)據(jù)結(jié)構(gòu)

ArrayList是開發(fā)中非常常用的數(shù)據(jù)存儲容器之一,其底層是 數(shù)組 實現(xiàn)的

我們可以在集合中存儲任意類型的數(shù)據(jù),ArrayList是線程不安全的,擅長隨機訪問元素,插入和刪除較慢 。

ArrayList的底層數(shù)據(jù)結(jié)構(gòu)就是一個 數(shù)組 ,數(shù)組元素的類型為Object類型,對ArrayList的所有操作底層都是基于數(shù)組的。

2、ArrayList是線程不安全的

對ArrayList進行添加元素的操作的時候是分兩個步驟進行的:

  • 先在object[size]的位置上存放需要添加的元素;
  • size的值增加1。

由于這個過程在多線程的環(huán)境下是不能保證具有原子性 的,因此ArrayList在多線程的環(huán)境下是線程不安全的。

在單線程運行的情況下,如果Size = 0,添加一個元素后,此元素在位置 0,而且Size=1;

而如果是在多線程情況下,比如有兩個線程,線程 A 先將元素存放在位置0。

但是此時 CPU 調(diào)度線程A暫停,線程 B 得到運行的機會。

線程B也向此ArrayList 添加元素,因為此時 Size 仍然等于 0

(注意:我們假設(shè)的是添加一個元素是要兩個步驟哦,而線程A僅僅完成了步驟1),所以線程B也將 元素存放在位置0。

然后線程A和線程B都繼續(xù)運行,都增 加 Size 的值。

那好,現(xiàn)在我們來看看ArrayList 的情況,元素實際上只有一個,存放在位置 0,而Size卻等于 2。這就是“線程不安全”了。

如果非要在多線程的環(huán)境下使用ArrayList,就需要保證它的線程安全性,通常有兩種解決辦法:

  • 使用synchronized關(guān)鍵字;
  • 可以用Collections類中的靜態(tài)方法synchronizedList(),對ArrayList進行調(diào)用即可。

3、ArrayList的實現(xiàn)

對于ArrayList而言,它實現(xiàn)List接口、底層使用數(shù)組保存所有元素。其操作基本上是對數(shù)組的操作。

下面我們來分析ArrayList的源代碼:

1) 私有屬性:

ArrayList定義只定義類兩個私有屬性:

/**
*ArrayList 的元素存儲在其中的數(shù)組緩沖區(qū)。
*ArrayList 的容量就是這個數(shù)組緩沖區(qū)的長度。添加第一個元素時,任何帶有 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList 都將擴展為 DEFAULT_CAPACITY(10)。
*/
transient Object[] elementData;
// ArrayList 的大小
private int size;

Java的serialization提供了一種持久化對象實例的機制。

當持久化對象時,可能有一個特殊的對象數(shù)據(jù)成員,我們不想用serialization機制來保存它。

為了在一個特定對象的一個域上關(guān)閉serialization,可以在這個域前加上關(guān)鍵字transient。

有點抽象,看個例子應(yīng)該能明白:

public class UserInfo implements Serializable {
    private static final long serialVersionUID = 996890129747019948L;
    private String name;
    private transient String psw;
    public UserInfo(String name, String psw) {
        this.name = name;
        this.psw = psw;
    }
    public String toString() {
        return "name=" + name + ", psw=" + psw;
    }
}
public class TestTransient {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("張三", "123456");
        System.out.println(userInfo);
        try {
            // 序列化,被設(shè)置為transient的屬性沒有被序列化
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.out"));
            o.writeObject(userInfo);
            o.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            // 重新讀取內(nèi)容
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.out"));
            UserInfo readUserInfo = (UserInfo) in.readObject();
            // 讀取后psw的內(nèi)容為null
            System.out.println(readUserInfo.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

被標記為transient的屬性在對象被序列化的時候不會被保存?;氐紸rrayList的分析中

2) 構(gòu)造方法:

ArrayList提供了三種方式的構(gòu)造器,可以構(gòu)造一個默認初始容量為10的空列表、構(gòu)造一個指定初始容量的空列表以及構(gòu)造一個包含指定collection的元素的列表,這些元素按照該collection的迭代器返回它們的順序排列的。

/**
 * 構(gòu)造一個具有指定初始容量的空列表。
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    }
}
/**
 * 構(gòu)造一個默認初始容量為10的空列表
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
 * 構(gòu)造一個包含指定集合元素的列表,按照集合的迭代器返回的順序。
 */
public ArrayList(Collection<? extends E> c) {
    Object[] a = c.toArray();
    if ((size = a.length) != 0) {
        if (c.getClass() == ArrayList.class) {
            elementData = a;
        } else {
            elementData = Arrays.copyOf(a, size, Object[].class);
        }
    } else {
        // 替換為空數(shù)組。
        elementData = EMPTY_ELEMENTDATA;
    }
}

3) 元素存儲:

ArrayList提供了set(int index, E element)、add(E e)、add(int index, E element)、addAll(Collection<? extends E> c)、addAll(int index, Collection<? extends E> c)這些添加元素的方法。

下面我們一一講解:

// 用指定的元素替代此列表中指定位置上的元素,并返回以前位于該位置上的元素。
public E set(int index, E element) {
    RangeCheck(index);
    E oldValue = (E) elementData[index];
    elementData[index] = element;
    return oldValue;
}
// 將指定的元素添加到此列表的尾部。
public boolean add(E e) {
    // 增加modCount
    ensureCapacity(size + 1);
    elementData[size++] = e;
    return true;
}
// 將指定的元素插入此列表中的指定位置。
// 如果當前位置有元素,則向右移動位于該位置的元素及所有后續(xù)元素(其索引加1)。
public void add(int index, E element) {
    // if (index > size || index < 0)
    //    throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
    rangeCheckForAdd(index);
    // 如果數(shù)組長度不足,將進行擴容。
    ensureCapacity(size + 1); // 增加modCount
    // 將 elementData中從Index位置開始、長度為size-index的元素,
    // 拷貝到從下標為index+1位置開始的新的elementData數(shù)組中。
    // 即將當前位于該位置的元素以及所有后續(xù)元素右移一個位置。
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
    elementData[index] = element;
    size++;
}
// 按照指定collection的迭代器所返回的元素順序,將該collection中的所有元素添加到此列表的尾部。
public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacity(size + numNew); // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}
// 從指定的位置開始,將指定collection中的所有元素插入到此列表中。
public boolean addAll(int index, Collection<? extends E> c) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacity(size + numNew); // 增加modCount
    int numMoved = size - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
    System.arraycopy(a, 0, elementData, index, numNew);
    size += numNew;
    return numNew != 0;
}

ArrayList是基于數(shù)組實現(xiàn)的,屬性中也看到了數(shù)組,具體是怎么實現(xiàn)的呢?

比如就這個添加元素的方法,如果數(shù)組大,則在將某個位置的值設(shè)置為指定元素即可,如果數(shù)組容量不夠了呢?

看到add(E e)中先調(diào)用了ensureCapacity(size+1)方法,之后將元素的索引賦給elementData[size], 而后size自增。

例如初次添加時,size為0,add將elementData[0]賦值為e,然后size設(shè)置為1(類似執(zhí)行以下兩條語句elementData[0]=e;size=1)。

將元素的索引賦給elementData[size]不是會出現(xiàn)數(shù)組越界的情況嗎?這里關(guān)鍵就在ensureCapacity(size+1)中了。

4) 元素讀?。?/h3>
// 返回此列表中指定位置的元素。
public E get(int index) {
   rangeCheck(index);
   return elementData(index);
}

5) 元素刪除:

ArrayList提供了根據(jù)下標或者指定對象兩種方式的刪除功能。

如下:

// 刪除此列表中指定位置的元素。將任何后續(xù)元素向左移動(從它們的索引中減去一個)。    
public E remove(int index) {
   rangeCheck(index);
   modCount++;
   E oldValue = elementData(index);
   int numMoved = size - index - 1;
   if (numMoved > 0)
       System.arraycopy(elementData, index+1, elementData, index, numMoved);
   elementData[--size] = null; // clear to let GC do its work
   return oldValue;
}

首先是檢查范圍,修改modCount,保留將要被移除的元素,將移除位置之后的元素向前挪動一個位置,將list末尾元素置空(null),返回被移除的元素。

// 從此列表中刪除第一次出現(xiàn)的指定元素(如果存在)。如果列表不包含該元素,則保持不變。 
public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}
// 私有刪除方法,跳過邊界檢查并且不返回刪除的值。
private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index, numMoved);
    elementData[--size] = null; 
}

首先通過代碼可以看到,當移除成功后返回true,否則返回 false。remove(Object o)中通過遍歷 element 尋找是否存在傳入對象,一旦找到就調(diào)用 fastRemove 移除對象。

為什么找到了元素就知道了index,不通過remove(index) 來移除元素呢?

因為 fastRemove 跳過了判斷邊界的處理,找到元素就相當于確定了 index 不會超過邊界,而且 fastRemove 并不返回被移除的元素。

// 從此列表中刪除索引介于兩者之間的所有元素    
protected void removeRange(int fromIndex, int toIndex) {
    modCount++;
    int numMoved = size - toIndex;
    System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
    int newSize = size - (toIndex-fromIndex);
    for (int i = newSize; i < size; i++) {
        elementData[i] = null;
    }
    size = newSize;
}

執(zhí)行過程是將 elementData 從 toIndex 位置開始的元素向前移動到 fromIndex,然后將 toIndex 位置之后的元素全部置空順便修改size。

這個方法是protected,及受保護的方法,為什么這個方法被定義為protected呢? 先看下面這個例子

ArrayList<Integer> ints = new ArrayList<Integer>(Arrays.asList(0, 1, 2, 3, 4, 5, 6));
ints.subList(2, 4).clear();
System.out.println(ints);

輸出結(jié)果是[0, 1, 4, 5, 6],結(jié)果是不是像調(diào)用了 removeRange(int fromIndex,int toIndex)!

6) 調(diào)整數(shù)組容量ensureCapacity:

從上面介紹的向ArrayList中存儲元素的代碼中,我們看到,每當向數(shù)組中添加元素時,都要去檢查添加后元素的個數(shù)是否會超出當前數(shù)組的長度,如果超出,數(shù)組將會進行擴容,以滿足添加數(shù)據(jù)的需求。

數(shù)組擴容通過一個公開的方法 ensureCapacity(int minCapacity) 來實現(xiàn)。

在實際添加大量元素前,我也可以使用ensureCapacity來手動增加ArrayList實例的容量,以減少遞增式再分配的數(shù)量。

public void ensureCapacity(int minCapacity) {
   modCount++;
   int oldCapacity = elementData.length;
   if (minCapacity > oldCapacity) {
       Object oldData[] = elementData;
       int newCapacity = (oldCapacity * 3) / 2 + 1; // 增加50%+1
       if (newCapacity < minCapacity)
           newCapacity = minCapacity;
       // 通常接近 size
       elementData = Arrays.copyOf(elementData, newCapacity);
   }
}

從上述代碼中可以看出,數(shù)組進行擴容時,會將老數(shù)組中的元素重新拷貝一份到新的數(shù)組中,每次數(shù)組 容量的增長大約是其原容量的1.5倍。

這種操作的代價是很高的,因此在實際使用時,我們應(yīng)該盡量避 免數(shù)組容量的擴張。

當我們可預(yù)知要保存的元素的多少時,要在構(gòu)造ArrayList實例時,就指定其容量, 以避免數(shù)組擴容的發(fā)生。

或者根據(jù)實際需求,通過調(diào)用ensureCapacity方法來手動增加ArrayList實例的容量。

// 為什么要用到
oldData[]Object oldData[] = elementData;

乍一看來后面并沒有用到關(guān)于oldData, 這句話顯得多此一舉!但是這是一個牽涉到內(nèi)存管理的類, 所以要 了解內(nèi)部的問題 。

而且為什么這一句還在if的內(nèi)部,這跟 elementData = Arrays.copyOf(elementData, newCapacity); 這句是有關(guān)系的,下面這句Arrays.copyOf的實現(xiàn)時新創(chuàng)建了newCapacity大小的內(nèi)存,然后把老的elementData放入。

好像也沒有用到oldData,有什么問題 呢。

問題就在于舊的內(nèi)存的引用是elementData, elementData指向了新的內(nèi)存塊,如果有一個局部變量oldData變量引用舊的內(nèi)存塊的話,在copy的過程中就會比較安全,因為這樣證明這塊老的內(nèi)存依 然有引用,分配內(nèi)存的時候就不會被侵占掉,然后copy完成后這個局部變量的生命期也過去了,然后釋放才是安全的。

不然在copy的的時候萬一新的內(nèi)存或其他線程的分配內(nèi)存侵占了這塊老的內(nèi)存,而 copy 還沒有結(jié)束,這將是個嚴重的事情。

ArrayList還給我們提供了將底層數(shù)組的容量調(diào)整為當前列表保存的實際元素的大小的功能。

它可以通過trimToSize方法來實現(xiàn)。

代碼如下:

// 將此ArrayList實例的容量修剪為列表的當前大小??梢允褂么瞬僮鱽碜钚』疉rrayList實例的存儲空間。    
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size);
    }
}

由于elementData的長度會被拓展,size標記的是其中包含的元素的個數(shù)。

所以會出現(xiàn)size很小但elementData.length很大的情況,將出現(xiàn)空間的浪費。

trimToSize將返回一個新的數(shù)組給elementData,元素內(nèi)容保持不變,length和size相同,節(jié)省空間。

7) 轉(zhuǎn)為靜態(tài)數(shù)組toArray

注意ArrayList的兩個轉(zhuǎn)化為靜態(tài)數(shù)組的toArray方法。

第一個,調(diào)用Arrays.copyOf將返回一個數(shù)組,數(shù)組內(nèi)容是size個elementData的元素,即拷貝

elementData從0至size-1位置的元素到新數(shù)組并返回。

// 返回一個數(shù)組,該數(shù)組以適當?shù)捻樞虬肆斜碇械乃性亍?   
public Object[] toArray() {    return Arrays.copyOf(elementData, size);}

第二個,如果傳入數(shù)組的長度小于size,返回一個新的數(shù)組,大小為size,類型與傳入數(shù)組相同。

所傳入數(shù)組長度與size相等,則將elementData復(fù)制到傳入數(shù)組中并返回傳入的數(shù)組。

若傳入數(shù)組長度大于size,除了復(fù)制elementData外,還將把返回數(shù)組的第size個元素置為空。

/* 以適當?shù)捻樞蚍祷匾粋€包含此列表中所有元素的數(shù)組;
返回數(shù)組的運行時類型是指定數(shù)組的類型。
如果列表適合指定的數(shù)組,則在其中返回。
否則將使用指定數(shù)組的運行時類型和此列表的大小分配一個新數(shù)組。*/     
public <T> T[] toArray(T[] a) {
   if (a.length < size)
       // 創(chuàng)建一個運行時類型的新數(shù)組
       return (T[]) Arrays.copyOf(elementData, size, a.getClass());
   System.arraycopy(elementData, 0, a, 0, size);
   if (a.length > size)
       a[size] = null;
   return a;
}

Fail-Fast機制:

ArrayList也采用了快速失敗的機制,通過記錄modCount參數(shù)來實現(xiàn)。

在面對并發(fā)的修改時,迭代器很快就會完全失敗,而不是冒著在將來某個不確定時間發(fā)生任意不確定行為的風險

總結(jié)

關(guān)于ArrayList的源碼,給出幾點比較重要的總結(jié):

  • 注意其三個不同的構(gòu)造方法。無參構(gòu)造方法構(gòu)造的ArrayList的容量默認為10,帶有Collection參數(shù)的構(gòu)造方法,將Collection轉(zhuǎn)化為數(shù)組賦給ArrayList的實現(xiàn)數(shù)組elementData。
  • 注意擴充容量的方法ensureCapacity。ArrayList在每次增加元素(可能是1個,也可能是一組) 時,都要調(diào)用該方法來確保足夠的容量。當容量不足以容納當前的元素個數(shù)時,就設(shè)置新的容量為舊的 容量的1.5倍加1,如果設(shè)置后的新容量還不夠,則直接新容量設(shè)置為傳入的參數(shù)(也就是所需的容量),而后用Arrays.copyof()方法將元素拷貝到新的數(shù)組。從中可以看出,當容 量不夠時,每次增加元素,都要將原來的元素拷貝到一個新的數(shù)組中,非常之耗時,也因此建議在事先 能確定元素數(shù)量的情況下,才使用ArrayList,否則建議使用LinkedList。
  • ArrayList的實現(xiàn)中大量地調(diào)用了 Arrays.copyOf() 和 System.arrayCopy() 方法。

我們有必要對這兩個方法的實現(xiàn)做下深入的了解。

先看Arrays.copyof()方法,它有很多個重載的方法,但實現(xiàn)思路都是一樣的,看看泛型版本的源碼:

復(fù)制指定的數(shù)組,用空值截斷或填充(如有必要),使副本具有指定的長度。

對于在原始數(shù)組和副本中都有效的所有索引,這兩個數(shù)組將包含相同的值。對于副本中有效但不是原始索引的任何索引,副本將包含null。

當且僅當指定的長度大于原始數(shù)組的長度時,此類索引才會存在。// 生成的數(shù)組與原始數(shù)組的類完全相同。  

  public static <T> T[] copyOf(T[] original, int newLength) {   
    return (T[]) copyOf(original, newLength, original.getClass());
  }

很明顯調(diào)用了另一個copyOf方法,該方法有三個參數(shù),最后一個參數(shù)指明要轉(zhuǎn)換的數(shù)據(jù)的類型,其源碼 如下:

// newType類
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {    
    @SuppressWarnings("unchecked")    
    T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength]: (T[]) 
    Array.newInstance(newType.getComponentType(), newLength);    
    System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));    
    return copy;
}

這里可以很明顯地看出,該方法實際上是在其內(nèi)部又創(chuàng)建了一個長度為newlength的數(shù)組,調(diào)用

System.arrayCopy()方法,將原來數(shù)組中的元素復(fù)制到了新的數(shù)組中。

下面來看System.arrayCopy()方法。該方法被標記了native,調(diào)用了系統(tǒng)的C/C++代碼,在JDK中是看不到的,但在openJDK中可以看到其源碼。該函數(shù)實際上最終調(diào)用了C語言的memmove()函數(shù),因此它可以保證同一個數(shù)組內(nèi)元素的正確復(fù)制和移動,比一般的復(fù)制方法的實現(xiàn)效率要高很多,很適合用來批量處理數(shù)組。

Java強烈推薦在復(fù)制大量數(shù)組元素時用該方法,以取得更高的效率。

ArrayList基于數(shù)組實現(xiàn),可以通過下標索引直接查找到指定位置的元素,因此查找效率高,但每次插入或刪除元素,就要大量地移動元素,插入刪除元素的效率低。

在查找給定元素索引值等的方法中,源碼都將該元素的值分為null和不為null兩種情況處理, ArrayList中允許元素為null。

到此這篇關(guān)于Java中ArrayList實現(xiàn)原理及基本方法的文章就介紹到這了,更多相關(guān)ArrayList實現(xiàn)原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java實現(xiàn)文件上傳、下載、圖片預(yù)覽

    java實現(xiàn)文件上傳、下載、圖片預(yù)覽

    這篇文章主要介紹了java實現(xiàn)文件上傳、下載、圖片預(yù)覽,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • 利用Java實現(xiàn)簡單的猜數(shù)字小游戲

    利用Java實現(xiàn)簡單的猜數(shù)字小游戲

    這篇文章主要為大家詳細介紹了如何利用java語言實現(xiàn)猜數(shù)字小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Spring?Boot面試必問之啟動流程知識點詳解

    Spring?Boot面試必問之啟動流程知識點詳解

    SpringBoot是Spring開源組織下的子項目,是Spring組件一站式解決方案,主要是簡化了使用Spring的難度,簡省了繁重的配置,提供了各種啟動器,開發(fā)者能快速上手,這篇文章主要給大家介紹了關(guān)于Spring?Boot面試必問之啟動流程知識點的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • Spring Boot連接超時導(dǎo)致502錯誤的實戰(zhàn)案例

    Spring Boot連接超時導(dǎo)致502錯誤的實戰(zhàn)案例

    這篇文章主要給大家介紹了關(guān)于Spring Boot連接超時導(dǎo)致502錯誤的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java Socket 編程詳解

    Java Socket 編程詳解

    Java Socket 編程是指使用 Java 語言進行網(wǎng)絡(luò)通信的過程,包括建立連接、傳輸數(shù)據(jù)和關(guān)閉連接等操作,本文將詳細介紹Java Socket編程,需要的朋友可以參考下
    2023-05-05
  • springboot通過jar包啟動中文日志亂碼問題及解決

    springboot通過jar包啟動中文日志亂碼問題及解決

    這篇文章主要介紹了springboot通過jar包啟動中文日志亂碼問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 使用IDEA創(chuàng)建SpringBoot項目的方法步驟

    使用IDEA創(chuàng)建SpringBoot項目的方法步驟

    這篇文章主要介紹了使用IDEA創(chuàng)建SpringBoot項目的方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • 詳解springmvc常用5種注解

    詳解springmvc常用5種注解

    在本篇里我們給大家總結(jié)了關(guān)于springmvc常用5種注解相關(guān)知識點以及實例代碼,需要的朋友們參考下。
    2019-07-07
  • JWT在OpenFeign調(diào)用中進行令牌中繼詳解

    JWT在OpenFeign調(diào)用中進行令牌中繼詳解

    Feign是一個聲明式的Web Service客戶端,是一種聲明式、模板化的HTTP客戶端。而OpenFeign是Spring Cloud 在Feign的基礎(chǔ)上支持了Spring MVC的注解,如@RequesMapping等等,這篇文章主要給大家介紹了關(guān)于JWT在OpenFeign調(diào)用中進行令牌中繼的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • Java常用正則表達式驗證工具類RegexUtils.java

    Java常用正則表達式驗證工具類RegexUtils.java

    相信大家對正則表達式一定都有所了解和研究,這篇文章主要為大家分享了Java 表單注冊常用正則表達式驗證工具類,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11

最新評論