一.磨嘰磨嘰Java值傳遞與引用傳遞
“在Java里面參數(shù)傳遞都是按值傳遞”
即:按值傳遞是傳遞的值的拷貝,按引用傳遞其實傳遞的是引用的地址值传透,所以統(tǒng)稱按值傳遞胳挎。
簡單的說,基本數(shù)據(jù)類型是按值傳遞的其弊,方法的實參是一個原值的復(fù)本癞己。類對象是按對象的引用地址(內(nèi)存地址)傳遞地址的值,那么在方法內(nèi)對這個對象進行修改是會直接反應(yīng)在原對象上的(或者說這兩個引用指向同一內(nèi)存地址)梭伐。注意String也是值傳遞痹雅。
public static void main(String[] args) {
String x = new String("now");
User user = new User("now");
change(x);
System.out.println("1:"+x);
change(user);
System.out.println("2:"+user.name);
User user1 = new User("now");
System.out.println("3:"+user1 .name);
}
public static void change(String x) {
x = "even";
}
public static void change(User x) {
x.name = "even";
}
public static void change(User x) {
x = new User("even");
}
得出的結(jié)果
1:even
2:even
3:now
二.回歸正題,聊聊Java內(nèi)部類的這些事
Java允許在一個類里面定義另一個類籽御,類里面的類就是內(nèi)部類练慕,也叫做嵌套類
簡單的內(nèi)部類如下:
class OuterClass {
class InnerClass{
}
}
經(jīng)常用到的內(nèi)部類:
public class PrivateToOuter {
Runnable mRunnable = new Runnable(){
private int x=10;
@Override
public void run() {
System.out.println(x);
}
};
}
以上代碼mRunnable讓人并不覺得是內(nèi)部類,它并不像InnerClass那樣形象技掏,但是其實以下句柄實現(xiàn)一個繼承Runable的類铃将,也就是自定義了一個類,那么明顯它就是一個內(nèi)部類哑梳。其實它是屬于內(nèi)部類一種:匿名內(nèi)部類Anonymous Inner Class
{
private int x=10;
@Override
public void run() {
System.out.println(x);
}
}
內(nèi)部類需要注意的以下幾點:
(1)內(nèi)部類的獲取
內(nèi)部類可以訪問包裝他的外部類的所有劲阎,方法和屬性,包括私有方法鸠真。但是對其他類來說悯仙,它是隱藏的,哪怕對同一個包下面其他類來說吠卷,內(nèi)部類都是隱藏的锡垄,也就是說,如果要訪問內(nèi)部類祭隔,就必須先要得到他的外部包裝類货岭,得到那個句柄之后在new 內(nèi)部類,就可以調(diào)用他的方法了疾渴,如下:
OuterClass outer = new OuterClass();
InnerClass innerClass = outer.new InnerClass();
所以內(nèi)部類是可以很好的解決單繼承的問題千贯。如果對于private在此邏輯為何失效的話,可以查看細(xì)話Java:"失效"的private修飾符
(2)靜態(tài)內(nèi)部類
如果用static 將內(nèi)部內(nèi)靜態(tài)化搞坝,那么內(nèi)部類就只能訪問外部類的靜態(tài)成員變量搔谴,具有局限性
class Out {
private static int age = 12;
private int time = 14;
static class In {
public void print() {
System.out.println(age);
}
}
}
public class Demo {
public static void main(String[] args) {
Out.In in = new Out.In();
in.print();
}
}
也就是說in只能訪問age,而非time
(3)私有內(nèi)部類
如果一個內(nèi)部類只希望被外部類中的方法操作桩撮,那么可以使用private聲明內(nèi)部類
class Out {
private int age = 12;
private class In {
public void print() {
System.out.println(age);
}
}
public void outPrint() {
new In().print();
}
}
public class Demo {
public static void main(String[] args) {
//此方法無效
/*
Out.In in = new Out().new In();
in.print();
*/
Out out = new Out();
out.outPrint();
}
}
需要特別告訴大家重要的point就是:
在內(nèi)部類構(gòu)造的時候敦第,會將外部類的引用傳遞進來,并且作為內(nèi)部類的一個屬性店量,所以內(nèi)部類會持有一個其外部類的引用芜果。
在Java中,非靜態(tài)的內(nèi)部類和匿名內(nèi)部類都會隱式地持有其外部類的引用垫桂。靜態(tài)的內(nèi)部類不會持有外部類的引用。所以point3中的內(nèi)部類是無法獲取到外部類的成員變量與方法粟按。
回歸到android:
public class SampleActivity extends Activity {
private final Handler handler= new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
}
}
}
這是我們獲取handler實例經(jīng)常所做的操作诬滩,但是回歸到point得知霹粥,handler的匿名內(nèi)部類中有SampleActivity的引用,所以這是有可能導(dǎo)致OOM的隱患疼鸟,比如以下代碼:
public class SampleActivity extends Activity {
private final Handler mLeakyHandler = new Handler() {
@Override
public void handleMessage(Message msg) { // ... }
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLeakyHandler.postDelayed(new Runnable() {
@Override
public void run() { /* ... */ }
}, 1000 * 60 * 10);
finish();
}
}
SampleActivity對象已經(jīng)finish后控,但是mLeakyHandler的消息要在10分鐘后執(zhí)行操作,而Handler是一個匿名內(nèi)部類的實例空镜,其持有外面的SampleActivity的引用(而且Runable也是匿名內(nèi)部類浩淘,其內(nèi)部也是持有SampleActivity的引用),所以這導(dǎo)致了SampleActivity無法回收吴攒,進行導(dǎo)致SampleActivity持有的很多資源都無法回收张抄,這就是我們常說的內(nèi)存泄露。解決方法如下:
public class SampleActivity extends Activity {
private static class MyHandler extends Handler {
private final WeakReference<SampleActivity> mActivity;
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<SampleActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) { // ... }
}
}
private final MyHandler mHandler = new MyHandler(this);
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() { /* ... */ }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
finish();
}
}