- 調(diào)用下面的方法,得到的返回值是什么?
public int getNum() {
try {
int a = 1 / 0;
return 1;
} catch (Exception e) {
return 2;
} finally {
return 3;
}
}
代碼在走到第 3 行的時(shí)候遇到了一個(gè) MathException,這時(shí)第四行的代碼就不會(huì)執(zhí)行了,代碼直接跳轉(zhuǎn)到catch 語(yǔ)句中,走到第 6 行的時(shí)候,異常機(jī)制有這么一個(gè)原則“如果在 catch 中遇到了 return 或者異常等能使該函數(shù)終止的話,那么用 finally 就必須先執(zhí)行完 finally 代碼塊里面的代碼然后再返回值。”因此代碼又跳到第 8行,可惜第 8 行是一個(gè) return 語(yǔ)句,那么這個(gè)時(shí)候方法就結(jié)束了,因此第 6 行的返回結(jié)果就無法被真正返回。如果 finally 僅僅是處理了一個(gè)釋放資源的操作,那么該道題最終返回的結(jié)果就是 2。因此上面返回值是 3。
Java 的基本數(shù)據(jù)類型都有哪些各占幾個(gè)字節(jié)?
Java 有 8 種基本數(shù)據(jù)類型
byte 1
char 2
sort 2
int 4
float 4
double 8
long 8
boolean 1(boolean 類型比較特別可能只占一個(gè) bit,多個(gè) boolean 可能共同占用一個(gè)字節(jié))String 是基本數(shù)據(jù)類型嗎?可以被繼承嗎?
String是引用類型,底層是用char數(shù)組實(shí)現(xiàn)的,String是final類,java 中被final修飾的類不能被繼承,所以String不能被繼承。在 java 中 wait 和 sleep 方法的不同?
最大的不同是wait會(huì)釋放鎖,sleep會(huì)一直持有鎖。wait通常用于線程間交互,sleep用于暫停執(zhí)行。什么是線程池,如何使用?
線程池就是事先將多個(gè)線程對(duì)象放到一個(gè)容器里,當(dāng)使用的時(shí)候就不用new而是直接去線程池中拿線程即可,節(jié)省了開辟子線程的時(shí)間,提高了代碼的執(zhí)行效率。
在 JDK 的 java.util.concurrent.Executors 中提供了生成多種線程池的靜態(tài)方法。
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(4);
ScheduledExecutorService newScheduledThreadPool =
Executors.newScheduledThreadPool(4);
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
然后調(diào)用他們的 execute 方法即可。
- Java 中的反射
說說你對(duì) Java 中反射的理解?
Java 中 的 反 射 首 先 是 能 夠 獲 取 到 Java 中 要 反 射 類 的 字 節(jié) 碼 , 獲 取 字 節(jié) 碼 有 三 種 方 法 :1.Class.forName(className) 2.類名.class 3.this.getClass()。然后將字節(jié)碼中的方法,變量,構(gòu)造函數(shù)等映射成相應(yīng)的 Method、Filed、Constructor 等類,這些類提供了豐富的方法可以被我們所使用。 - Java 中的動(dòng)態(tài)代理
寫一個(gè) ArrayList 的動(dòng)態(tài)代理類
final List<String> list = new ArrayList<String>();
List<String> proxyInstance = (List<String>)
Proxy.newProxyInstance(list.getClass().getClassLoader(),
list.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
return method.invoke(list, args);
}
});
proxyInstance.add("你好");
System.out.println(list);
- Java 中的設(shè)計(jì)模式
Java 中一般認(rèn)為有 23 種設(shè)計(jì)模式,我們不需要所有的都會(huì),但是其中常用的幾種設(shè)計(jì)模式應(yīng)該去掌握。下面列
出了所有的設(shè)計(jì)模式。需要掌握的設(shè)計(jì)模式我單獨(dú)列出來了,當(dāng)然能掌握的越多越好。
總體來說設(shè)計(jì)模式分為三大類:
創(chuàng)建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結(jié)構(gòu)型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責(zé)任鏈模式、命令模式、備忘錄
模式、狀態(tài)模式、訪問者模式、中介者模式、解釋器模式。 - 寫 10 個(gè)簡(jiǎn)單的 linux 命令
mkdir 創(chuàng)建文件夾
rmdir 刪除文件夾
rm 刪除文件
mv 移動(dòng)文件
cp 拷貝文件
cat 查看文件
tail 查看文件尾部
more 分頁(yè)查看文件
cd 切換當(dāng)前目錄
ls 列出文件清單
reboot 重啟
date 顯示日期
cal 顯示日歷
ps 查看系統(tǒng)進(jìn)程相當(dāng)于 windows 的任務(wù)管理器
ifconfig 配置網(wǎng)絡(luò) - Service 是否在 main thread 中執(zhí)行, service 里面是否能執(zhí)行耗時(shí)的操作?
默認(rèn)情況,如果沒有顯示的指 service 所運(yùn)行的進(jìn)程, Service 和 activity 是運(yùn)行在當(dāng)前 app 所在進(jìn)程的 main thread(UI 主線程)里面。service 里面不能執(zhí)行耗時(shí)的操作(網(wǎng)絡(luò)請(qǐng)求,拷貝數(shù)據(jù)庫(kù),大文件 )
特殊情況 ,可以在清單文件配置 service 執(zhí)行所在的進(jìn)程 ,讓 service 在另外的進(jìn)程中執(zhí)行。
<service android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" ></service>
- Serializable 和 Parcelable 的區(qū)別
1.在使用內(nèi)存的時(shí)候,Parcelable類會(huì)比Serializable性能高,所以推薦使用Parcelable。
2.Serializable在進(jìn)行序列化的時(shí)候會(huì)產(chǎn)生大量的臨時(shí)變量,從而引起頻繁的GC。
3.Parcelable 不能使用在要將數(shù)據(jù)存儲(chǔ)在磁盤上的情況。盡管 Serializable 效率低點(diǎn),但在這種情況下,還是建議你用 Serializable 。
實(shí)現(xiàn):
Serializable 的實(shí)現(xiàn),只需要繼承 Serializable 即可。這只是給對(duì)象打了一個(gè)標(biāo)記,系統(tǒng)會(huì)自動(dòng)將其序列化。
Parcelabel 的實(shí)現(xiàn),需要在類中添加一個(gè)靜態(tài)成員變量 CREATOR,這個(gè)變量需要繼承 Parcelable.Creator 接
口。
public class MyParcelable implements Parcelable {
private int mData;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mData);
}
public static final Parcelable.Creator<MyParcelable> CREATOR= new Parcelable.Creator<MyParcelable>() {
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}
public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};
private MyParcelable(Parcel in) {
mData = in.readInt();
}
}
- 請(qǐng)描述一下 Intent 和 IntentFilter
Android 中通過 Intent 對(duì)象來表示一條消息,一個(gè) Intent 對(duì)象不僅包含有這個(gè)消息的目的地,還可以包含消息的內(nèi)容,這好比一封 Email,其中不僅應(yīng)該包含收件地址,還可以包含具體的內(nèi)容。對(duì)于一個(gè) Intent 對(duì)象,消息“目的地”是必須的,而內(nèi)容則是可選項(xiàng)。
通過 Intent 可以實(shí)現(xiàn)各種系統(tǒng)組件的調(diào)用與激活.
IntentFilter: 可以理解為郵局或者是一個(gè)信箋的分揀系統(tǒng).
這個(gè)分揀系統(tǒng)通過 3 個(gè)參數(shù)來識(shí)別 :
Action: 動(dòng)作 view
Data: 數(shù)據(jù) uri uri
Category : 而外的附加信息 - Fragment 跟 Activity 之間是如何傳值的
當(dāng) Fragment 跟 Activity 綁定之后,在 Fragment 中可以直接通過 getActivity()方法獲取到其綁定的 Activity對(duì)象,這樣就可以調(diào)用 Activity 的方法了。在 Activity 中可以通過如下方法獲取Fragment 實(shí)例 。
FragmentManager fragmentManager = getFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(tag);
Fragment fragment = fragmentManager.findFragmentById(id);
獲取到 Fragment 之后就可以調(diào)用 Fragment 的方法。也就實(shí)現(xiàn)了通信功能。
- 如何避免 OOM 異常
1、圖片過大導(dǎo)致 OOM
Android 中用 bitmap 時(shí)很容易內(nèi)存溢出,比如報(bào)如下錯(cuò)誤:Java.lang.OutOfMemoryError : bitmap size exceeds VM budget
解決方法:
方法 1: 等比例縮小圖片
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
//Options 只保存圖片尺寸大小,不保存圖片到內(nèi)存
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2;
Bitmap bmp = null;
bmp = BitmapFactory.decodeResource(getResources(),
mImageIds[position],opts);
//回收
bmp.recycle();
以上代碼可以優(yōu)化內(nèi)存溢出,但它只是改變圖片大小,并不能徹底解決內(nèi)存溢出
方法 2:對(duì)圖片采用軟引用,及時(shí)地進(jìn)行 recyle()操作
SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(pBitmap);
if(bitmap != null){
if(bitmap.get() != null && !bitmap.get().isRecycled()){
bitmap.get().recycle();
bitmap = null;
}
}
2、界面切換導(dǎo)致 OOM
有時(shí)候我們會(huì)發(fā)現(xiàn)這樣的問題,橫豎屏切換 N 次后 OOM 了。
2.1、看看頁(yè)面布局當(dāng)中有沒有大的圖片,比如背景圖之類的。
去除 xml 中相關(guān)設(shè)置,改在程序中設(shè)置背景圖(放在 onCreate()方法中):
Drawable drawable = getResources().getDrawable(R.drawable.id);
ImageView imageView = new ImageView(this);
imageView.setBackgroundDrawable(drawable);
在 Activity destory 時(shí)注意,drawable.setCallback(null); 防止 Activity 得不到及時(shí)的釋放.
2.2 、 跟 上 面 方 法 相 似 , 直 接 把 xml 配 置 文 件 加 載 成 view 再 放 到 一 個(gè) 容 器 里 , 然 后 直 接 調(diào) 用
this.setContentView(View view);方法,避免 xml 的重復(fù)加載。
2.3、 在頁(yè)面切換時(shí)盡可能少地重復(fù)使用一些代碼
比如:重復(fù)調(diào)用數(shù)據(jù)庫(kù),反復(fù)使用某些對(duì)象等等......
常見的內(nèi)存使用不當(dāng)?shù)那闆r
3、查詢數(shù)據(jù)庫(kù)沒有關(guān)閉游標(biāo) 查詢數(shù)據(jù)庫(kù)沒有關(guān)閉游標(biāo) 查詢數(shù)據(jù)庫(kù)沒有關(guān)閉游標(biāo)
程序中經(jīng)常會(huì)進(jìn)行查詢數(shù)據(jù)庫(kù)的操作,但是經(jīng)常會(huì)有使用完畢 Cursor 后沒有關(guān)閉的情況。如果我們的查詢結(jié)果集比較小,對(duì)內(nèi)存的消耗不容易被發(fā)現(xiàn),只有在常時(shí)間大量操作的情況下才會(huì)出現(xiàn)內(nèi)存問題,這樣就會(huì)給以后的測(cè)試和問題排查帶來困難和風(fēng)險(xiǎn)。
4、構(gòu)造 Adapter Adapter Adapter 時(shí),沒有使用緩存的 沒有使用緩存的 沒有使用緩存的convertView convertView convertView
在使用 ListView 的時(shí)候通常會(huì)使用 Adapter,那么我們應(yīng)該盡可能的使用 ConvertView。
5、Bitmap 對(duì)象不再使用時(shí)調(diào)用 對(duì)象不再使用時(shí)調(diào)用 對(duì)象不再使用時(shí)調(diào)用 recycle() recycle() recycle()釋放內(nèi)存.
有時(shí)我們會(huì)手工的操作 Bitmap 對(duì)象,如果一個(gè) Bitmap 對(duì)象比較占內(nèi)存,當(dāng)它不再被使用的時(shí)候,可以調(diào)用Bitmap.recycle()方法回收此對(duì)象的像素所占用的內(nèi)存,但這不是必須的,視情況而定。
6、其他
Android 應(yīng)用程序中最典型的需要注意釋放資源的情況是在 Activity 的生命周期中,在 onPause()、onStop()、onDestroy()方法中需要適當(dāng)?shù)尼尫刨Y源的情況。
- Android 中如何捕獲未捕獲的異常
1、自定義一個(gè) Application,比如叫 MyApplication 繼承 Application 實(shí)現(xiàn) UncaughtExceptionHandler。
2、覆寫 UncaughtExceptionHandler 的 onCreate 和 uncaughtException 方法。
@Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(final Thread thread, final Throwable ex) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
System.out.println(Thread.currentThread());
Toast.makeText(getApplicationContext(), "thread="+thread.getId()+"
ex="+ex.toString(), 1).show();
Looper.loop();
}
}).start();
SystemClock.sleep(3000);
android.os.Process.killProcess(android.os.Process.myPid());
}
}
注意:上面的代碼只是簡(jiǎn)單的將異常打印出來。
在 onCreate 方法中我們給 Thread 類設(shè)置默認(rèn)異常處理 handler,如果這句代碼不執(zhí)行則一切都是白搭。
在 uncaughtException 方法中我們必須新開辟個(gè)線程進(jìn)行我們異常的收集工作,然后將系統(tǒng)給殺死.
3、在 AndroidManifest 中配置該 Application
<application
android:name="com.example.uncatchexception.MyApplication"/>
- 請(qǐng)描述一下 View 的繪制流程
整個(gè) View 樹的繪圖流程是在 ViewRoot.java 類(該類位于 Android 源碼下面:
D:\AndroidSource_GB\AndroidSource_GB\frameworks\base\core\java\android\view)的performTraversals()函數(shù)展開的,該函數(shù)做的執(zhí)行過程可簡(jiǎn)單概況為根據(jù)之前設(shè)置的狀態(tài),判斷是否需要重新計(jì)算視圖大小(measure)、是否重新需要安置視圖的位置(layout)、以及是否需要重繪 (draw),其框架過程如下:

由 ViewRoot 對(duì)象的 performTraversals()方法調(diào)用 draw()方法發(fā)起繪制該 View 樹,值得注意的是每次發(fā)起繪
圖時(shí),并不會(huì)重新繪制每個(gè) View 樹的視圖,而只會(huì)重新繪制那些“需要重繪”的視圖,View 類內(nèi)部變量包含了一個(gè)
標(biāo)志位 DRAWN,當(dāng)該視圖需要重繪時(shí),就會(huì)為該 View 添加該標(biāo)志位。
Handler 機(jī)制
Android 中主線程也叫 UI 線程,那么從名字上我們也知道主線程主要是用來創(chuàng)建、更新 UI 的,而其他耗時(shí)操作,比如網(wǎng)絡(luò)訪問,或者文件處理,多媒體處理等都需要在子線程中操作,之所以在子線程中操作是為了保證 UI 的流暢程度,手機(jī)顯示的刷新頻率是 60Hz,也就是一秒鐘刷新 60 次,每 16.67 毫秒刷新一次,為了不丟幀,那么主線程處理代碼最好不要超過 16 毫秒。當(dāng)子線程處理完數(shù)據(jù)后,為了防止 UI 處理邏輯的混亂,Android 只允許主線程修改 UI,那么這時(shí)候就需要 Handler 來充當(dāng)子線程和主線程之間的橋梁了。我們通常將 Handler 聲明在 Activity 中,然后覆寫 Handler 中的 handleMessage 方法,當(dāng)子線程調(diào)用handler.sendMessage()方法后 handleMessage 方法就會(huì)在主線程中執(zhí)行。這里面除了 Handler、Message 外還有隱藏的 Looper 和 MessageQueue 對(duì)象。
在主線程中 Android 默認(rèn)已經(jīng)調(diào)用了 Looper.preper()方法,調(diào)用該方法的目的是在 Looper 中創(chuàng)建MessageQueue 成員變量并把 Looper 對(duì)象綁定到當(dāng)前線程中。當(dāng)調(diào)用 Handler sendMessage(對(duì)象)方法的時(shí)候就將 Message 對(duì)象添加到了 Looper 創(chuàng)建的 MessageQueue 隊(duì)列中,同時(shí)給 Message 指定了 target 對(duì)象,其實(shí)這個(gè) target 對(duì)象就是 Handler 對(duì)象。主線程默認(rèn)執(zhí)行了Looper.looper()方法,該方法從 Looper 的成員變量MessageQueue 中取出 Message,然后調(diào)用 Message 的 target 對(duì)象的 handleMessage()方法。這樣就完成了整個(gè)消息機(jī)制。事件分發(fā)中的 2.1 事件分發(fā)中的 onTouch onTouch onTouch 和 onTouchEvent onTouchEvent onTouchEvent 有什么區(qū)別,又該如何使用?
這兩個(gè)方法都是在 View 的 dispatchTouchEvent 中調(diào)用的onTouch 優(yōu)先于 onTouchEvent 執(zhí)行。如果在onTouch 方法中通過返回 true 將事件消費(fèi)掉,onTouchEvent 將不會(huì)再執(zhí)行。
另外需要注意的是,onTouch 能夠得到執(zhí)行需要兩個(gè)前提條件,第一 mOnTouchListener 的值不能為空,第二當(dāng)前點(diǎn)擊的控件必須是 enable 的。因此如果你有一個(gè)控件是非 enable 的,那么給它注冊(cè) onTouch 事件將永遠(yuǎn)得不到執(zhí)行。對(duì)于這一類控件,如果我們想要監(jiān)聽它的 touch 事件,就必須通過在該控件中重寫 onTouchEvent 方法來實(shí)現(xiàn)。講一下android中進(jìn)程的優(yōu)先級(jí)?
前臺(tái)進(jìn)程
可見進(jìn)程
服務(wù)進(jìn)程
后臺(tái)進(jìn)程
空進(jìn)程Map、Set、List、Queue、Stack的特點(diǎn)與用法。
Collection 是對(duì)象集合, Collection 有兩個(gè)子接口 List 和 Set
List 可以通過下標(biāo) (1,2..) 來取得值,值可以重復(fù)。
而 Set 只能通過游標(biāo)來取值,并且值是不能重復(fù)的。
ArrayList , Vector , LinkedList 是 List 的實(shí)現(xiàn)類。
ArrayList 是線程不安全的, Vector 是線程安全的,這兩個(gè)類底層都是由數(shù)組實(shí)現(xiàn)的。
LinkedList 是線程不安全的,底層是由鏈表實(shí)現(xiàn)的。
Map 是鍵值對(duì)集合:
HashTable 和 HashMap 是 Map 的實(shí)現(xiàn)類。
HashTable 是線程安全的,不能存儲(chǔ) null 值。
HashMap 不是線程安全的,可以存儲(chǔ) null 值。
Stack類:繼承自Vector,實(shí)現(xiàn)一個(gè)后進(jìn)先出的棧。提供了幾個(gè)基本方法,push、pop、peak、empty、search等。
Queue接口:提供了幾個(gè)基本方法,offer、poll、peek等。已知實(shí)現(xiàn)類有LinkedList、PriorityQueue等。
21.Java中==和equals的區(qū)別,equals和hashCode的區(qū)別
java中的數(shù)據(jù)類型,可分為兩類:
a. 基本數(shù)據(jù)類型:byte short long int char double boolean float .它們之間的比較應(yīng)當(dāng)用(==),比較的是他們的值。
b. 復(fù)合數(shù)據(jù)類型(類) :當(dāng)他們用(==)進(jìn)行比較的時(shí)候,比較的是他們?cè)趦?nèi)存中的存放地址,所以,除非是同一個(gè)new出來的對(duì)象,他們的比較后的結(jié)果為true,否則比較后結(jié)果為false。
equals方法:
JAVA當(dāng)中所有的類都是繼承于Object這個(gè)基類的,在Object中的基類中定義了一個(gè)equals的方法,這個(gè)方法的初始行為是比較對(duì)象的內(nèi)存地址,但在一些類庫(kù)當(dāng)中這個(gè)方法被覆蓋掉了,如String,Integer,Date在這些類當(dāng)中equals有其自身的實(shí)現(xiàn),而不再是比較類在堆內(nèi)存中的存放地址了。
hashCode 方法:
如果兩個(gè)對(duì)象根據(jù)equals()方法比較是相等的,那么調(diào)用這兩個(gè)對(duì)象中任意一個(gè)對(duì)象的hashCode方法都必須產(chǎn)生同樣的整數(shù)結(jié)果。
如果兩個(gè)對(duì)象根據(jù)equals()方法比較是不相等的,那么調(diào)用這兩個(gè)對(duì)象中任意一個(gè)對(duì)象的hashCode方法,則不一定要產(chǎn)生相同的整數(shù)結(jié)果。
從而在集合操作的時(shí)候有如下規(guī)則:
將對(duì)象放入到集合中時(shí),首先判斷要放入對(duì)象的hashcode值與集合中的任意一個(gè)元素的hashcode值是否相等,如果不相等直接將該對(duì)象放入集合中。如果hashcode值相等,然后再通過equals方法判斷要放入對(duì)象與集合中的任意一個(gè)對(duì)象是否相等,如果equals判斷不相等,直接將該元素放入到集合中,否則不放入。
Android性能優(yōu)化
- 節(jié)制的使用Service,當(dāng)啟動(dòng)一個(gè)Service時(shí),系統(tǒng)會(huì)傾向于將這個(gè)Service所依賴的進(jìn)程進(jìn)行保留,系統(tǒng)可以在LRUcache當(dāng)中緩存的進(jìn)程數(shù)量也會(huì)減少,導(dǎo)致切換程序的時(shí)候耗費(fèi)更多性能。我們可以使用IntentService,當(dāng)后臺(tái)任務(wù)執(zhí)行結(jié)束后會(huì)自動(dòng)停止,避免了Service的內(nèi)存泄漏。
知曉內(nèi)存的開支情況
- 使用枚舉通常會(huì)比使用靜態(tài)常量消耗兩倍以上的內(nèi)存,盡可能不使用枚舉
- 任何一個(gè)Java類,包括匿名類、內(nèi)部類,都要占用大概500字節(jié)的內(nèi)存空間
- 任何一個(gè)類的實(shí)例要消耗12-16字節(jié)的內(nèi)存開支,因此頻繁創(chuàng)建實(shí)例也是會(huì)在一定程序上影響內(nèi)存的
- 使用HashMap時(shí),即使你只設(shè)置了一個(gè)基本數(shù)據(jù)類型的鍵,比如說int,但是也會(huì)按照對(duì)象的大小來分配內(nèi)存,大概是32字節(jié),而不是4字節(jié),因此最好使用優(yōu)化后的數(shù)據(jù)集合
避免創(chuàng)建不必要的對(duì)象 - 如果有需要拼接的字符串,那么可以優(yōu)先考慮使用StringBuffer或者StringBuilder來進(jìn)行拼接,而不是加號(hào)連接符,因?yàn)槭褂眉犹?hào)連接符會(huì)創(chuàng)建多余的對(duì)象,拼接的字符串越長(zhǎng),加號(hào)連接符的性能越低。
- 當(dāng)一個(gè)方法的返回值是String的時(shí)候,通常需要去判斷一下這個(gè)String的作用是什么,如果明確知道調(diào)用方會(huì)將返回的String再進(jìn)行拼接操作的話,可以考慮返回一個(gè)StringBuffer對(duì)象來代替,因?yàn)檫@樣可以將一個(gè)對(duì)象的引用進(jìn)行返回,而返回String的話就是創(chuàng)建了一個(gè)短生命周期的臨時(shí)對(duì)象。
- 在沒有特殊原因的情況下,盡量使用基本數(shù)據(jù)類型來代替封裝數(shù)據(jù)類型,int比Integer要更加有效,其它數(shù)據(jù)類型也是一樣。
僅在需要時(shí)才加載布局
舉例:填信息時(shí)不是需要全部填的,有一個(gè)添加更多字段的選項(xiàng),當(dāng)用戶需要添加其他信息的時(shí)候,才將另外的元素顯示到界面上。用VISIBLE性能表現(xiàn)一般,可以用ViewStub。ViewStub也是View的一種,但是沒有大小,沒有繪制功能,也不參與布局,資源消耗非常低,可以認(rèn)為完全不影響性能。
<ViewStub
android:id="@+id/view_stub"
android:layout="@layout/profile_extra"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
public void onMoreClick() {
ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);
if (viewStub != null) {
View inflatedView = viewStub.inflate();
editExtra1 = (EditText) inflatedView.findViewById(R.id.edit_extra1);
editExtra2 = (EditText) inflatedView.findViewById(R.id.edit_extra2);
editExtra3 = (EditText) inflatedView.findViewById(R.id.edit_extra3);
}
}
為什么在Service中創(chuàng)建子線程而不是Activity中?
這是因?yàn)锳ctivity很難對(duì)Thread進(jìn)行控制,當(dāng)Activity被銷毀之后,就沒有任何其它的辦法可以再重新獲取到之前創(chuàng)建的子線程的實(shí)例。而且在一個(gè)Activity中創(chuàng)建的子線程,另一個(gè)Activity無法對(duì)其進(jìn)行操作。但是Service就不同了,所有的Activity都可以與Service進(jìn)行關(guān)聯(lián),然后可以很方便地操作其中的方法,即使Activity被銷毀了,之后只要重新與Service建立關(guān)聯(lián),就又能夠獲取到原有的Service中Binder的實(shí)例。因此,使用Service來處理后臺(tái)任務(wù),Activity就可以放心地finish,完全不需要擔(dān)心無法對(duì)后臺(tái)任務(wù)進(jìn)行控制的情況。
哪些操作會(huì)導(dǎo)致ANR 在主線程執(zhí)行以下操作:
- 高耗時(shí)的操作,如圖像變換 2. 磁盤讀寫,數(shù)據(jù)庫(kù)讀寫操作 3. 大量的創(chuàng)建新對(duì)象
String、StringBuilder、StringBuffer、CharSequence區(qū)別
1)CharSequence接口:是一個(gè)字符序列.String StringBuilder 和 StringBuffer都實(shí)現(xiàn)了它.
- String類:是常量,不可變.
- StringBuilder類;只可以在單線程的情況下進(jìn)行修改(線程不安全).
- StringBuffer類:可以在多線程的情況下進(jìn)行改變(線程安全). 5)Stringbuilder比StringBuffer效率高,應(yīng)該盡量使用StringBuilder.
1.CharSequence是一個(gè)java接口,代表一個(gè)char序列,String、StringBuilder、StringBuffer都實(shí)現(xiàn)了該接口,CharSequence實(shí)例通過調(diào)用toString方法可轉(zhuǎn)化為String對(duì)象。
2.String類是final的,不可派生子類,其內(nèi)部封裝的是char[],另外,android下的String類和jdk中的String類是有區(qū)別的,android下的String類中部分API通過native方法實(shí)現(xiàn),效率相對(duì)高一些。
3.String使用'+'進(jìn)行字符串拼接時(shí),在編譯期會(huì)轉(zhuǎn)化為StringBuilder#append方式
4.String在內(nèi)存中有一個(gè)常量池,兩個(gè)相同的串在池中只有一份實(shí)例(String s = "abc"方式或者String#intern方式會(huì)在池中分配),使用new String方式會(huì)在heap中分配,每次創(chuàng)建都是一個(gè)全新的實(shí)例。
5.StrigBuilder & StringBuffer都是可擴(kuò)展的串,提供了一系列apped方法用于拼接不同類型對(duì)象
6.StringBuffer于jdk1.0引入,線程安全(多線程場(chǎng)景下使用),StringBuilder于jdk1.5引入,線程不安全,因而效率更高。
7.StringBuilder & StringBuffer初始容量都為16,開發(fā)者應(yīng)該指定其容量,以避免多次擴(kuò)容所帶來的性能問題。
要做一個(gè)盡可量流暢的ListView,你可以做到的優(yōu)化手段是什么?越詳細(xì)越多手段越好
復(fù)用convertView
使用ViewHolder
滑動(dòng)時(shí)不加載圖片
Item中有圖片時(shí) 異步加載 并且對(duì)圖片進(jìn)行適當(dāng)壓縮
分批,分頁(yè)加載
Java中反射的作用是什么?什么時(shí)候會(huì)用到
對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;
對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為java語(yǔ)言的反射機(jī)制。
Java反射機(jī)制主要提供了以下功能:
a)在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類;
b)在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象;
c)在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法;
d)在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法;生成動(dòng)態(tài)代理。
Java中有內(nèi)存泄露嗎?舉一些例子?
1.查詢數(shù)據(jù)庫(kù)沒有關(guān)閉游標(biāo)
- 構(gòu)造Adapter時(shí),沒有使用緩存的 convertView
- Bitmap對(duì)象不再使用時(shí)調(diào)用recycle()釋放內(nèi)存
- 無用時(shí)沒有釋放對(duì)象的引用
- 在Activity中使用非靜態(tài)的內(nèi)部類,并開啟一個(gè)長(zhǎng)時(shí)間運(yùn)行的線程,因?yàn)閮?nèi)部類持有Activity的引用,會(huì)導(dǎo)致Activity本來可以被gc時(shí)卻長(zhǎng)期得不到回收
6.使用Handler處理消息前,Activity通過例如finish()退出,導(dǎo)致內(nèi)存泄漏
7.動(dòng)態(tài)注冊(cè)廣播在Activity銷毀前沒有unregisterReceiver
如何縮減APK包大小
代碼
保持良好的編程習(xí)慣,不要重復(fù)或者不用的代碼,謹(jǐn)慎添加libs,移除使用不到的libs。
使用proguard混淆代碼,它會(huì)對(duì)不用的代碼做優(yōu)化,并且混淆后也能夠減少安裝包的大小。
native code的部分,大多數(shù)情況下只需要支持armabi與x86的架構(gòu)即可。如果非必須,可以考慮拿掉x86的部分。
資源
使用Lint工具查找沒有使用到的資源。去除不使用的圖片,String,XML等等。
assets目錄下的資源請(qǐng)確保沒有用不上的文件。
生成APK的時(shí)候,aapt工具本身會(huì)對(duì)png做優(yōu)化,但是在此之前還可以使用其他工具如tinypng對(duì)圖片進(jìn)行進(jìn)一步的壓縮預(yù)處理。
jpeg還是png,根據(jù)需要做選擇,在某些時(shí)候jpeg可以減少圖片的體積。
對(duì)于9.png的圖片,可拉伸區(qū)域盡量切小,另外可以通過使用9.png拉伸達(dá)到大圖效果的時(shí)候盡量不要使用整張大圖。
策略
有選擇性的提供hdpi,xhdpi,xxhdpi的圖片資源。建議優(yōu)先提供xhdpi的圖片,對(duì)于mdpi,ldpi與xxxhdpi根據(jù)需要提供有差異的部分即可。
盡可能的重用已有的圖片資源。例如對(duì)稱的圖片,只需要提供一張,另外一張圖片可以通過代碼旋轉(zhuǎn)的方式實(shí)現(xiàn)。
能用代碼繪制實(shí)現(xiàn)的功能,盡量不要使用大量的圖片。例如減少使用多張圖片組成animate-list的AnimationDrawable,這種方式提供了多張圖片很占空間。
聲明ViewHolder內(nèi)部類時(shí),為什么建議使用static關(guān)鍵字
這個(gè)是考靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類的主要區(qū)別之一。非靜態(tài)內(nèi)部類會(huì)隱式持有外部類的引用,就像大家經(jīng)常將自定義的adapter在Activity類里,然后在adapter類里面是可以隨意調(diào)用外部activity的方法的。當(dāng)你將內(nèi)部類定義為static時(shí),你就調(diào)用不了外部類的實(shí)例方法了,因?yàn)檫@時(shí)候靜態(tài)內(nèi)部類是不持有外部類的引用的。聲明ViewHolder靜態(tài)內(nèi)部類,可以將ViewHolder和外部類解引用。大家會(huì)說一般ViewHolder都很簡(jiǎn)單,不定義為static也沒事吧。確實(shí)如此,但是如果你將它定義為static的,說明你懂這些含義。萬(wàn)一有一天你在這個(gè)ViewHolder加入一些復(fù)雜邏輯,做了一些耗時(shí)工作,那么如果ViewHolder是非靜態(tài)內(nèi)部類的話,就很容易出現(xiàn)內(nèi)存泄露。如果是靜態(tài)的話,你就不能直接引用外部類,迫使你關(guān)注如何避免相互引用。 所以將 ViewHolder內(nèi)部類 定義為靜態(tài)的,是一種好習(xí)慣.
java是如何管理內(nèi)存的
Java的內(nèi)存管理就是對(duì)象的分配和釋放問題。(兩部分)
分配 :內(nèi)存的分配是由程序完成的,程序員需要通過關(guān)鍵字new 為每個(gè)對(duì)象申請(qǐng)內(nèi)存空間 (基本類型除外),所有的對(duì)象都在堆 (Heap)中分配空間。
釋放 :對(duì)象的釋放是由垃圾回收機(jī)制決定和執(zhí)行的,這樣做確實(shí)簡(jiǎn)化了程序員的工作。但同時(shí),它也加重了JVM的工作。因?yàn)?,GC為了能夠正確釋放對(duì)象,GC必須監(jiān)控每一個(gè)對(duì)象的運(yùn)行狀態(tài),包括對(duì)象的申請(qǐng)、引用、被引用、賦值等,GC都需要進(jìn)行監(jiān)控。
JVM的內(nèi)存區(qū)域組成
java把內(nèi)存分兩種:一種是棧內(nèi)存,另一種是堆內(nèi)存
1。在函數(shù)中定義的基本類型變量和對(duì)象的引用變量都在函數(shù)的棧內(nèi)存中分配;
2。堆內(nèi)存用來存放由new創(chuàng)建的對(duì)象和數(shù)組以及對(duì)象的實(shí)例變量 在函數(shù)(代碼塊)中定義一個(gè)變量時(shí),java就在棧中為這個(gè)變量分配內(nèi)存空間,當(dāng)超過變量的作用域后,java會(huì)自動(dòng)釋放掉為該變量所分配的內(nèi)存空間;在堆中分配的內(nèi)存由java虛擬機(jī)的自動(dòng)垃圾回收器來管理.
堆和棧的優(yōu)缺點(diǎn)
堆的優(yōu)勢(shì)是可以動(dòng)態(tài)分配內(nèi)存大小,生存期也不必事先告訴編譯器,因?yàn)樗窃谶\(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存的。
缺點(diǎn)就是要在運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存,存取速度較慢; 棧的優(yōu)勢(shì)是,存取速度比堆要快,僅次于直接位于CPU中的寄存器。
另外,棧數(shù)據(jù)可以共享。但缺點(diǎn)是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。
垃圾回收機(jī)制:
(問題一:什么叫垃圾回收機(jī)制?)
垃圾回收是一種動(dòng)態(tài)存儲(chǔ)管理技術(shù),它自動(dòng)地釋放不再被程序引用的對(duì)象,按照特定的垃圾收集算法來實(shí)現(xiàn)資源自動(dòng)回收的功能。當(dāng)一個(gè)對(duì)象不再被引用的時(shí)候,內(nèi)存回收它占領(lǐng)的空間,以便空間被后來的新對(duì)象使用,以免造成內(nèi)存泄露。
(問題二:java的垃圾回收有什么特點(diǎn)?)
JAVA語(yǔ)言不允許程序員直接控制內(nèi)存空間的使用。內(nèi)存空間的分配和回收都是由JRE負(fù)責(zé)在后臺(tái)自動(dòng)進(jìn)行的,尤其是無用內(nèi)存空間的回收操作(garbagecollection,也稱垃圾回收),只能由運(yùn)行環(huán)境提供的一個(gè)超級(jí)線程進(jìn)行監(jiān)測(cè)和控制。
(問題四:什么樣的對(duì)象符合垃圾回收條件?) 當(dāng)沒有任何獲得線程能訪問一個(gè)對(duì)象時(shí),該對(duì)象就符合垃圾回收條件。
(問題五:垃圾回收器是怎樣工作的?)
垃圾回收器如發(fā)現(xiàn)一個(gè)對(duì)象不能被任何活線程訪問時(shí),他將認(rèn)為該對(duì)象符合刪除條件,就將其加入回收隊(duì)列,但不是立即銷毀對(duì)象,何時(shí)銷毀并釋放內(nèi)存是無法預(yù)知的。垃圾回收不能強(qiáng)制執(zhí)行,然而Java提供了一些方法(如:System.gc()方法),允許你請(qǐng)求JVM執(zhí)行垃圾回收,而不是要求,虛擬機(jī)會(huì)盡其所能滿足請(qǐng)求,但是不能保證JVM從內(nèi)存中刪除所有不用的對(duì)象。
(問題六:一個(gè)java程序能夠耗盡內(nèi)存嗎?) 可以。垃圾收集系統(tǒng)嘗試在對(duì)象不被使用時(shí)把他們從內(nèi)存中刪除。然而,如果保持太多活的對(duì)象,系統(tǒng)則可能會(huì)耗盡內(nèi)存。垃圾回收器不能保證有足夠的內(nèi)存,只能保證可用內(nèi)存盡可能的得到高效的管理。
(問題七:如何顯示的使對(duì)象符合垃圾回收條件?) (1) 空引用 :當(dāng)對(duì)象沒有對(duì)他可到達(dá)引用時(shí),他就符合垃圾回收的條件。也就是說如果沒有對(duì)他的引用,刪除對(duì)象的引用就可以達(dá)到目的,因此我們可以把引用變量設(shè)置為null,來符合垃圾回收的條件。
StringBuffer sb = new StringBuffer("hello");
System.out.println(sb);
sb=null;
(2) 重新為引用變量賦值:可以通過設(shè)置引用變量引用另一個(gè)對(duì)象來解除該引用變量與一個(gè)對(duì)象間的引用關(guān)系。
StringBuffer sb1 = new StringBuffer("hello");
StringBuffer sb2 = new StringBuffer("goodbye");
System.out.println(sb1);
sb1=sb2;//此時(shí)"hello"符合回收條件
(3) 方法內(nèi)創(chuàng)建的對(duì)象:所創(chuàng)建的局部變量?jī)H在該方法的作用期間內(nèi)存在。一旦該方法返回,在這個(gè)方法內(nèi)創(chuàng)建的對(duì)象就符合垃圾收集條件。有一種明顯的例外情況,就是方法的返回對(duì)象。
public static void main(String[] args) {
Date d = getDate();
System.out.println("d = " + d);
}
private static Date getDate() {
Date d2 = new Date();
StringBuffer now = new StringBuffer(d2.toString());
System.out.println(now);
return d2;
}
(4) 隔離引用:這種情況中,被回收的對(duì)象仍具有引用,這種情況稱作隔離島。若存在這兩個(gè)實(shí)例,他們互相引用,并且這兩個(gè)對(duì)象的所有其他引用都刪除,其他任何線程無法訪問這兩個(gè)對(duì)象中的任意一個(gè)。也可以符合垃圾回收條件。
public class Island {
Island i;
public static void main(String[] args) {
Island i2 = new Island();
Island i3 = new Island();
Island i4 = new Island();
i2.i=i3;
i3.i=i4;
i4.i=i2;
i2=null;
i3=null;
i4=null;
}
}