分類
發燒車訊

【集合系列】- 初探java集合框架圖

一、集合類簡介

Java集合就像一種容器,可以把多個對象(實際上是對象的引用,但習慣上都稱對象)“丟進”該容器中。從Java 5 增加了泛型以後,Java集合可以記住容器中對象的數據類型,使得編碼更加簡潔、健壯。

Java集合大致可以分為兩大體系,一個是Collection,另一個是Map

  • Collection :主要由List、Set、Queue接口組成,List代表有序、重複的集合;其中Set代表無序、不可重複的集合;Java 5 又增加了Queue體系集合,代表一種隊列集合實現。
  • Map:則代表具有映射關係的鍵值對集合。

java.util.Collection下的接口和繼承類關係簡易結構圖:

java.util.Map下的接口和繼承類關係簡易結構圖:

其中,Java 集合框架中主要封裝的是典型的數據結構和算法,如動態數組、雙向鏈表、隊列、棧、Set、Map 等。

將集合框架挖掘處理,可以分為以下幾個部分
1) 數據結構
List列表、Queue隊列、Deque雙端隊列、Set集合、Map映射
2) 比較器
Comparator比較器、Comparable排序接口
3) 算法
Collections常用算法類、Arrays靜態數組的排序、查找算法
4) 迭代器
Iterator通用迭代器、ListIterator針對 List 特化的迭代器

二、有序列表(List)

List集合的特點就是存取有序,可以存儲重複的元素,可以用下標進行元素的操作

List主要實現類:ArrayList、LinkedList、Vector、Stack。

2.1、ArrayList

ArrayList是一個動態數組結構,支持隨機存取,尾部插入刪除方便,內部插入刪除效率低(因為要移動數組元素);如果內部數組容量不足則自動擴容,因此當數組很大時,效率較低。

2.2、LinkedList

LinkedList是一個雙向鏈表結構,在任意位置插入刪除都很方便,但是不支持隨機取值,每次都只能從一端開始遍歷,直到找到查詢的對象,然後返回;不過,它不像 ArrayList 那樣需要進行內存拷貝,因此相對來說效率較高,但是因為存在額外的前驅和後繼節點指針,因此佔用的內存比 ArrayList 多一些。

2.3、Vector

Vector也是一個動態數組結構,一個元老級別的類,早在jdk1.1就引入進來類,之後在jdk1.2里引進ArrayList,ArrayList大部分的方法和Vector比較相似,兩者是不同的,Vector是允許同步訪問的,Vector中的操作是線程安全的,但是效率低,而ArrayList所有的操作都是異步的,執行效率高,但不安全!

關於Vector,現在用的很少了,因為裏面的getsetadd等方法都加了synchronized,所以,執行效率會比較低,如果需要在多線程中使用,可以採用下面語句創建ArrayList對象

List<Object> list =Collections.synchronizedList(new ArrayList<Object>());

也可以考慮使用複製容器 java.util.concurrent.CopyOnWriteArrayList進行操作,例如:

final CopyOnWriteArrayList<Object> cowList = new CopyOnWriteArrayList<String>(Object);

2.4、Stack

Stack是Vector的一個子類,本質也是一個動態數組結構,不同的是,它的數據結構是先進后出,取名叫棧!

關於Stack,現在用的也很少,因為有個ArrayDeque雙端隊列,可以替代Stack所有的功能,並且執行效率比它高!

三、集(Set)

Set集合的特點:元素不重複,存取無序,無下標;

Set主要實現類:HashSet、LinkedHashSet和TreeSet。

3.1、HashSet

HashSet底層是基於 HashMap 的k實現的,元素不可重複,特性同 HashMap。

3.2、LinkedHashSet

LinkedHashSet底層也是基於 LinkedHashMap 的k實現的,一樣元素不可重複,特性同 LinkedHashMap。

3.3、TreeSet

同樣的,TreeSet也是基於 TreeMap 的k實現的,同樣元素不可重複,特性同 TreeMap;

Set集合的實現,基本都是基於Map中的鍵做文章,使用Map中鍵不能重複、無序的特性;所以,我們只需要重點關注Map的實現即可!

四、隊列(Queue)

Queue是一個隊列集合,隊列通常是指“先進先出”(FIFO)的容器。新元素插入(offer)到隊列的尾部,訪問元素(poll)操作會返回隊列頭部的元素。通常,隊列不允許隨機訪問隊列中的元素。

Queue主要實現類:ArrayDeque、LinkedList、PriorityQueue。

4.1、ArrayDeque

ArrayQueue是一個基於數組實現的雙端隊列,可以想象,在隊列中存在兩個指針,一個指向頭部,一個指向尾部,因此它具有“FIFO隊列”及“棧”的方法特性。

既然是雙端隊列,那麼既可以先進先出,也可以先進后出,以下是測試例子!

先進先出

public static void main(String[] args) {
                ArrayDeque<String> queue = new ArrayDeque<>();
        //入隊
        queue.offer("AAA");
        queue.offer("BBB");
        queue.offer("CCC");
        System.out.println(queue);
        //獲取但不出隊
        System.out.println(queue.peek());
        System.out.println(queue);
        //出隊
        System.out.println(queue.poll());
        System.out.println(queue);
}

輸出結果:

[AAA, BBB, CCC]
AAA
[AAA, BBB, CCC]
AAA
[BBB, CCC]

先進后出

public static void main(String[] args) {
                ArrayDeque<String> stack = new ArrayDeque<>();
        //壓棧,此時AAA在最下,CCC在最外
        stack.push("AAA");
        stack.push("BBB");
        stack.push("CCC");
        System.out.println(stack);
        //獲取最後添加的元素,但不刪除
        System.out.println(stack.peek());
        System.out.println(stack);
        //彈出最後添加的元素
        System.out.println(stack.pop());
        System.out.println(stack);
}

輸出結果:

[CCC, BBB, AAA]
CCC
[CCC, BBB, AAA]
CCC
[BBB, AAA]

4.2、LinkedList

LinkedList是List接口的實現類,也是Deque的實現類,底層是一種雙向鏈表的數據結構,在上面咱們也有所介紹,LinkedList可以根據索引來獲取元素,增加或刪除元素的效率較高,如果查找的話需要遍歷整合集合,效率較低,LinkedList同時實現了stack、Queue、PriorityQueue的所有功能。

例子

public static void main(String[] args) {
                LinkedList<String> ll = new LinkedList<>();
        //入隊
        ll.offer("AAA");
        //壓棧
        ll.push("BBB");
        //雙端的另一端入隊
        ll.addFirst("NNN");
        ll.forEach(str -> System.out.println("遍歷中:" + str));
        //獲取隊頭
        System.out.println(ll.peekFirst());
        //獲取隊尾
        System.out.println(ll.peekLast());
        //彈棧
        System.out.println(ll.pop());
        System.out.println(ll);
        //雙端的後端出列
        System.out.println(ll.pollLast());
        System.out.println(ll);
}

輸出結果:

遍歷中:NNN
遍歷中:BBB
遍歷中:AAA
NNN
AAA
NNN
[BBB, AAA]
AAA
[BBB]

4.3、PriorityQueue

PriorityQueue也是一個隊列的實現類,此實現類中存儲的元素排列並不是按照元素添加的順序進行排列,而是內部會按元素的大小順序進行排列,是一種能夠自動排序的隊列。

例子

public static void main(String[] args) {
        PriorityQueue<Integer> queue1 = new PriorityQueue<>(10);

        System.out.println("處理前的數據");
        Random rand = new Random();
        for (int i = 0; i < 10; i++) {
                Integer num = rand.nextInt(90) + 10;
                System.out.print(num + ", ");
            queue1.offer(num); // 隨機兩位數
        }

        System.out.println("\n處理后的數據");
        for (int i = 0; i < 10; i++) { // 默認是自然排序 [升序]
            System.out.print(queue1.poll() + ", ");
        }
}

輸出結果:

處理前的數據
36, 23, 24, 11, 12, 26, 79, 96, 14, 73, 
處理后的數據
11, 12, 14, 23, 24, 26, 36, 73, 79, 96, 

五、映射表(Map)

Map是一個雙列集合,其中保存的是鍵值對,鍵要求保持唯一性,值可以重複。

Map 主要實現類:HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties。

5.1、HashMap

關於HashMap,相信大家都不陌生,繼承自AbstractMap,key 不可重複,因為使用的是哈希表存儲元素,所以輸入的數據與輸出的數據,順序基本不一致,另外,HashMap最多只允許一條記錄的 key 為 null。

5.2、LinkedHashMap

HashMap 的子類,內部使用鏈表數據結構來記錄插入的順序,使得輸入的記錄順序和輸出的記錄順序是相同的。LinkedHashMap與HashMap最大的不同處在於,LinkedHashMap輸入的記錄和輸出的記錄順序是相同的!

5.3、TreeMap

能夠把它保存的記錄根據鍵排序,默認是按鍵值的升序排序,也可以指定排序的比較器,當用 Iterator 遍歷時,得到的記錄是排過序的;如需使用排序的映射,建議使用 TreeMap。TreeMap實際使用的比較少!

5.4、IdentityHashMap

繼承自AbstractMap,與HashMap有些不同,在獲取元素的時候,通過==代替equals ()來進行判斷,比較的是內存地址

get方法源碼部分

public V get(Object key) {
        Object k = maskNull(key);
        Object[] tab = table;
        int len = tab.length;
        int i = hash(k, len);
        while (true) {
            Object item = tab[i];
            //用==比較k和元素是否相等
            if (item == k)
                return (V) tab[i + 1];
            if (item == null)
                return null;
            i = nextKeyIndex(i, len);
        }
}

5.5、WeakHashMap

WeakHashMap繼承自AbstractMap,被稱為緩存Map,向WeakHashMap中添加元素,再次通過鍵調用方法獲取元素方法時,不一定獲取到元素值,因為WeakHashMap 中的 Entry 可能隨時被 GC 回收。

5.6、Hashtable

Hashtable,一個元老級的類,鍵值不能為空,與HashMap不同的是,方法都加了synchronized同步鎖,是線程安全的,但是效率上,沒有HashMap快!

同時,HashMap 是 HashTable 的輕量級實現,他們都完成了Map 接口,區別在於 HashMap 允許K和V為空,而HashTable不允許K和V為空,由於非線程安全,效率上可能高於 Hashtable。

如果需要在多線程環境下使用HashMap,可以使用如下的同步器來實現或者使用併發工具包中的ConcurrentHashMap

Map<String, Object> map =Collections.synchronizedMap(new HashMap<>());

5.7、Properties

Properties繼承自HashTable,Properties新增了load()和和store()方法,可以直接導入或者將映射寫入文件,另外,Properties的鍵和值都是String類型。

六、比較器

Comparable和Comparator接口都是用來比較大小的,一般在TreeSet、TreeMap接口中使用的比較多,主要用於解決排序問題。

6.1、Comparable

Comparable:對實現它的每個類的對象進行整體排序

package java.lang;
import java.util.*;

public interface Comparable<T> {
    public int compareTo(T o);
}

若一個類實現了Comparable 接口,實現 Comparable 接口的類的對象的 List 列表 ( 或數組)可以通過 Collections.sort(或 Arrays.sort)進行排序。

此外,實現 Comparable 接口的類的對象 可以用作 “有序映射 ( 如 TreeMap)” 中的鍵或 “有序集合 (TreeSet)” 中的元素,而不需要指定比較器。

使用例子:

/**
  * 實體類Person實現Comparable接口
  */
public class Person implements Comparable<Person>{
    private int age;
    private String name;

    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    
    @Override
    public int compareTo(Person o){
        return this.age-o.age;
    }
    
    @Override
    public String toString(){
        return name+":"+age;
    }
}

測試

public static void main(String[] args) {
        Person person1 = new Person("張三",18);
        Person person2 = new Person("李四",17);
        Person person3 = new Person("王五",19);

        List<Person> list = new ArrayList<>();
        list.add(person1);
        list.add(person2);
        list.add(person3);

        System.out.println(list);
        Collections.sort(list);
        System.out.println(list);
}

輸出:

[張三:18, 李四:17, 王五:19]
[李四:17, 張三:18, 王五:19]
6.2、Comparator

Comparator:也是對實現它的每個類的對象進行排序

package java.util;
import ***;

public interface Comparator<T> {
    int compare(T o1, T o2);
    ......
}

如果我們的這個類Person無法修改或者沒有繼承Comparable接口,我們又要對其進行排序,Comparator就可以派上用場了。

將類Person實現的Comparable接口去掉

/**
  * 實體類Person
  */
public class Person {
    private int age;
    private String name;
    
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString(){
        return name+":"+age;
    }
}

測試類:

public static void main(String[] args) {
        Person person1 = new Person("張三",18);
        Person person2 = new Person("李四",17);
        Person person3 = new Person("王五",19);

        List<Person> list = new ArrayList<>();
        list.add(person1);
        list.add(person2);
        list.add(person3);

        System.out.println(list);
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                if(o1 == null || o2 == null){
                    return 0;
                }
                //o1比o2小,返回負數
                //o1等於o2,等於0
                //o1大於o2,返回正數
                return o1.getAge()-o2.getAge();
            }
        });
        System.out.println(list);
}

輸出:

[張三:18, 李四:17, 王五:19]
[李四:17, 張三:18, 王五:19]

七、常用工具類

7.1、Collections類

java.util.Collections工具類為集合框架提供了很多有用的方法,這些方法都是靜態的,在編程中可以直接調用。整個Collections工具類源碼差不多有4000行,這裏只針對一些典型的方法進行闡述。

7.1.1、addAll

addAll:向指定的集合c中加入特定的一些元素elements

public static <T> boolean addAll(Collection<? super T> c, T… elements)
7.1.2、binarySearch

binarySearch:利用二分法在指定的集合中查找元素

#集合元素T實現Comparable接口的方式,進行查詢
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)

#元素以外部實現Comparator接口的方式,進行查詢
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
7.1.3、sort
#集合元素T實現Comparable接口的方式,進行排序
public static <T extends Comparable<? super T>> void sort(List<T> list)

#元素以外部實現Comparator接口的方式,進行排序
public static <T> void sort(List<T> list, Comparator<? super T> c)
7.1.4、shuffle

shuffle:混排,隨機打亂原來的順序,它打亂在一個List中可能有的任何排列的蹤跡。

#方法一
public static void shuffle(List<?> list)

#方法二,指定隨機數訪問
public static void shuffle(List<?> list, Random rnd)
7.1.5、reverse

reverse:集合排列反轉

#直接反轉集合的元素
public static void reverse(List<?> list)

#返回可以使集合反轉的比較器Comparator
public static <T> Comparator<T> reverseOrder()

#集合的反轉的反轉,如果cmp不為null,返回cmp的反轉的比較器,如果cmp為null,效果等同於第二個方法.
public static <T> Comparator<T> reverseOrder(Comparator<T> cmp)
7.1.6、synchronized系列

synchronized系列:確保所封裝的集合線程安全(強同步)

#同步Collection接口下的實現類
public static <T> Collection<T> synchronizedCollection(Collection<T> c)

#同步SortedSet接口下的實現類
public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)

#同步List接口下的實現類
public static <T> List<T> synchronizedList(List<T> list)

#同步Map接口下的實現類
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)

#同步SortedMap接口下的實現類
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)

7.2、Arrays類

java.util.Arrays工具類也為集合框架提供了很多有用的方法,這些方法都是靜態的,在編程中可以直接調用。整個Arrays工具類源碼有3000多行,這裏只針對一些典型的方法進行闡述。

7.2.1、asList

asList:將一個數組轉變成一個List,準確來說是ArrayList

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
}

注意:這個List是定長的,企圖添加或者刪除數據都會報錯java.lang.UnsupportedOperationException

7.2.2、sort

sort:對數組進行排序,適合byte,char,double,float,int,long,short等基本類型,還有Object類型

#基本數據類型,例子int類型數組
public static void sort(int[] a)

#Object類型數組
#如果使用Comparable進行排序,Object需要實現Comparable
#如果使用Comparator進行排序,可以使用外部比較方法實現
public static void sort(Object[] a)
7.2.3、binarySearch

binarySearch:通過二分查找法對已排序的數組進行查找。如果數組沒有經過Arrays.sort排序,那麼檢索結果未知。

適合byte,char,double,float,int,long,short等基本類型,還有Object類型和泛型。

#基本數據類型,例子int類型數組,key為要查詢的參數
public static int binarySearch(int[] a, int key)

#Object類型數組,key為要查詢的參數
#如果使用Comparable進行排序,Object需要實現Comparable
#如果使用Comparator進行排序,可以使用外部比較方法實現
public static int binarySearch(Object[] a, Object key)
7.2.4、copyOf

copyOf:數組拷貝,底層採用System.arrayCopy(native方法)實現。

適合byte,char,double,float,int,long,short等基本類型,還有泛型數組。

#基本數據類型,例子int類型數組,newLength新數組長度
public static int[] copyOf(int[] original, int newLength)

#T為泛型數組,newLength新數組長度
public static <T> T[] copyOf(T[] original, int newLength)
7.2.5、copyOfRange

copyOfRange:數組拷貝,指定一定的範圍,底層採用System.arrayCopy(native方法)實現。

適合byte,char,double,float,int,long,short等基本類型,還有泛型數組。

#基本數據類型,例子int類型數組,from:開始位置,to:結束位置
public static int[] copyOfRange(int[] original, int from, int to)

#T為泛型數組,from:開始位置,to:結束位置
public static <T> T[] copyOfRange(T[] original, int from, int to)
7.2.6、equals和deepEquals

equals:判斷兩個數組的每一個對應的元素是否相等(equals, 對於兩個數組的元素a和a2有a==null ? a2==null : a.equals(a2))

#基本數據類型,例子int類型數組,a為原數組,a2為目標數組
public static boolean equals(int[] a, int[] a2)

#Object數組,a為原數組,a2為目標數組
public static boolean equals(Object[] a, Object[] a2)

deepEquals:主要針對一個數組中的元素還是數組的情況(多維數組比較)

#Object數組,a1為原數組,a2為目標數組
public static boolean deepEquals(Object[] a1, Object[] a2)
7.2.7、toString和deepToString

toString:將數組轉換成字符串,中間用逗號隔開

#基本數據類型,例子int類型數組,a為數組
public static String toString(int[] a)

#Object數組,a為數組
public static String toString(Object[] a)

deepToString:當數組中又包含數組,就不能單純的利用Arrays.toString()了,使用此方法將數組轉換成字符串

#Object數組,a為數組
public static String deepToString(Object[] a)

八、迭代器

JCF的迭代器(Iterator)為我們提供了遍歷容器中元素的方法。只有容器本身清楚容器里元素的組織方式,因此迭代器只能通過容器本身得到。每個容器都會通過內部類的形式實現自己的迭代器。

ArrayList<String> list = new ArrayList<String>();
list.add(new String("a1"));
list.add(new String("a2"));
list.add(new String("a3"));
Iterator<String> it = list.iterator();//得到迭代器
while(it.hasNext()){
    String obj = it.next();//訪問元素
    System.out.println(obj);
}

JDK 1.5 引入了增強的for循環,簡化了迭代容器時的寫法

//使用增強for迭代
ArrayList<String> list = new ArrayList<String>();
list.add(new String("a1"));
list.add(new String("a2"));
list.add(new String("a3"));
for(String obj : list){
    //enhanced for statement
    System.out.println(obj);
}

九、總結

以上,主要是對java集合的整體架構進行簡單的介紹,如果有理解不當之處,歡迎指正。

十、參考

1、JDK1.7&JDK1.8 源碼
2、
3、

作者:炸雞可樂
原文出處:

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

分類
發燒車訊

澳洲野火 煙雲飄1萬2000多公里觸及巴西

摘錄自2020年1月8日中央社報導

澳洲野火延燒,巴西國家太空署(National Institute for Space Research, INPE)旗下的遙測部門今天推文表示,野火煙霾今天觸及巴西。

遙測部門(Department of Remote Sensing)指著衛星影像說,澳洲大火煙霾一路飄洋過海來到巴西最南端的南大河州(Rio Grande do Sul)。

民間氣象公司MetSul也在推特發文說煙雲抵達南大河州首府快樂港(Porto Alegre),但強調:「從澳洲飄來的煙霾幾乎難以察覺,即使衛星圖顯示大快樂港地區上空被煙霧籠罩。」

智利氣象局昨(6日)表示,智利和阿根廷能看見野火產生的煙霾。這意味著煙雲飄了1萬2000多公里到達南美洲。不過智利氣象局表示,飄來的煙霾並不會對南美居民的健康產生負面影響。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

分類
發燒車訊

LG 化學將在歐洲建電動車用電池新廠 年產能為 5 萬個

車用電池龍頭 LG 化學(LG Chem)23 日宣布,將在車廠密集的歐洲興建一座電動車(EV)用電池工廠,年產能為 5 萬個。報導指出,LG 化學上述 EV 電池新廠的落腳地點雖尚未敲定,不過預估最有可能會選在 LG 電子、LG Display 等韓廠進駐的波蘭弗羅茨瓦夫。   據報導,LG 化學關係人士表示,待上述歐洲電池新廠量產後,將可大幅降低物流費用,屆時將可擴大歐洲市場的供貨規模。   據報導,目前 LG 化學已擁有 2 座電池工廠,分別為南韓忠清北道的梧倉工廠以及美國密西根州工廠,年產能分別為 20 萬個、5 萬個,且 LG 化學位於南京、年產能為 10 萬個的電池新廠也將在年末完工,並預計於 2016 年初開始進行生產。  

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

分類
發燒車訊

深圳取消電動車搖號

僅取消搖號程式,其他條件和程式維持不變   昨日,深圳市小汽車指標調控管理中心發佈公告,調整了今年待配置的電動小汽車增量指標配置方式。即單位和個人申請今年度待配置電動小汽車增量指標的,符合申請條件並通過資格審查後,即直接發放電動小汽車增量指標,不再實施搖號;市公安交警局憑指標證明檔和有關材料辦理電動小汽車 上牌登記手續。值得注意的是,今年待配置電動小汽車增量指標的申請截止日期為12月31日,按照“審核通過時間 優先、申請報名時間優先”的原則配置,指標配置完畢即止。   據瞭解,汽車租賃電動小汽車增量指標的有效期至今年12月31日,逾期未使用的,視為放棄指標,並按照《深圳市小汽車增量調控管理實施細則》的規定,自有效期屆滿次日起,指標持有人兩年內不得申請增量指標。此外,汽車租賃企業還可以根據相關規定申請普通小汽車增量指標和電動小汽車增量指標。   深圳去年底宣佈實施小汽車限購,根據年初公佈的《深圳市小汽車增量調控管理實施細則》,今年全年深圳將配置10萬個小汽車增量指標,其中以搖號方式配置電動小汽車增量指標為2萬個。截至目前,已經進行了8期電動小汽車增量指標搖號,扣除已經成功配置的指標數和剛劃出的2000個分時租賃電動小汽車指標,今年待配置的電動小汽車增量指標還剩9213個。  
337家企業分享4000個租賃電動小汽車指標   昨天,我市舉行了租賃電動小汽車指標搖號,4000個指標全部配置完成,337家企業分享了這些指標。參加本輪搖號的有效編碼數共1057732個。“租賃電動小汽車指標是以企業為申請單位的,每個企業可以申請4000個指標。我們在對申請企業進行資格審核時發現有一個人註冊了35家公司,每個公司都申請了4000個指標。後來我們約談了相關企業,還剔除了部分不符合申請條件的企業,這樣最終符合條件的申請編 碼數達到了1057732個。”     文章來源:深圳特區報 

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

分類
發燒車訊

Windows終端利器Cmder

在IT這一行,大部分情況下都是推薦大家使用Linux或者類Unix操作系統去編程,Linux作為一代優秀的操作系統,已經人盡皆知,在IT行業已經成為核心。有條件的大佬都選擇了使用mac編程,最優秀的莫過於終端體驗了,與Linux完全一致的命令行,帶來了許許多多的方便,但是使用Windows的用戶呢?相信大家都使用過cmd終端,它到底好不好呢。相信大家心中已經有了評判。

一、為什麼要換成cmder

現在我就要推薦一款Windows下的終端—>cmder
先來上兩張圖給大家看看

都不用我說,一眼就能分辨出他倆的區別了,其實他倆最大的區別是cmder完全支持Linux命令行,包括vi,而且可以多開,快捷鍵複製粘貼,分屏等,功能非常強大

二、下載和安裝

1.下載

官網自己下載也可以

  • 在官網下載的時候有兩個版本
    • Mini版本,只有簡單的命令行
    • Full版本,包含git功能(分佈式版本控制系統的git)

我推薦大家安裝Full版本,這樣就可以不用單獨安裝git了

2.安裝

安裝非常簡單,下載完成后,直接解壓到你存放軟件的目錄就好了

然後雙擊一下cmder.exe就可以先簡單體驗一下了

三、個性化設置

這款軟件可以完全替代Windows系統自帶的cmd終端,當然需要一點人性化的設置

1.配置環境變量

我就只上圖了,環境變量配置太過簡單了,百度上太多了,都是通用套路,配置完環境變量,就可以直接在Windows+r鍵里運行cmder打開終端了

上圖中我把git也配置進去了,這樣就不會說git不是內部或者外部命令了

2.配置右鍵菜單啟動

右鍵管理員身份運行cmder.exe,然後把下面的命令複製到cmder中執行一次

// 設置任意地方鼠標右鍵啟動Cmder
Cmder.exe /REGISTER ALL

3.進入設置的方法

右下角的,然後選擇Settings或者直接使用快捷鍵Windows+Alt+p打開設置

如果不習慣英文,可以將設置改成中文

下次再次打開設置,又會中文,只有這個設置生效一次,其他的都可以永久生效

4.設置字體風格等

設置字體的風格,大小等,圖中紅色位置不要勾選,否則會出現cmder終端字體重疊錯位的問題

終端界面的字體大小在設置里可以修改,也可以在終端界面滑動鼠標滾輪,或者觸控板雙擊縮放調整字體大小

5.窗口位置大小記憶

勾選這兩個設置,只需要設置一次,下次會自動記住上次終端在桌面出現的位置和窗口大小

6.設置vi模式下ESC鍵最小化窗口的問題

  • 將圖中紅色改成除了總是的其他選項,否則使用vi時會出現無法切換模式的問題
  • 勾選綠色的選項可以解決打開多個終端,任務欄显示多個窗口的問題

7.解決中文亂碼的問題

在使用ls命令時,中文亂碼的解決方案,將下面的代碼複製到圖中位置

set LANG=zh_CN.UTF-8
set LC_ALL=zh_CN.utf8

8.強製作為默認終端

  • 圖中綠色設置可以強制將cmder註冊成Windows的默認終端

    設置此選項后,系統啟動后就會生效,且,即使你打開的是cmd,也會被放到cmder的窗口中執行

  • 紅色選項可以解決每次關閉控制台時,彈出確認關閉的彈窗

9.解決粘貼多行文本時的彈窗

例如在終端中執行多行SQL語句,總會彈出提示,勾選選項可以解決

10.將命令提示改成$

默認的命令提示符是λ,大家都知道Linux是$,這裏提供一下修改的方法,並不是必須的

1)首先在cmder的安裝目錄下,找到vendor/目錄,然後找到clink.lua文件

2)右鍵使用sublime打開

  • 沒有sublime或者notepad++打開也可以,還沒有的話,記事本也可以的

3)打開后可以Ctrl+F查找下面的字段
local lambda =
4)將local lambda =""的值替換成$

5)保存關閉,重啟終端

11.將Idea的Terminal終端換成cmder

1)在idea中打開其他設置界面,如圖所示

在idea中settings是對當前項目生效,Other Settings是對所有項目生效

2)如圖中修改shell Path的路徑,替換成下面的內容

注意將cmder安裝目錄換成你的安裝目錄

//這種方式比較可靠,避免了環境變量失效的問題
"cmd.exe" /k ""你的cmder安裝目錄\vendor\init.bat""

//或者,這個需要有環境變量
"cmd.exe" /k ""%環境變量配置的cmder home目錄名稱%\vendor\init.bat""

3)再次打開Terminal終端就可以使用Linux命令了

12.將vscode的Terminal終端設置成cmder

1)打開設置

2)搜索code save,點擊打開設置json文件

3)將下面的代碼粘貼到文件中,修改為自己需要的內容

注意修改cmder的安裝目錄為自己的安裝目錄

// 設置終端為cmder
"terminal.integrated.shell.windows": "cmd.exe",
"terminal.integrated.env.windows": {
    //設置cmder的根目錄
    "CMDER_ROOT": "cmder的根目錄"
},
"terminal.integrated.shellArgs.windows": [
    "/k",
    //設置啟動初始化目錄
    "cmder的根目錄\\vendor\\init.bat"
],

//下面的設置可以不需要
//終端顏色配置
"workbench.colorCustomizations": {
    //可以將鼠標放到下面的色號上根據自己的偏好進行選擇
    "terminal.foreground": "#37FF13",
    "terminal.background": "#2b2424"
},
"terminal.integrated.cursorBlinking": true,
//設置terminal中的行高
"terminal.integrated.lineHeight": 1.1,
"terminal.integrated.letterSpacing": 0.1,
"terminal.integrated.fontSize": 12, //字體大小設置
"terminal.integrated.fontFamily": "monaco", //字體設置
"terminal.integrated.shell.linux": "/bin/zsh"

4)Ctrl+J打開終端,就可以使用了

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

分類
發燒車訊

印尼水患災情慘重 雅加達省長遭民眾控告

摘錄自2020年1月14日中央社報導

印尼一名律師今天(14日)表示,在暴雨引發洪水及土石流災情,導致數十人喪命、數千人無家可歸後,雅加達省長阿尼斯(AniesBaswedan)因此被這座大城市的居民控告。

超過200名水患受災民眾昨天在首都雅加達(Jakarta)地方法院提出集體訴訟,尋求總計約430億印尼盾(約新台幣9000萬元)的賠償金。

這起訴訟指出,阿尼斯未能替雅加達這座大型城市提供合適的預警系統及有效的緊急救難措施,好讓人民的性命及財務損失降到最低。

雅加達的法務局沒有立即回應置評請求。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

分類
發燒車訊

二叉搜索樹BST(C語言實現可用)

1:概述

搜索樹是一種可以進行插入,搜索,刪除等操作的數據結構,可以用作字典或優先級隊列。二叉搜索樹是最簡單的搜索樹。其左子樹的鍵值<=根節點的鍵值,右子樹的鍵值>=根節點的鍵值。

如果共有n個元素,那麼每次操作需要的O(log n)的時間.

 

 

 

常用知識點

  • 滿二叉樹 : 一棵深度為k,且有2^k-1個節點的二叉樹,稱為滿二叉樹。這種樹的特點是每一層上的節點數都是最大節點數。
  • 完全二叉樹 : 而在一棵二叉樹中,除最後一層外,若其餘層都是滿的,並且最後一層要麼是滿的,要麼在右邊缺少連續若干節點,則此二叉樹為完全二叉樹。具有n個節點的完全二叉樹的深度為floor(log2n)+1。深度為k的完全二叉樹,至少有2^(k-1)個恭弘=叶 恭弘子節點,至多有2^k-1個節點。

2.基本操作

  1. 查找(search)
  2. 插入(insert)
  3. 刪除(remove)

3:操作原理

  

查找

假設查找的值為x,從根節點的值開始比對,如果小於根節點的值,則往左兒子繼續查找,如果大於根節點的值,則往右兒子繼續查找.依次類推.直到當前節點的值等於要查找的值.

 

  以查找數值10為例

插入

按照查找的步驟即可找到插入值應該在的位置

 

 

以插入數值6為例

刪除:

有四種情況:

1: // 當前節點無左節點 ,右字節點7覆蓋5, 

: 3: // 當前節點無右節點 ,右字節點7覆蓋5, 

 

 : 4: // 刪除節點5的左節點沒有右節點, 只需要8作為3的右節點 ,3節點覆蓋5

 

 

: 2:  如果以上3中情況都沒有,只需要尋找當前節點的左節點的所有字節點的最大值,用最大值填充5節點 4填充5

 

 

 

 

5:完整代碼

#include <stdio.h> 
#include <stdlib.h>
struct TNode{
    int data;
    struct TNode *lt;
    struct TNode *rt;    
};
struct TNode* insrtTree(struct TNode *t,int key,int i);
void printTree(struct TNode *root);
struct TNode* delTree(struct TNode* t,int key);
int find(struct TNode* t,int key); 
int arr[1000]={0};
int main(){
    int n,m;
    int i,t;
    scanf("%d%d",&n,&m); 
    struct TNode *root=NULL;
    for(i=0;i<n;i++){
        scanf("%d",&arr[i]); 
        root=insrtTree(root,arr[i],i);
    }
    //t=arr[m-1];
    
    /*
    if(arr[m-1]==0){
        printf("Right child");
    }else{
        printf("Light child");
    }*/
    root=delTree(root,10);
    printTree(root);
    return 0;
}

int find(struct TNode* pt,int key){
    if(pt==NULL)return NULL;
    else if(pt->data==key)return 1;
    else if(pt->data>key) return find(pt->lt,key);
    else if(pt->data<key) return find(pt->rt,key);
}
// 刪除節點 
struct TNode* delTree(struct TNode* pt,int key){
    if(pt==NULL)return NULL;
    else if(pt->data>key) pt->lt=delTree(pt->lt,key);//尋找左節點 
    else if(pt->data<key) pt->rt=delTree(pt->rt,key);//尋找右節點
    //  找到節點 處理四種情況  
    else if(pt->lt==NULL){ // 當前節點無左節點 
        struct TNode* curt=pt->rt;
        free(pt);
        return curt;
    }else if(pt->rt==NULL){// 當前節點無右節點 
        struct TNode* curt=pt->lt;
        free(pt);
        return curt;
    }else if(pt->lt->rt==NULL){// 當前節點的左節點無右節點 
        struct TNode* curt=pt->lt;
        curt->rt=pt->rt;
        free(pt);
        return curt;
    }else{ 
    // 以上不滿足就把左兒子的子孫中最大的節點, 即右子樹的右子樹的...右子樹, 
    //提到需要刪除的節點位置
            struct TNode* p;
            for(p=pt->lt;p->rt->rt!=NULL;p=p->rt);
            struct TNode* curt=p->lt;
            p->rt=curt->rt;
            curt->lt=pt->lt;
            curt->rt=pt->rt;
            free(p);
            return curt;
    }
    return pt;
}
struct TNode* insrtTree(struct TNode *t,int key,int i){
    if(t==NULL){ //處理第一個節點 以及子節點為NULL情況 
        t=(struct TNode*)malloc(sizeof(struct TNode));
        t->lt=t->rt=NULL;
        t->data=key;
        return t;
    }
    if(t->data>key){// 插入左子樹情況 
         arr[i]=1;
        t->lt=insrtTree(t->lt,key,i);
    }else{         // 插入右子樹情況
        arr[i]=0;
        t->rt=insrtTree(t->rt,key,i);
    }
    return t;
}
void printTree(struct TNode *root){
    if(root==NULL)return;
    printf("%d ",root->data);
    printTree(root->lt);
    printTree(root->rt);
}

 

說明: 本身學習了 https://blog.csdn.net/li_l_il/article/details/88677927 但是完善了代碼 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

分類
發燒車訊

數據結構之隊列and棧總結分析

一、前言:

  數據結構中隊列和棧也是常見的兩個數據結構,隊列和棧在實際使用場景上也是相輔相成的,下面簡單總結一下,如有不對之處,多多指點交流,謝謝。

二、隊列簡介

  隊列顧名思義就是排隊的意思,根據我們的實際生活不難理解,排隊就是有先後順序,先到先得,其實在程序數據結構中的隊列其效果也是一樣,及先進先出。

     隊列大概有如下一些特性:

     1、操作靈活,在初始化時不需要指定其長度,其長度自動增加(默認長度為32)

        注:在實際使用中,如果事先能夠預估其長度,那麼在初始化時指定長度,可以提高效率

        2、泛型的引入,隊列在定義時可以指定數據類型避免裝箱拆箱操作

     3、存儲數據滿足先進先出原則

       

   c#中有關隊列的幾個常用方法:

    • Count:Count屬性返回隊列中元素個數。
    • Enqueue:Enqueue()方法在隊列一端添加一個元素。
    • Dequeue:Dequeue()方法在隊列的頭部讀取和刪除元素。如果在調用Dequeue()方法時,隊列中不再有元素,就拋出一個InvalidOperationException類型的異常。
    • Peek:Peek()方法從隊列的頭部讀取一個元素,但不刪除它。
    • TrimExcess:TrimExcess()方法重新設置隊列的容量。Dequeue()方法從隊列中刪除元素,但它不會重新設置隊列的容量。要從隊列的頭部去除空元素,應使用TrimExcess()方法。
    • Clear:Clear()方法從隊列中移除所有的元素。
    • ToArray:ToArray()複製隊列到一個新的數組中。

  下面通過隊列來實例模擬消息隊列的實現流程:

 

using System;
using System.Collections;
using System.Collections.Generic;

namespace dataStructureQueueTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("通過Queue來模擬消息隊列的實現");
            QueueTest queueTest = new QueueTest();

            while (true)
            {
                Console.WriteLine("請輸入你操作的類型:1:代表生成一條消息,2:代表消費一條消息");
                string type = Console.ReadLine();
                if (type == "1")
                {
                    Console.WriteLine("請輸入具體消息:");
                    string inforValue = Console.ReadLine();
                    queueTest.InformationProducer(inforValue);
                }
                else if (type == "2")
                {
                    //// 在消費消息的時候,模擬一下,消費成功與消費失敗下次繼續消費的場景

                    object inforValue = queueTest.InformationConsumerGet();
                    if (inforValue == null)
                    {
                        Console.WriteLine("當前無可消息可消費");
                    }
                    else
                    {
                        Console.WriteLine("獲取到的消息為:" + inforValue);

                        Console.WriteLine("請輸入消息消費結果:1:成功消費消息,2:消息消費失敗");
                        string consumerState = Console.ReadLine();

                        ///// 備註:該操作方式線程不安全,在多線程不要直接使用
                        if (consumerState == "1")
                        {
                            queueTest.InformationConsumerDel();
                        }
                    }
                }
                else
                {
                    Console.WriteLine("操作有誤,請重新選擇");
                }
            }
        }
    }

    /// <summary>
    /// 隊列練習
    /// </summary>
    public class QueueTest
    {
        /// <summary>
        /// 定義一個隊列
        /// </summary>
        public Queue<string> queue = new Queue<string>();

        /// <summary>
        /// 生成消息--入隊列
        /// </summary>
        /// <param name="inforValue"></param>
        public void InformationProducer(string inforValue)
        {
            queue.Enqueue(inforValue);
        }

        /// <summary>
        /// 消費消息---出隊列--只獲取數據,不刪除數據
        /// </summary>
        /// <returns></returns>
        public object InformationConsumerGet()
        {
            if (queue.Count > 0)
            {
                return queue.Peek();
            }

            return null;
        }

        /// <summary>
        /// 消費消息---出隊列---獲取數據的同時刪除數據
        /// </summary>
        /// <returns></returns>
        public string InformationConsumerDel()
        {
            if (queue.Count > 0)
            {
                return queue.Dequeue();
            }

            return null;
        }
    }
}

 

 

三、棧簡介

  棧和隊列在使用上很相似,只是棧的數據存儲滿足先進后出原則,棧有如下一些特性:

     1、操作靈活,在初始化時不需要指定其長度,其長度自動增加(默認長度為10)

        注:在實際使用中,如果事先能夠預估其長度,那麼在初始化時指定長度,可以提高效率

        2、泛型的引入,棧在定義時可以指定數據類型避免裝箱拆箱操作

     3、存儲數據滿足先進后出原則

    c#中有關棧的幾個常用方法:

  • Count:Count屬性返回棧中的元素個數。
  • Push:Push()方法在棧頂添加一個元素。
  • Pop:Pop()方法從棧頂刪除一個元素,並返回該元素。如果棧是空的,就拋出一個InvalidOperationException類型的異常。
  • Peek:Peek()方法返回棧頂的元素,但不刪除它。
  • Contains:Contains()方法確定某個元素是否在棧中,如果是,就返回true。

     下面通過一個棧來模擬瀏覽器的回退前進操作的實現

 

using System;
using System.Collections.Generic;

namespace dataStructureStackTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //// 通過棧來模擬瀏覽器回退前進操作
            ////   1、定義兩個棧,分別記錄回退的地址集合,和前進地址集合
            ////   2、在操作具體的回退或者前進操作時
            ////      如果和前一次操作相同,那麼就取出對應隊列的一條數據存儲到另外一個隊列
            Console.WriteLine("本練習模擬瀏覽器的回退前進操作:");

            /// 假設瀏覽器已瀏覽了20個網站記錄
            StackTest stackTestBack = new StackTest(20);
            StackTest stackTestGo = new StackTest(20);
            for (int i = 0; i < 20; i++)
            {
                stackTestBack.PushStack("網站" + (i + 1).ToString());
            }

            //// 記錄上一次操作
            string beforOpert = "";
            while (true)
            {
                Console.WriteLine("");
                Console.WriteLine("請輸入你操作的類型:1:回退,2:前進");
                string type = Console.ReadLine();

                if (type == "1")
                {
                    //// 出棧
                    if (beforOpert == type)
                    {
                        stackTestGo.PushStack(stackTestBack.GetAndDelStack());
                    }
                    string wbeSit = stackTestBack.GetStack();
                    Console.WriteLine("回退到頁面:" + wbeSit);
                    beforOpert = type;
                }
                else if (type == "2")
                {
                    //// 出棧
                    if (beforOpert == type)
                    {
                        stackTestBack.PushStack(stackTestGo.GetAndDelStack());
                    }
                    string wbeSit = stackTestGo.GetStack();

                    Console.WriteLine("回退到頁面:" + wbeSit);
                    beforOpert = type;
                }
                else
                {
                    Console.WriteLine("請輸入正確的操作方式!!");
                }
            }
        }
    }

    /// <summary>
    /// 隊列練習
    /// </summary>
    public class StackTest
    {
        /// <summary>
        /// 定義一個棧
        /// </summary>
        public Stack<string> stack;

        /// <summary>
        ///無參數構造函數,棧初始化為默認長度
        /// </summary>
        public StackTest()
        {
            stack = new Stack<string>();
        }

        /// <summary>
        ///有參數構造函數,棧初始化為指定長度
        ///如果在定義隊列時,如果知道需要存儲的數據長度,那麼最好預估一個長度,並初始化指定的長度
        /// </summary>
        public StackTest(int stackLen)
        {
            stack = stackLen > 0 ? new Stack<string>(stackLen) : new Stack<string>();
        }

        /// <summary>
        /// 入棧
        /// </summary>
        /// <param name="inforValue"></param>
        public void PushStack(string inforValue)
        {
            stack.Push(inforValue);
        }

        /// <summary>
        /// 出棧(但不刪除)
        /// </summary>
        /// <returns></returns>
        public string GetStack()
        {
            if (stack.Count > 0)
            {
                return stack.Peek();
            }

            return null;
        }

        /// <summary>
        /// 出棧(並刪除)
        /// </summary>
        /// <returns></returns>
        public string GetAndDelStack()
        {
            if (stack.Count > 0)
            {
                return stack.Pop();
            }

            return null;
        }
    }
}

 

四、使用場景總結

  根據隊列和棧的特點,下面簡單總結一下隊列和棧的一些實際使用場景

   隊列:

    1、異步記錄日誌,此處會涉及到單例模式的使用

    2、消息隊列

    3、業務排隊,比如12306車票購買排隊等候

    4、其他符合先進先出原則的業務操作

   棧:

    1、可回退的操作記錄,比如:瀏覽器的回退操作

    2、計算表達式匹配,比如:計算器表達式計算

    3、其他符合先進后出原則的業務操作

 

附件:

關於這一些練習的代碼,上傳到github,有興趣的可以看一下:

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

分類
發燒車訊

吉利:到2020年新能源汽車銷量將實現90%以上的占比

日前,吉利控股集團董事長李書福在接受《中國經營報》記者採訪時表示,以後我們開發的新產品基本是新能源汽車和智慧互聯汽車,傳統汽車就逐漸不生產了。

此話背後,實際就是吉利於近日提出的“藍色吉利行動”中的重要一環,到2020年,其新能源汽車銷量將實現90%以上的銷量占比。

具體來說,根據“藍色吉利行動”,吉利新能源將在技術上主打純電動、油電混動、插電式混合動力三種路線,並通過兩大平臺——FE(中高端)與PE(緊湊級)平臺來發展純電動車板塊。

從以上路徑上看,吉利與其他車企並無二致,但其公佈的“五大承諾”卻足以讓業內熱議——第一,提前全面實現2020年國家第四階段每百公里5.0L的企業平均燃油消耗限值;第二,實現消費者用傳統汽車的購買成本購買插電式混動汽車的夢想;第三,實現到2020年新能源汽車銷量占吉利整體銷量的90%以上;第四,在氫燃料及金屬燃料電池汽車研發方面取得實質性成果;第五,實現新能源技術,智慧化、輕量化技術在行業的領先地位。

雖然言之鑿鑿,但不得不說的是,90%以上的新能源銷量加上此前吉利發佈的“2020年實現120萬輛”的銷量目標,同年吉利新能源汽車銷量目標竟逾100萬輛。

對此,吉利控股集團總裁CEO安聰慧表示:“吉利制定這樣的目標並不是為了和其他企業進行對比,而是結合自身發展提出來的。”

據其介紹,在技術領域,吉利汽車將以與沃爾沃合作打造的CMA中高級車基礎模組架構為核心打造新能源車型,該方面的設計研發工作主要由吉利汽車歐洲研發中心承擔,該中心在瑞典哥德堡已有1200名工程師,中國杭州也有300名工程師,負責架構開發、上車體開發、核心部件開發開發,整車設計、工程製造及新技術的研發。CMA基礎模組架構可以實現電機+發動機等核心部件的批量生產。

此外,2015年初,吉利與新大洋機電集團成立合資公司並推出知豆電動車,加之此前其子公司上海華普國潤與康迪車業成立的合資公司,署名吉利旗下的新能源車型並不止吉利品牌。雖然,吉利在新能源領域的開疆破土頗有“借力而為”之感,但不論如何,2015年1~11月,在乘聯會統計的自主品牌新能源車銷量占比情況中,吉利節節攀升,的確實現了在自主品牌領域的市占率穩增,也正因如此,加之政策的多重鼓勵,吉利才許下到2020年實現新能源汽車逾百萬的戰略目標。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開

分類
發燒車訊

源碼學習系列之SpringBoot自動配置(篇二)

源碼學習系列之SpringBoot自動配置(篇二)之HttpEncodingAutoConfiguration 源碼分析

繼上一篇博客之後,本博客繼續跟一下SpringBoot的自動配置源碼

ok,先複習一下上一篇的內容,從前面的學習,我們知道了SpringBoot的自動配置主要是由一個選擇器AutoConfigurationImportSelector,先通過選擇器將自動配置的類加載到Spring容器

注意點:

  • List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);獲取的候選配置的類名
  • 由SpringFactoriesLoader加載器負責加載配置類名,已經裝載配置類到容器,SpringFactoriesLoader的loadSpringFactories方法讀取自動配置工程的META-INF/spring.factories配置文件,加載配置類的全類名,包裝成Properties對象,然後再加載到容器里
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    /* 將spring.factories的類都裝載到Spring容器*/
     public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();

        try {
        //將META-INF/spring.factories文件里配置的屬性都裝載到Enumeration數據結構里
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            ArrayList result = new ArrayList();
            //遍歷獲取屬性,然後再獲取對應的配置類全類名
            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }

            return result;
        } catch (IOException var8) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
        }
    }

ok,Springboot的自動配置類都在這個包里,源碼很多,所以本博客只是簡單跟一下源碼

自動配置可以說是SpringBoot框架的一個很重要的功能,其強大的功能就是通過很多配置類實現的,當然這麼多配置,可以參考SpringBoot官方的配置參考:
https://docs.spring.io/spring-boot/docs/2.1.10.RELEASE/reference/html/common-application-properties.html

SpringBoot的自動配置類很多,顯然不是每個配置類都生效的,比如你沒引對應的jar,那對應的配置類肯定是不起效的,ok,本博客以HttpEncodingAutoConfiguration自動編碼配置類為實例,記錄一下SpringBoot的自動配置

先補充一些@Conditional註解的用法:詳情可以參考我上篇博客

@Conditional派生註解 作用(都是判斷是否符合指定的條件)
@ConditionalOnJava 系統的java版本是否符合要求
@ConditionalOnBean 有指定的Bean類
@ConditionalOnMissingBean 沒有指定的bean類
@ConditionalOnExpression 符合指定的SpEL表達式
@ConditionalOnClass 有指定的類
@ConditionalOnMissingClass 沒有指定的類
@ConditionalOnSingleCandidate 容器只有一個指定的bean,或者這個bean是首選bean
@ConditionalOnProperty 指定的property屬性有指定的值
@ConditionalOnResource 路徑下存在指定的資源
@ConditionalOnWebApplication 系統環境是web環境
@ConditionalOnNotWebApplication 系統環境不是web環境
@ConditionalOnjndi JNDI存在指定的項

通過上篇博客的學習,我們已經知道了SpringBoot有很多自動配置類,所以本博客拿HttpEncodingAutoConfiguration類來看看

補充:

  • @Configuration proxyBeanMethods屬性:默認是開啟的,開啟后允許其它配置類調用這個類的@bean方法,詳情參看Spring官方文檔:
package org.springframework.boot.autoconfigure.web.servlet;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.http.HttpProperties;
import org.springframework.boot.autoconfigure.http.HttpProperties.Encoding;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.filter.CharacterEncodingFilter;

@Configuration(
    proxyBeanMethods = false
)//指定是一個配置列,關了proxyBeanMethods,其它配置類就不能調相應的@bean類
@EnableConfigurationProperties({HttpProperties.class})//讓使用 @ConfigurationProperties註解的HttpProperties類生效,HttpProperties類通過ConfigurationProperties註解,將屬性配置一個一個加載進來
@ConditionalOnWebApplication(
    type = Type.SERVLET
)//指定系統環境是Web環境配置才起效,並且指定類型是SERVLET
@ConditionalOnClass({CharacterEncodingFilter.class})//系統有CharacterEncodingFilter過濾器類,則配置類起效,CharacterEncodingFilter類:SpringMVC中進行亂碼解決的過濾器
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)//判斷配置文件是否有spring.http.encoding.enabled屬性,如果沒配置,也是默認為true的,因為配置了`matchIfMissing =true`
public class HttpEncodingAutoConfiguration {
    //創建一個Encoding對象
    private final Encoding properties;
    // 構造函數里通過properties.getEncoding();進行屬性映射,獲取默認的配置
    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }

    @Bean
    @ConditionalOnMissingBean//如果系統沒有CharacterEncodingFilter類,就執行characterEncodingFilter方法
    public CharacterEncodingFilter characterEncodingFilter() {
        //重新創建一個編碼過濾器
        OrderedCharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        //設置默認的配置
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }

    @Bean
    public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
        return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);
    }

    private static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
        private final Encoding properties;

        LocaleCharsetMappingsCustomizer(Encoding properties) {
            this.properties = properties;
        }

        public void customize(ConfigurableServletWebServerFactory factory) {
            if(this.properties.getMapping() != null) {
                factory.setLocaleCharsetMappings(this.properties.getMapping());
            }

        }

        public int getOrder() {
            return 0;
        }
    }
}

通過對HttpEncodingAutoConfiguration源碼的學習,可以看出,其實主要是用@Conditional及其派生註解,這些註解都是要在特定情況才會起效,起效了,才會將組件加載到Spring容器里

ok,然後我們怎麼知道哪些配置是起效的?在SpringBoot項目里,是可以通過配置,開啟打印的,可以在application.properties加上debug=true屬性就可以

控制台打印的Positive matches就表示有效的配置類

console打印的Negative matches表示不起效的配置類:
比如我的項目沒有加aop的,aop自動配置類就不起效

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開