Java內部類的作用
在普通類裡面在建立一個類,這個類叫做內部類。內部類大致分為4類:
成員內部類、區域性內部類、匿名內部類和靜態內部類
一、內部類分類
定義一個介面方便示例:
package helloworld;
/**
* 介面
**/
public interface InterfaceTest{
void helloWorld();
}
1.成員內部類:
成員內部類是最普通的內部類,它的定義為位於另一個類的內部,形如下面的形式:
/** * @author shixuan * @date 2018/9/13 17:14 * @Description: 示例程式碼 */ public class InnerClassTest { String Hello = "hello"; private String sayHello = "hello tomorrow"; static String staticSayHello = "hello"; private class InnerClass1 implements InterfaceTest { @Override public void sayHello() { System.out.println("1. private say hello: "+sayHello); System.out.println("2. generate say hello"+sayHello); System.out.println("3. static say hello: "+staticSayHello); } } }
如上面程式碼所示,成員內部類可以訪問外部類所有成員變數和方法(其中包括靜態的和私有的)。需要注意的是當成員內部類和外部類擁有相同名稱的變數或方法時,會發生隱藏現象,即預設情況下訪問的是成員內部類的成員。如果要訪問外部同名變數需要用以下方式:
外部類.this.成員
2.區域性內部類
和成員內部類的區別在於區域性內部類訪問僅限於方法內或者該作用域內。區域性內部類定義在一個方法或者一個作用域內。相當於方法裡的一個區域性變數一樣。如下:
/** * @author shixuan * @date 2018/9/13 17:14 * @Description: 示例程式碼 */ public class InnerClassTest { String Hello = "hello"; private String sayHello = "hello tomorrow"; static String staticSayHello = "hello"; } class SaySomething{ public InterfaceTest justSay(){ class Hello implements InterfaceTest{ @Override public void sayHello() { System.out.println("I'm a Inner class"); } } return new Hello(); } }
區域性內部類跟方法裡的區域性變數一樣是不能有public、protected、private以及static修飾符的。
3. 匿名內部類
匿名內部類是在編寫監聽程式碼時比較常用的內部類,方便而且易於維護。匿名內部類由於沒有名字,所以它的建立方式有點兒奇怪。建立格式如下:
new 父類構造器(引數列表)|實現介面()
{
//匿名內部類的類體部分
}
- 我們看到使用匿名內部類我們必須繼承一個超類或實現一個介面,當然只能是繼承一個超類或者實現一個介面,而且兩者不可得兼。同時,它沒有關鍵字class,因為匿名內部類是直接使用new關鍵字來生成一個物件的引用,當然這種引用是隱式的。
- 沒有類名,也就不會有構造器
- 不能有任何靜態成員變數或方法
- 為區域性內部類,所以區域性內部類的限制匿名內部類都有
- 匿名內部類不能是抽象的,它必須要實現繼承的類或者介面的所有抽象方法
而最常見的匿名內部類的應用場合為: 需要通過實現介面來建立匿名內部類。
public interface AnonymousClassInterface {//interface
String getString();
}
/**
* @author shixuan
* @date 2018/9/13 17:14
* @Description: 示例程式碼
*/
public class InnerClassTest {
public void test(AnonymousClassInterface anonymousClassInterface) {
System.out.println(anonymousClassInterface.getString());
}
public static void main(String[] args) {
InnerClassTest innerClassTest = new InnerClassTest();
innerClassTest.test(new AnonymousClassInterface() {
@Override
public String getString() {
return "hello world";
}
});
}
}
- 以上例子中,test()方法需要傳入一個AnonymousClassInterface 物件作為引數。
- 但是AnonymousClassInterface 只是一個介面,所以無法直接建立物件。
- 所以需要建立一個ProductInformationList介面實現類的物件傳入test()方法中。
- 如果這個介面實現類的物件會被重複使用的話,則可以將此實現類定義為一個獨立的類;
- 但是現在只需要使用一次,所以就採用上述方法,定義一個匿名內部類。
4.靜態內部類
靜態內部類也是定義在另一個類裡面的類,只不過在類的前面多了一個關鍵字static。靜態內部類是不需要依賴於外部類的,這點和類的靜態成員屬性有點類似,並且它不能使用外部類的非static成員變數或者方法,這點很好理解,因為在沒有外部類的物件的情況下,可以建立靜態內部類的物件,如果允許訪問外部類的非static成員就會產生矛盾,因為外部類的非static成員必須依附於具體的物件。
詳情請看下面對內部類的作用描述。
二、內部類的作用
雖然成員內部類可以無條件訪問外部類的所有成員,但是,外部類訪問內部類就沒那麼容易了。下面我們來講講內部類的作用。
1 | 實現隱藏 |
2 | 擁有外圍類的所有元素的訪問許可權 |
3 | 實現多重繼承 |
4 | 避免修改介面而實現同一個類中兩種同名方法的呼叫 |
1. 實現隱藏功能
普通類是沒有 private 與protected許可權的,而內部類可以被這些關鍵字來修飾,從而影藏我們需要隱藏的資訊。
/**
* @author shixuan
* @date 2018/9/13 17:14
* @Description: 示例程式碼
*/
public class InnerClassTest {
private class InnerClass1 implements InterfaceTest {
@Override
public void sayHello() {
System.out.println("Hello");
}
}
static class InnerClass2 implements InterfaceTest {
@Override
public void sayHello() {
System.out.println("hello tomrrow");
}
}
public InterfaceTest getIn1() {
return new InnerClass1();
}
public InnerClass2 getIn2(){
return new InnerClass2();
}
}
測試程式碼
/**
* @author shixuan
* @date 2018/9/14 10:44
* @Description: client
*/
public class TestExample {
public static void main(String[] args) {
InnerClassTest innerClassTest=new InnerClassTest();
//1
InterfaceTest interfaceTest=innerClassTest.getIn1();
interfaceTest.sayHello();
//2
innerClassTest.getIn2().sayHello();
}
}
/**
*執行結果
*Hello
*hello tomrrow
*/
從上面程式碼可以看出,內部類只能被外部類訪問,測試程式碼裡呼叫的sayHello()這個方法的時候並不知道這個方法來自哪裡,只知道這是呼叫外部類方法時返回的某個例項中的方法。除此之外的其他類都是訪問不到該內部類的。從而實現了很好的隱藏效果。
2.擁有外圍類的所有元素的訪問許可權
/**
* @author shixuan
* @date 2018/9/13 17:14
* @Description: 示例程式碼
*/
public class InnerClassTest {
String Hello = "hello";
private String sayHello = "hello tomorrow";
static String staticSayHello = "hello";
private class InnerClass1 implements InterfaceTest {
@Override
public void sayHello() {
System.out.println("1. private say hello: "+sayHello);
System.out.println("2. generate say hello"+sayHello);
System.out.println("3. static say hello: "+staticSayHello);
}
}
static class InnerClass2 implements InterfaceTest {
@Override
public void sayHello() {
//這裡訪問不到外部類的非靜成員
System.out.println("static say hello: "+staticSayHello);
}
}
public InterfaceTest getIn1() {
return new InnerClass1();
}
public InnerClass2 getIn2(){
return new InnerClass2();
}
}
測試類
/**
* @author shixuan
* @date 2018/9/14 10:44
* @Description: client
*/
public class TestExample {
public static void main(String[] args) {
InnerClassTest innerClassTest=new InnerClassTest();
//1
InterfaceTest interfaceTest=innerClassTest.getIn1();
interfaceTest.sayHello();
//2
innerClassTest.getIn2().sayHello();
}
/**
* 1. private say hello: hello tomorrow
*2. generate say hellohello tomorrow
*3. static say hello: hello
*
*static say hello: hello
*/
}
3.Java 是如何在一個類的內部定義另一個類
實際上編譯器在編譯我們的外部類的時候,會掃描其內部是否還存在其他型別的定義,如果有那麼會「蒐集」這些類的程式碼,並按照某種特殊名稱規則單獨編譯這些類。