一文搞定java的四種內部類
一:成員內部類
1.成員變量 與成員內部類
成員變量:在類中定義的,沒有staitc修飾符的變量稱爲成員變量,也稱爲實例變量
成員變量的特點:
1.每個實例都有這樣的變量
2.要在main方法中調用成員變量(實例變量),必須先要創建對象,然後才能調用實例變量
在類中定義的沒有static修飾符的內部類稱爲成員內部類
實際上,jvm就是把成員內部類當做是類中的一個成員方法,可以直接訪問外部類中私有的成員變量和私有的成員方法
成員內部類的特點和成員變量的特點類似:要創建成員內部類的對象,必須先要創建外部類的對象.然後通過外部類的對象來創建內部類的對象
public class Outer {
private int index;
private void test() {
System.out.println("Outer類私有的test方法被調用,訪問Outer類中私有的屬性 index=" + index);
}
public Outer(int index) {
this.index = index;
}
protected class Inner {
private int index;
// 注意:在成員內部了中不能有靜態屬性
//private static int index2;
public void fun() {
System.out.println("Inner類的實例方法fun()被調用,訪問Inner類中的私有的實例屬性 index="
+ index);
// Outer.this就是在內部類中持有的一個外部類對象的引用
// Outer.this.index 就是標識的外部類中的私有的成員變量
System.out
.println("在Inner類中訪問外部類私有的成員變量 index=" + Outer.this.index);
test();
}
public Inner(int index) {
this.index = index;
}
}
}
外部調用
public class Main {
public static void main(String[] args) {
// 要創建成員內部類的對象,必須先要創建外部類的對象.
Outer outer = new Outer(100);
// 然後通過外部類的對象來創建內部類的對象
Outer.Inner inner = outer.new Inner(500);
inner.fun();
}
}
補充:當一個具體類繼承了一個抽象類A並且實現了一個接口B,如果A,和B的抽象方法相同,那麼具體類中就會出現只實現一個該方法的情況,遇到這種情況我們可以讓該類繼承A在該類的內部創建成員內部類實現B那麼該成員內部類就相當與接口中方法的實現。
二:靜態內部類
靜態變量與靜態內部類
在類中聲明的有static修飾符的變量稱爲靜態變量
靜態變量的特點:
1.靜態變量在內存中只有一份,被這個類所有的對象所共享
2.調用靜態變量的時候不需要創建對象,可以直接通過類名來調用
靜態內部類的特點:
在類中定義的有static修飾符的內部類稱爲靜態內部類.在靜態內部類中可以定義靜態屬性
實際上,jvm就是把靜態內部類當做是類中的一個靜態方法,可以直接訪問外部類中私有的靜態變量和私有的靜態方法
靜態內部類的特點和靜態變量的特點類似:創建靜態內部類的對象的時候,不需要創建外部類的對象
public class Outer {
private int index1;
private void test1() {
System.out .println("Outer類私有的test方法被調用,訪問Outer類中私有的屬性 index1=" + index1);
}
private static int index = 100;
private static void test() {
System.out.println("Outer類中私有的靜態方法被調用,訪問Outer類中私有的靜態屬性 index=" + index);
}
public Outer(int index) {
}
protected static class Inner {
private static int index;
public void fun() {
System.out.println("Inner類的實例方法fun()被調用,訪問Inner類中的私有的靜態屬性 index="
+ index);
// 在靜態內部類中不能訪問外部類中私有的成員變量和私有的成員方法
// System.out
// .println("在Inner類中訪問外部類私有的成員變量 index1=" + index1);
// test1();
// 可以在靜態內部類中直接訪問外部類私有的靜態屬性和私有的靜態方法
System.out.println("在靜態內部類中訪問外部類中私有的靜態屬性 inxex=" + Outer.index);
test();
}
public Inner(int index) {
this.index = index;
}
}
}
外部調用
public class Main {
public static void main(String[] args) {
// 創建靜態內部類的對象的時候,不需要創建外部類的對象
Outer.Inner inner = new Outer.Inner(500);
inner.fun();
}
}
**三:局部內部類(此類爲難點)
java是前向的編程語言.所以前向是指在使用這種類型之前必須先要把這種類型聲明好,聲明找之後才能使用
我們在方法的第返回類型中使用Inner的時候,Inner這種類型還沒有聲明,所以方法的返回類型寫成Inner是不行的
但是Inner類是繼承自Object類的,所以方法的返回類型可以寫成Object
局部變量與局部內部類
在方法中或代碼塊中{}聲明的變量稱爲局部變量
局部變量的特點:
1.局部變量只在它聲明的{}裏面有效
2.局部變量不能使用訪問權限修飾符
局部內部類的特點
在方法或代碼塊中聲明的內部類,稱爲局部內部類
局部內部類的特點和局部變量的特點一致
1.局部內部類是一種類型,而這種類型只在它聲明的{}裏面有效
2.局部內部類不能使用訪問權限修飾符
public class Outer {
public static IA test() {
String addr = "北京";
class Inner implements IA {
private int index;
@Override
public void fun() {
System.out.println("局部內部類的實例方法被調用,訪問類中實例屬性 index=" + index);
}
public Inner(int index) {
this.index = index;
}
}
Inner inner = new Inner(100);
return inner;
}
}
內部類實現的接口
public interface IA {
//接口中必須有你要從外界調用的方法;
void fun();
}
外部調用
當我們調用Outer.test()的時候,該方法返回了一個Inner類的對象.但是這個Inner類的對象
被當做Object類型的.我們需要調用Inner類方法,就需要把obj還原成Inner類型的
但是Inner這種類型僅僅在Outer類的test()方法中有效,除了這個方法就無法識別Inner類型
由於無法識別Inner類型,也就無法對obj進行類型轉換,無法類型轉換,也就無法調用Inner類中的特有方法
所以:Outer類的test()方法的返回類型寫Object也是不行的
// Object obj = Outer.test();
// (Outer.Inner)obj;
public class Main {
public static void main(String[] args) {
//正確的調用方法,另該內部類實現某接口(接口中必須有你要調用的方法),通過接口類型調用方法:
//能調用到局部內部類中的方法,自然也就能通過方法訪問外部類對象了
IA ia = Outer.test();
ia.fun();
}
}
**四:匿名內部類(最常用)
package com.powernode.innerclass.test7;
如果一個局部內部類只會使用一次,用完之後就再也不會使用了,就可以把這個局部內部類改造成一個匿名內部類
匿名內部類一定是實現一個接口或繼承一個抽象類的,匿名內部類就是一個特殊的局部內部類.
注意:以上說法是錯誤的,準確的概念應該是,匿名內部類一定是實現了一個接口或繼承了一個類,
示例代碼:
public class test02 {
public static void main(String[] args) {
//匿名內部類方式一
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
});
t1.start();
//匿名內部類方式二 ,這種方式很少見相當於大括號就是實現.
Thread t2 = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
t2.start();
}
}
匿名內部類有兩種使用形式
1.出現在方法的返回值當中
2.出現在方法調用的實參中
// 下面的代碼是匿名內部類的第一種使用形式:匿名內部類出現在方法的返回值當中
public class EngineFactory {
public IEngine getEngine(String eName) {
if ("紅旗".equals(eName)) {
// 當我們判斷到eName是"紅旗"的時候,我們應該執行的操作是
// 1.聲明一個具體類,實現IEngine這個接口並且實現其中的全部的抽象方法
// 2.創建這個具體類的對象,當做方法的返回(這不過這個對象沒有名字)
return new IEngine() {
@Override
public void start() {
System.out.println("紅旗發動機啓動,速度40");
}
@Override
public void speedup() {
System.out.println("紅旗發動機加速,速度60");
}
@Override
public void stop() {
System.out.println("紅旗發動機停止,速度0");
}
};
} else if ("奇瑞".equals(eName)) {
return new IEngine() {
@Override
public void start() {
System.out.println("奇瑞發動機啓動,速度30");
}
@Override
public void speedup() {
System.out.println("奇瑞發動機加速,速度50");
}
@Override
public void stop() {
System.out.println("奇瑞發動機停止,速度0");
}
};
} else {
System.out.println("發動機型號錯誤,不能創建發動機對象");
return null;
}
}
}
內部類實現的接口
public interface IEngine {
public abstract void start();
public abstract void speedup();
public abstract void stop();
}
測試類
public class Car {
public void testEngine(IEngine e) {
e.start();
e.speedup();
e.stop();
}
}
外部調用
public class Main {
public static void main(String[] args) {
Car car = new Car();
EngineFactory ef = new EngineFactory();
//直接使用接口類型來接受返回的對象,使用
IEngine e1 = ef.getEngine("紅旗");
if (e1 != null) {
car.testEngine(e1);
}
}
}
匿名內部類的第二種使用形式:匿名內部類出現在方法的返回值當中
這種方式在Android的設置監聽器中很常見,這裏就不在贅述了
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.