在Java中,可以將一個類定義在另一個類裡面或者一個方法裡面,這樣的類稱為內部類。廣泛意義上的內部類一般來說包括這四種:成員內部類、局部內部類、匿名內部類和靜態內部類。下面就先來了解一下這四種內部類的用法。
成員內部類是定義在另一個類內部的類。
package com.qunar.fresh;
/**
* Created by xiaosi on 16-3-29.
*/
public class Circle {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
// 內部類
class Draw{
public void drawCircle(){
System.out.println("Circle---->" + radius);
}
}
public Draw getDrawInstance(){
return new Draw();
}
public static void main(String[] args) {
Circle circle = new Circle(12.5);
circle.getDrawInstance().drawCircle(); // 12.5
}
}
Circle稱為外部類。成員內部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態成員)。在內部類drawCircle方法中,可以很輕松的訪問外部類的私有成員radius。
注意點:
(1)當成員內部類擁有和外部類同名的成員變量或者方法時,會發生隱藏現象,即默認情況下訪問的是成員內部類的成員。
public class Circle {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
// 內部類
class Draw {
private double radius;
public Draw(double radius) {
this.radius = radius;
}
public void drawCircle() {
// 成員內部類擁有和外部類同名的成員變量或者方法時,默認情況下訪問的是成員內部類的成員
System.out.println("Circle---->" + radius);
}
}
public Draw getDrawInstance(double radius) {
return new Draw(radius);
}
public static void main(String[] args) {
Circle circle = new Circle(12.5);
circle.getDrawInstance(11.6).drawCircle(); // 11.6
}
}
如果要訪問外部類的同名成員,需要以下面的形式進行訪問:
外部類.this.成員變量
外部類.this.成員方法
(2)成員內部類可以無條件地訪問外部類的成員,而外部類訪問成員內部類的成員卻這麼簡單。在外部類中訪問成員內部類的成員,必須先創建一個成員內部類的對象,再通過指向這個對象的引用來訪問:
(3)成員內部類是依附外部類而存在的,也就是說,如果要創建成員內部類的對象,前提是必須存在一個外部類的對象。創建成員內部類對象的一般方式如下:
第2種方式:
(4)內部類可以擁有private、protected、public及包訪問權限。比如上面的例子,如果成員內部類Inner用private修飾,則只能在外部類的內部訪問,如果用public修飾,則任何地方都能訪問;如果用protected修飾,則只能在同一個包下或者繼承外部類的情況下訪問;如果是默認訪問權限,則只能在同一個包下訪問。這一點和外部類有一點不一樣,外部類只能被public和包訪問兩種權限修飾。
局部內部類是定義在一個方法或者一個作用域內的類,它和成員內部類的區別在於局部內部類的訪問僅限於方法內或者該作用域內。
備注:
局部內部類就像是方法裡面的一個局部變量一樣,是不能有public、protected、private以及static修飾符的。
匿名類是不能有名稱的類,所以沒辦法引用它們。必須在創建時,作為new語句的一部分來聲明它們。這就要采用另一種形式的new語句,如下所示:new <類或接口> <類的主體>這種形式的new語句聲明一個新的匿名類,它對一個給定的類進行擴展,或者實現一個給定的接口。它還創建那個類的一個新實例,並把它作為語句的結果而返回。
舉個例子來說,假設你有一個Map,key是物品,value是對應的價格,單位是人民幣。現在有個需求是將裡面的價格都轉換為美元,傳統的做法是遍歷整個Map,然後更新每個value值,將價格轉換為美元價格,這種方式比較麻煩。我們使用Function可以解決這一問題。
new Function
匿名內部類是唯一一種沒有構造器的類(不能定義構造器)。正因為其沒有構造器,所以匿名內部類的使用范圍非常有限,大部分匿名內部類用於接口回調。匿名內部類在編譯的時候由系統自動起名為Outter$1.class。一般來說,匿名內部類用於繼承其他類或是實現接口,並不需要增加額外的方法,只是對繼承方法的重寫或者對接口方法的實現。
匿名內部類不能是抽象類,因為系統在創建匿名內部類的時候,會立即創建內部類的對象。因此不允許將匿名內部類定義成抽象類。
靜態內部類也是定義在另一個類裡面的類,只不過在類的前面多了一個關鍵字static。靜態內部類是不需要依賴於外部類的,這點和類的靜態成員屬性有點類似,並且它不能使用外部類的非static成員變量或者方法,因為在沒有外部類的對象的情況下,可以創建靜態內部類的對象,如果允許訪問外部類的非static成員就會產生矛盾,因為外部類的非static成員必須依附於具體的對象。
public class Outer2 {
private static String sname = "Outer2";
private String name;
public Outer2(String name) {
this.name = name;
}
// 成員內部類
public static class Inner {
public void print() {
// 靜態內部類不能訪問外部類的非static成員變量或者方法
// System.out.println("Outer---->" + name);
// 可以使用靜態變量或者方法
System.out.println("Outer---->" + sname);
}
}
}
調用:
Outer2.Inner inner2 = new Outer2.Inner();
inner2.print();
public void drawCircle() {
System.out.println("Circle---->" + Circle.this.radius); // 12.5
}
public class Circle {
private double radius;
public Circle(double radius) {
this.radius = radius;
// 需要創建成員內部類的對象
new Draw().drawCircle();
}
// 成員內部類
class Draw {
public void drawCircle() {
System.out.println("Circle---->" + radius); // 12.5
}
}
public static void main(String[] args) {
Circle circle = new Circle(12.5); // Circle---->12.5
}
}
package com.qunar.fresh;
/**
* Created by xiaosi on 16-3-29.
*/
public class Outer {
private String name;
public Outer(String name) {
this.name = name;
}
// 成員內部類
class Inner {
public void print() {
System.out.println("Outer---->" + name); // Outer---->OuterClass
}
}
public static void main(String[] args) {
Outer outer = new Outer("OuterClass");
Outer.Inner inner = outer.new Inner();
inner.print();
}
}
package com.qunar.fresh;
/**
* Created by xiaosi on 16-3-29.
*/
public class Outer {
private String name;
private Inner inner = null;
public Outer(String name) {
this.name = name;
}
public Inner getInstance() {
if (inner == null) {
return new Inner();
}
return inner;
}
// 成員內部類
class Inner {
public void print() {
System.out.println("Outer---->" + name); // Outer---->OuterClass
}
}
public static void main(String[] args) {
Outer outer = new Outer("OuterClass");
Outer.Inner inner = outer.getInstance();
inner.print();
}
}
@Test
public void test1(){
Map map = Maps.newHashMap();
map.put("apple",4.5);
map.put("bear",6.3);
// {bear=6.3, apple=4.5}
System.out.println(map.toString());
Map newMap = Maps.transformValues(map, new Function() {
double rate = 0.1544;
@Override
// 轉換為美元
public Double apply(Double input) {
return rate * input;
}
});
// {bear=0.97272, apple=0.6948000000000001}
System.out.println(newMap.toString());
}