近幾日,看了一下 Android 開發,看到 java 與 C# 有許多不同的用法。
都是面向對象的語言,但是禪宗分南北,還是有不少用法上的不同,這里總結一下。
一. 類名.this 與內部類
在 java 中,經常看到類似類名.this 的用法,this 就是當前對象實例,為什么前面會出現類名呢?對此 C# 程序員會很納悶。
在 Java 中,很多地方使用到了內部類,甚至可以在在內部類中訪問外部類中的成員,這個時候,在內部類中使用 this 的時候,就會出現 this 到底是誰的問題,到底是表示內部類的當前對象實例,還是外部類的當前對象實例問題。
在 Java 中,通過在 this 的前面加上外部類的類名,表示在內部類中使用外部類的當前對象實例。
我們看下面的一個例子。
package core.sisheng; // 外部類定義 public class OuterClass { // 內部類定義 private class InnerClass { // 內部類中沒有定義 id 成員,這里訪問外部類中的成員 public int getId(){ return OuterClass.this.id; } public void setId(int id) { OuterClass.this.id = id;} // 內部類中定義了 name 成員,直接訪問內部類中的成員, 默認 this 訪問當前類中的成員 private String name; public String getName() { return this.name;} // 可以在 this 的前面加上一個內部類的名稱 public void setName(String name) { InnerClass.this.name = name;} // 內部類中也可以訪問外部類中同名的成員,需要加上外部類的名稱 public String getOuterName() { return OuterClass.this.name;} public void setOuterName(String name) { OuterClass.this.name = name;} @Override public String toString() { return "Id: " + this.getId() + ", Inner Name: " + this.getName() + ", Outer Name: " + this.getOuterName(); } } // 外部類中定義的成員 id 和 name private int id; private String name; private InnerClass innerInstance; public OuterClass() { this.innerInstance = new InnerClass(); this.innerInstance.setId(20); this.innerInstance.setName("Tom"); this.innerInstance.setOuterName("Alice"); } public String toString() { return this.innerInstance.toString(); } }
在C#中,類區分為嵌套類和非嵌套類,前者是聲明在其他數據類型內部的類。后者是直接定義在某一個命名空間的類。C# 中很少定義嵌套類。
非內嵌類只允許使用public和internal的訪問控制,而內置類則允許使用所有的五種訪問控制符,private, protected , internal protected,public和internal。內部類也可以訪問外部類的所有方法,包括instance方法和private方法,但是需要顯式 的傳遞一個外部類的實例。
C#中的內部類能夠使用外部類定義的類型和靜態方法,但是不能直接使用外部類的實例方法,因此,不存在上面的問題。
在C#中,外部類對於內部類的作用更像是一個命名空間,只要訪問控制允許,就可以使用下面的方法創建內部類對象實例。
OuterClass.InnerClass obj = new OuterClass.InnerClass();
這個實例與外部類的任何實例沒有任何直接的關系。類似於Java中的靜態內部類。
二、類名.class 與類型
在 java 中還經常看到類名.class 的用法,這個用法相當於 C# 中的 typeof( 類名 ),用來獲取類型的類型對象實例引用。
java中,每個class都有一個相應的Class對象,當編寫好一個類,編譯完成后,在生成的.class文件中,就產生一個Class對象,用來表示這個類的類型信息。獲得Class實例的三種方式:
- 通過調用對象實例的 getClass() 方法獲取該對象的Class實例。
- 使用Class的靜態方法forName(),用類的名字獲取一個Class實例。Class.forName(xxx.xx.xx) 返回的是一個類, 作用是要求JVM查找並加載指定的類,也就是說JVM會執行該類的靜態代碼段。
- 類名.calss的方式獲取Class實例,對基本數據類型的封裝類,還可以采用.TYPE來獲取對應的基本數據類型的Class實例。
C# 中獲取類型對象實例的方式更加簡單明確一些。
- 通過調用數據實例的 GetType() 方法獲取,這個方法繼承自Object,所以C#中任何對象都具有GetType()方法,x.GetType(),其中x為變量名。
- typeof(x)中的x,必須是具體的類名、類型名稱等,不可以是變量名稱。
- 通過 System.Type 的靜態方法 System.Type.GetType()。
三、匿名類
在 java 中,匿名類的使用也比較多,比如在 Android 中,實現按鈕的監聽,經常會看到類似這樣的代碼。
this.listener0 = new OnClickListener() { @Override public void onClick(View arg0) { Intent intent = new Intent( MainActivity.this, ActivityFrameLayout.class); setTitle("FrameLayout"); startActivity( intent ); } };
在這里,OnClickListenter 實際上是一個接口,接口能用來創建對象實例嗎?當然不能。
所以,java 在這里自動創建一個實現接口的匿名類,我們創建出來的實際上就是這個匿名類的對象實例。
這樣做的好處就是我們沒有必須再定義一個只使用一次的類,然后再通過這個類創建對象實例,簡化了程序的開發。
比如,我們有下面的一個接口。
public interface myInterface { void onClick(); }
就可以通過接口創建一個實現接口的匿名類的對象實例,然后使用這個對象實例。
myInterface instance = new myInterface(){ @Override public void onClick() { System.out.println("Clicked!"); } }; instance.onClick();
在 C# 中,我們根本就不會使用這種形式,通過委托,可以非常簡單地實現同樣的功能。
注意,java 中是沒有委托的。
如果我們輸出一下這個實例的類型,你會看到這個匿名類的實際類型的。
System.out.println( instance.getClass()); // class core.sisheng.Study1$1