鵝廠實習| 週記(二)

如下是本週的知識清單:

  • SparseArray
  • atomic包
  • Android埋點
  • Java基礎之註解
  • 一點小感悟

1.SparseArrayhtml

當新建一個key爲整型的HashMap時,會出現以下的提示信息,推薦使用SparseArray來替代HashMap: java

接下來就來介紹下SparseArray:程序員

a.數據結構:又稱稀疏數組,內部經過兩個數組分別存儲key和value,並用壓縮的方式來存儲數據後端

b.優勢:可替代key爲int、value爲Object的HashMap,相比於HashMap數組

  • 能更節省存儲空間
  • 因爲key指定爲int,能節省int和Integer的裝箱拆箱操做帶來的性能消耗
  • 擴容時只須要數組拷貝工做,而不需重建哈希表

c.適用場景:數據量不大(千之內)、空間比時間重要、須要使用Map且key爲整型;不適合存儲大容量數據,此時性能將退化至少50%安全

d.使用服務器

  • 添加:public void put(int key, E value)
  • 刪除:
    • public void delete(int key)
    • public void remove(int key)實際上內部會調用delete方法
  • 查找:
    • public E get(int key)
    • public E get(int key, E valueIfKeyNotFound)可設置假設key不存在時默認返回的value
    • public int keyAt(int index)獲取相應的key
    • public E valueAt(int index)獲取相應的value

e.get/put過程:元素會按照key從小到大進行存儲,先使用二分法查詢key對應在數組中的下標index,而後經過該index進行增刪查。源碼分析SparseArray解析數據結構


2.atomic包多線程

a.原子操做類:與採起悲觀鎖策略的synchronized不一樣,atomic包採用樂觀鎖策略去原子更新數據,並使用CAS技術具體實現併發

//保證自增線程安全的兩種方式
public class Sample {
    private static Integer count = 0;
    synchronized public static void increment() {
        count++;
    }
}
public class Sample {
    private static AtomicInteger count = new AtomicInteger(0);
    public static void increment() {
        count.getAndIncrement();
    }
}
複製代碼

基礎知識:Java併發問題--樂觀鎖與悲觀鎖以及樂觀鎖的一種實現方式-CAS

b.類型

原子更新基本類型:

  • AtomicInteger:原子更新Integer
  • AtomicLong:原子更新Long
  • AtomicBoolean:原子更新boolean

以AtomicInteger爲例,經常使用方法

  • getAndAdd(int delta):取當前值,再和delta值相加
  • addAndGet(int delta) :先和delta值相加,再取相加後的最終值
  • getAndIncrement():取當前 值,再自增
  • incrementAndGet() :先自增,再取自增後的最終值
  • getAndSet(int newValue):取當前值,再設置爲newValue值

原子更新數組:

  • AtomicIntegerArray:原子更新整型數組中的元素
  • AtomicLongArray:原子更新長整型數組中的元素
  • AtomicReferenceArray:原子更新引用類型數組中的元素

以AtomicIntegerArray爲例,經常使用方法

  • addAndGet(int i, int delta):先將數組中索引爲i的元素與delta值相加,再取相加後的最終值
  • getAndIncrement(int i):取數組中索引爲i的元素的值,再自增
  • compareAndSet(int i, int expect, int update):若是數組中索引爲i的元素的值和expect值相等,則更新爲update值

原子更新引用類型:

  • AtomicReference:原子更新引用類型
  • AtomicReferenceFieldUpdater:原子更新引用類型裏的字段
  • AtomicMarkableReference:原子更新帶有標記位的引用類型
//這幾個類提供的方法基本一致,以AtomicReference爲例
public class AtomicDemo {

    private static AtomicReference<User> reference = new AtomicReference<>();

    public static void main(String[] args) {
        User user1 = new User("a", 1);
        reference.set(user1);
        User user2 = new User("b",2);
        User user = reference.getAndSet(user2);
        System.out.println(user);//輸出User{userName='a', age=1}
        System.out.println(reference.get());//輸出User{userName='b', age=2}
    }

    static class User {
        private String userName;
        private int age;

        public User(String userName, int age) {
            this.userName = userName;
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{" +"userName='" + userName + '\'' +", age=" + age + '}';
        }
    }
}
複製代碼

原子更新字段:

  • AtomicIntegeFieldUpdater:原子更新整型字段
  • AtomicLongFieldUpdater:原子更新長整型字段
  • AtomicStampedReference:原子更新帶有版本號的引用類型

使用方法:因爲原子更新字段類是抽象類,所以須要先經過其靜態方法newUpdater建立一個更新器,並設置想更新的類和屬性 注意:被更新的屬性必須用public volatile修飾

//這幾個類提供的方法基本一致,以AtomicIntegeFieldUpdater爲例
public class AtomicDemo {

    private static AtomicIntegerFieldUpdater updater = AtomicIntegerFieldUpdater.newUpdater(User.class,"age");
    public static void main(String[] args) {
        User user = new User("a", 1);
        int oldValue = updater.getAndAdd(user, 5);
        System.out.println(oldValue);//輸出1
        System.out.println(updater.get(user));//輸出6
    }

    static class User {
        private String userName;
        public volatile int age;

        public User(String userName, int age) {
            this.userName = userName;
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{" +"userName='" + userName + '\'' +", age=" + age +'}';
        }
    }
} 
複製代碼

c.優勢:能夠避免多線程的優先級倒置和死鎖狀況的發生,提高在高併發處理下的性能,相比於synchronized ,在非激烈競爭的狀況下,開銷更小,速度更快


3.Android埋點

a.含義:預先在目標應用採集數據,對特定用戶行爲或事件進行捕獲、處理,並以必定方式上報至服務器,便於後續進行數據分析

b.方式

  • 代碼埋點:在某個事件發生時經過預先寫好的代碼來發送數據
    • 優勢:控制精準,採集靈活性強,可自由選擇什麼時候發送自定義數據
    • 缺點:開發、測試成本高,須要等發版才能修改線上埋點、更新代價大
  • 無埋點/全埋點:在端上自動採集並上報儘量多的數據,在計算時篩選出可用的數據
    • 優勢:很大程度上減小開發、測試的重複勞動,數據可回溯且覆蓋全面
    • 缺點:採集信息不夠靈活,數據量大,後端篩選分析工做量大
  • 可視化埋點:經過可視化工具選擇須要收集的埋點數據,下發配置給客戶端,終端點擊時獲取當前點擊的控件根據配置文件進行選擇上報
    • 優勢:很大程度上減小開發、測試的重複勞動,數據量可控且相對精確,可在線上動態埋點、而無需等待App發版
    • 缺點:採集信息不夠靈活,沒法解決數據回溯的問題

幾個實踐:51信用卡網易58


4.Java基礎之註解(Annotation)

a.含義:是附加在代碼中的一些元數據,在JDK1.5 版本開始引入,與類、接口、枚舉在同一個層次

b.做用

  • 聲明在包、類、字段、方法、局部變量、方法參數等前面,用來對這些元素進行說明和註釋
  • 註解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的做用,好比編譯時進行格式檢查、簡化操做進而下降代碼量

c.使用

如下代碼展現了註解的定義、屬性和使用的方法:

//1.註解的定義:經過@interface關鍵字
//如下表示建立了一個名爲TestAnnotation的註解
public @interface TestAnnotation {    
    //2.註解的屬性:
    //聲明:採用「無形參的方法」形式,方法名錶示屬性名,返回值表示屬性類型
    //類型:必須是8種基本數據類型,或者類、接口、註解及對應數組
    //默認值:用default關鍵值,在賦值時能夠省略
    //如下表示註解TestAnnotation中有id和msg兩個屬性,且msg默認值爲hi
    int id();
    String msg() default "hi";
}

//3.註解的使用:
//對屬性賦值:在註解使用打個括號,以value=""形式,多個屬性以前用逗號隔開;若註解只有一個屬性,則賦值時value=能夠省略;若是沒有屬性,括號均可以省略
//如下表示對Test類進行標識,並對註解的適兩個屬性進行賦值
@TestAnnotation(id=1,msg="hello")
public class Test {
}
複製代碼

d.類型

  • 元註解:是一種基本註解,用於解釋註解,注意其描述對象是註解而非代碼,包含類型以下表:
名稱 做用 取值
@Target (目標註解) 描述註解的限定使用範圍 ElementType.CONSTRUCTOR: 對構造方法進行註解;ElementType.ANNOTATION_TYPE: 對註解進行註解;ElementType.FIELD: 對屬性進行註解;ElementType.LOCAL_VARIABLE: 對局部變量進行註解;ElementType.METHOD: 對方法進行註解;ElementType.PACKAGE: 對包進行註解;ElementType.PARAMETER: 對描述參數進行註解;ElementType.TYPE: 對類型(類、接口、枚舉)進行註解
@Inherited (繼承註解) 擁有該註解的註解所做用的類,且其子類未帶任何註解,則該子類也會繼承父類的註解
@Retention(保留註解) 描述註解的生命週期 RetentionPolicy.SOURCE: 註解只保留在源碼階段,在編譯器完整編譯以後會被丟棄忽視;RetentionPolicy.CLASS: 註解會保留到編譯進行時,但不會被加載到 JVM ;RetentionPolicy.RUNTIME: 註解會保留到程序運行時,且會被加載進入到 JVM
@Documented(文檔註解) 將註解添加到Java文檔
@Repeatable(可重複註解) 表示註解的值能夠同時取多個

來段代碼感覺下這些註釋的使用效果:

//表示TestAnnotation註釋是對類描述的、保留到運行時、被添加到Javadoc、有繼承性值的
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface TestAnnotation {
}
//因爲B類是A類的子類,且B類沒被任何註解應用,則B類繼承了A類的TestAnnotation註解
@TestAnnotation
public class A {}
public class B extends A {}
複製代碼

接下來用單獨一個例子來解釋可重複註解

//1.定義一個註解容器(此處指@Persons):
//做用:存放其餘註解(此處指@Person),其自己也是個註解
//注意:須要有個value屬性,類型就是被@Repeatable解釋的註解數組(此處指Person[])
@interface Persons {
    Person[] value();//註解屬性
}
//2.使用@Repeatable解釋(此處指@Person),括號中是註解容器類(此處指Persons)
@Repeatable(Persons.class)
@interface Person {
    String role default "";//註解屬性
}
//3.使用@Repeatable解釋的註釋時,能夠取多個註解值來解釋代碼
@Person(role="coder")
@Person(role="PM")
public class SuperMan {//SuperMan既是程序員又是產品經理
}
複製代碼
  • Java內置註解:下表展現了幾個經常使用的內部已實現註解
名稱 做用
@Override(複寫註解) 被標記的方法須要被子類複寫,不然編譯器會報錯
@Deprecated(過期註解) 標記已過期的元素,當元素使用時會在代碼劃橫線
@SuppressWarnings(阻止警告註解) 被標記的元素會阻止編譯器發出警告提醒
@SafeVarargs(參數安全類型註解) 提醒開發者不要用參數作不安全的操做、阻止編譯器產生unchecked警告
  • 自定義註解:在以前已經介紹了註解的定義、屬性和使用的具體方法,還差一步,註解的提取,須要經過Java的反射技術獲取類方法和字段的註解信息,經常使用方法:
方法名 返回值 描述
isAnnotationPresent(Class<? extends Annotation> annotationClass) boolean 若是指定類型的註解存在於此元素上,則返回 true,不然返回 false
getAnnotation(Class<A> annotationClass) <A extends Annotation> 該元素若是存在指定類型的註解,則返回這些註解,不然返回 null
getAnnotations() Annotation[] 返回此元素上存在的全部註解,包括從父類繼承的
getDeclaredAnnotations() Annotation[] 返回直接存在於此元素上的全部註解,但不包括父類的註解

在以前的Test類裏就能夠添加如下代碼,來獲取在類上給@TestAnnotation設置的屬性值了:

boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);	
if (hasAnnotation) {
			TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);		
			System.out.println("id:"+testAnnotation.id());//輸出1
			System.out.println("msg:"+testAnnotation.msg());//輸出hello
}
複製代碼

推薦閱讀秒懂,Java 註解 (Annotation)你能夠這樣學


5.一點小感悟

最近的生活變得很是規律和健康,果真工做令人勤快,從早上出門開始,穿梭巴士、免費早餐、養生茶水、一餐一果、關燈午休、夜宵券、打車報銷...天天都能感覺到鵝廠對員工的關懷,幸福感滿滿。

這陣子的工做也有了新的進展,走過了熟悉項目、定位bug、討論方案的階段,寫下了第一行代碼~捋代碼邏輯的這段日子我開始深深懷疑人生,感受智商down到谷底,這裏就不得不感激導師的耐心指導,還老是關心我有沒有疑問,努力挽救一個辣雞少女。

前幾天開了個總結會,關於某個版本的bug review,不只是回顧bug產生緣由和解決辦法,更可能是反思和總結經驗,好比反覆打補丁不如從根源解決、重構務必看懂每行代碼切勿放過哪怕一個字段、注意空指針問題、要考慮到邊界條件、自測要到位、多機型多系統測試、使用接口要注意內部實現...聽罷感受受益不淺,提醒本身時刻注意,少走些彎路。

前輩的一些tips

看着同事愈來愈少才發覺立刻就放假了,不過你們都絲毫沒有懈怠,天天十點多還沒什麼人離開,有時候大半夜還在羣裏討論方案,週五也是如此,週末有天來公司還看到幾個好學的小哥哥在,和優秀的人共事也但願本身早日也能如此優秀呀~

PS:上週末由於身體不舒服沒有及時更新,和這周就合併了~還有立刻過年了提早祝你們新年快樂,假期愉快,明年再見(`・ω・´)

白天 和 黑夜
相關文章
相關標籤/搜索