多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > Android最佳性能實踐(三)――高性能編碼優化

Android最佳性能實踐(三)――高性能編碼優化

來源:程序員人生   發布時間:2015-03-26 09:37:58 閱讀次數:4187次

轉載請注明出處:http://blog.csdn.net/guolin_blog/article/details/42318689

在前兩篇文章當中,我們主要學習了Android內存方面的相干知識,包括如何公道地使用內存,和當產生內存泄漏時如何定位出問題的緣由。那末關于內存的知識就討論到這里,今天開始我們將學習1些性能編碼優化的技能。

這里先事前提示大家1句,本篇文章中討論的編碼優化技能都是屬于1些“微優化”,也就是說即便我們都依照本篇文章的技能來優化代碼,在性能方面也是看不出有甚么顯著的提升的。使用適合的算法與數據結構將永久是你優化程序性能的最主要手段,但本篇文章中不會討論這1塊的內容。因此,這里我們行將學習的其實不是甚么靈丹妙藥,而是大家應當把這些技能當作1種好的編碼規范,我們在平時寫代碼時就能夠潛移默化地使用這些編碼規范,不但能夠在微觀層面提升程序1定的性能,也能夠讓我們的代碼變得更加專業,下面就讓我們來1起學習1下這些技能。

避免創建沒必要要的對象

創建對象歷來都不應當是1件隨便的事情,由于創建1個對象就意味著垃圾回收器需要回收1個對象,而這兩步操作都是需要消耗時間的。雖然說創建1個對象的代價確切非常小,并且Android 2.3版本當中又增加了并發垃圾回收器機制(詳見 Android最好性能實踐(2)――分析內存的使用情況),這讓GC操作時的停頓時間也變得難以發覺,但是這些理由都不足以讓我們可以肆意地創建對象,需要創建的對象我們自然要創建,但是沒必要要的對象我們就應當盡可能避免創建。

下面來看1些我們可以免創建對象的場景:

  • 如果我們有1個需要拼接的字符串,那末可以優先斟酌使用StringBuffer或StringBuilder來進行拼接,而不是加號連接符,由于使用加號連接符會創建過剩的對象,拼接的字符串越長,加號連接符的性能越低。
  • 在沒有特殊緣由的情況下,盡可能使用基本數據類來代替封裝數據類型,int比Integer要更加高效,其它數據類型也是1樣。
  • 當1個方法的返回值是String的時候,通常可以去判斷1下這個String的作用是甚么,如果我們明確地知道調用方會將這個返回的String再進行拼接操作的話,可以斟酌返回1個StringBuffer對象來代替,由于這樣可以將1個對象的援用進行返回,而返回String的話就是創建了1個短生命周期的臨時對象。
  • 正如前面所說,基本數據類型要優于對象數據類型,類似地,基本數據類型的數組也要優于對象數據類型的數組。另外,兩個平行的數組要比1個封裝好的對象數組更加高效,舉個例子,Foo[]和Bar[]這樣的兩個數組,使用起來要比Custom(Foo,Bar)[]這樣的1個數組高效很多。

固然上面所說的只是1些代表性的例子,我們所要遵照的1個基本原則就是盡量地少創建臨時對象,越少的對象意味著越少的GC操作,同時也就意味著越好的程序性能和用戶體驗。

靜態優于抽象

如果你其實不需要訪問1個對象中的某些字段,只是想調用它的某個方法來去完成1項通用的功能,那末可以將這個方法設置成靜態方法,這會讓調用的速度提升15%⑵0%,同時也不用為了調用這個方法而去專門創建對象了,這樣還滿足了上面的1條原則。另外這也是1種好的編程習慣,由于我們可以放心腸調用靜態方法,而不用擔心調用這個方法后是不是會改變對象的狀態(靜態方法內沒法訪問非靜態字段)。

對常量使用static final修飾符

我們先來看1下在1個類的最頂部定義以下代碼:

static int intVal = 42; static String strVal = "Hello, world!";
編譯器會為上述代碼生成1個初始化方法,稱為<clinit>方法,該方法會在定義類第1次被使用的時候調用。然后這個方法會將42的值賦值到intVal當中,并從字符串常量表中提取1個援用賦值到strVal上。當賦值完成后,我們就能夠通過字段搜索的方式來去訪問具體的值了。

但是我們還可以通過final關鍵字來對上述代碼進行優化:

static final int intVal = 42; static final String strVal = "Hello, world!";
經過這樣修改以后,定義類就不再需要1個<clinit>方法了,由于所有的常量都會在dex文件的初始化器當中進行初始化。當我們調用intVal時可以直接指向42的值,而調用strVal時會用1種相對輕量級的字符串常量方式,而不是字段搜索的方式。

另外需要大家注意的是,這類優化方式只對基本數據類型和String類型的常量有效,對其它數據類型的常量是無效的。不過,對任何常量都是用static final的關鍵字來進行聲明依然是1種非常好的習慣。

使用增強型for循環語法

增強型for循環(也被稱為for-each循環)可以用于去遍歷實現Iterable接口的集合和數組,這是jdk 1.5中新增的1種循環模式。固然除這類新增的循環模式以外,我們依然還可使用原本的普通循環模式,只不過它們之間是有效力區分的,我們來看下面1段代碼:

static class Counter { int mCount; } Counter[] mArray = ... public void zero() { int sum = 0; for (int i = 0; i < mArray.length; ++i) { sum += mArray[i].mCount; } } public void one() { int sum = 0; Counter[] localArray = mArray; int len = localArray.length; for (int i = 0; i < len; ++i) { sum += localArray[i].mCount; } } public void two() { int sum = 0; for (Counter a : mArray) { sum += a.mCount; } }
可以看到,上述代碼當中我們使用了3種不同的循環方式來對mArray中的所有元素進行求和。其中zero()方法是最慢的1種,由于它是把mArray.length寫在循環當中的,也就是說每循環1次都需要重新計算1次mArray的長度。而one()方法則相對快很多,由于它使用了1個局部變量len來記錄數組的長度,這樣就省去了每次循環時字段搜索的時間。two()方法在沒有JIT(Just In Time Compiler)的裝備上是運行最快的,而在有JIT的裝備上運行效力和one()方法不相上下,唯1需要注意的是這類寫法需要JDK 1.5以后才支持。

但是這里要跟大家提1個特殊情況,對ArrayList這類集合,自己手寫的循環要比增強型for循環更快,而其他的集合就沒有這類情況。因此,對我們來講,默許情況下可以都使用增強型for循環,而遍歷ArrayList時就還是使用傳統的循環方式吧。

多使用系統封裝好的API

Java語言當中其實給我們提供了非常豐富的API接口,我們在編寫程序時如果可使用系統提供的API就應當盡可能使用,系統提供的API完成不了我們需要的功能時才應當自己去寫,由于使用系統的API在很多時候比我們自己寫的代碼要快很多,它們的很多功能都是通過底層的匯編模式履行的。

比如說String類當中提供的好多API都是具有極高的效力的,像indexOf()方法和1些其它相干的API,雖然說我們通過自己編寫算法也能夠完成一樣的功能,但是效力方面會和這些方法差的比較遠。這里舉個例子,如果我們要實現1個數組拷貝的功能,使用循環的方式來對數組中的每個元素逐一進行賦值固然是可行的,但是如果我們直接使用系統中提供的System.arraycopy()方法將會讓履行效力快9倍以上。

避免在內部調用Getters/Setters方法

我們平時寫代碼時都被告知,1定要使用面向對象的思惟去寫代碼,而面向對象的3大特性我們都知道,封裝、多態和繼承。其中封裝的基本思想就是不要把類內部的字段暴漏給外部,而是提供特定的方法來允許外部操作相應類的內部字段,從而在Java語言當中就出現了Getters/Setters這類封裝技能。

但是在Android上這個技能就不再是那末的受推重了,由于字段搜索要比方法調用效力高很多,我們直接訪問某個字段可能要比通過getters方法來去訪問這個字段快3到7倍。不過我們肯定不能僅僅由于效力的緣由就將封裝這個技能給拋棄了,編寫代碼還是要依照面向對象思惟的,但是我們可以在能優化的地方進行優化,比如說避免在內部調用getters/setters方法。

那甚么叫做在內部調用getters/setters方法呢?這里我舉1個非常簡單的例子:

public class Calculate { private int one = 1; private int two = 2; public int getOne() { return one; } public int getTwo() { return two; } public int getSum() { return getOne() + getTwo(); } }
可以看到,上面是1個Calculate類,這個類的功能非常簡單,先將one和two這兩個字段進行了封裝,然后提供了getOne()方法獲得one字段的值,提供了getTwo()方法獲得two字段的值,還提供了1個getSum()方法用于獲得總和的值。

這里我們注意到,getSum()方法當中的算法就是將one和two的值相加進行返回,但是它獲得one和two的值的方式也是通過getters方法進行獲得的,其實這是1種完全沒有必要的方式,由于getSum()方法本身就是Calculate類內部的方法,它是可以直接訪問到Calculate類中的封裝字段的,因此這類寫法在Android上是不推重的,我們可以進行以下修改:

public class Calculate { private int one = 1; private int two = 2; ...... public int getSum() { return one + two; } }
改成這類寫法以后,我們就避免了在內部調用getters/setters方法,而對外部而言Calculate類依然是具有很好的封裝性的。

固然,本篇文章中推薦的這些技能呢也其實不全面,只是從Android官方文檔抽取了幾個感覺比較實用的分享給大家,更多技能大家也能夠到Android官網上去瀏覽。另外在高性能編碼方面《Efficient Java》這本書當中也提供了非常多的技能,有興趣的朋友也能夠去瀏覽1下這本書。那末本篇文章就到這里,下篇文章當中將會介紹Android布局優化的技能,敬請期待。

第1時間取得博客更新提示,和更多技術信息分享,歡迎關注我的微信公眾號,掃1掃下方2維碼或搜索微信號guolin_blog,便可關注。

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 亚洲国产一区二区三区四区五区 | 久久毛片网 | 欧美 第一页 | 高清免费a级在线观看国产 高清免费国产在线观看 | 男女羞羞视频免费 | 成人欧美一区二区三区黑人免费 | 在线国产福利 | 日韩欧美视频一区二区在线观看 | 久久久xxxx| 动漫美女毛片 | 亚洲视频中文字幕在线 | 久久久高清日本道免费观看 | 亚洲视频在线观看免费视频 | 最近最新中文字幕大全2019免费视频 | 中文字幕亚洲欧美日韩不卡 | 日本护士xxxxx在线 | 精品国产免费久久久久久 | 亚洲欧洲高清有无 | 久久精品国产精品亚洲毛片 | 国产精品合集一区二区三区 | 成人中文字幕在线 | 最近手机中文字幕1 | 春色视频www免费视频观看 | 亚洲欧美日韩在线精品一区二区 | adc欧美成人影院 | 伊人亚洲 | 老司机午夜免费福利视频 | 欧美重口另类videos人妖 | 成人永久福利在线观看不卡 | 亚洲国产精品久久卡一 | 国产亚洲精品欧美一区 | 国产精品国产三级国产专不∫ | 国产成人综合久久 | 波多野结衣国产一区二区三区 | 国产成人一区二区三区精品久久 | 日本高清无卡码一区二区久久 | 国产高清国内精品福利99久久 | 久久久久国产一级毛片高清版 | 男女xx00| 国产亚洲精品久久久久久无 | 97色婷婷成人综合在线观看 |