1、什麼是嵌套類及內部類前端
能夠在一個類的內部定義另外一個類,這種類稱爲嵌套類(nested classes),它有兩種類型:靜態嵌套類和非靜態嵌套類。靜態嵌套類使用不多,最重要的是非靜態嵌套類,也便是被稱做爲內部類(inner)。嵌套類從JDK1.1開始引入。其中inner類又可分爲三種:
其1、在一個類(外部類)中直接定義的內部類;
其2、在一個方法(外部類的方法)中定義的內部類;
其3、匿名內部類。
java
下面,我將說明這幾種嵌套類的使用及注意事項。ide
2、靜態嵌套類this
以下所示代碼爲定義一個靜態嵌套類,
spa
public class StaticTest { .net
private static String name = "javaJohn"; orm
private String id = "X001"; 對象
static class Person{ 接口
private String address = "swjtu,chenDu,China"; 事件
public String mail = "josserchai@yahoo.com";//內部類公有成員
public void display(){
//System.out.println(id);//不能直接訪問外部類的非靜態成員
System.out.println(name);//只能直接訪問外部類的靜態成員
System.out.println("Inner "+address);//訪問本內部類成員。
}
}
public void printInfo(){
Person person = new Person();
person.display();
//System.out.println(mail);//不可訪問
//System.out.println(address);//不可訪問
System.out.println(person.address);//能夠訪問內部類的私有成員
System.out.println(person.mail);//能夠訪問內部類的公有成員
}
public static void main(String[] args) {
StaticTest staticTest = new StaticTest();
staticTest.printInfo();
}
}
在靜態嵌套類內部,不能訪問外部類的非靜態成員,這是由Java語法中"靜態方法不能直接訪問非靜態成員"所限定。若想訪問外部類的變量,必須經過其它方法解決,因爲這個緣由,靜態嵌套類使用不多。注意,外部類訪問內部類的的成員有些特別,不能直接訪問,但能夠經過內部類來訪問,這是由於靜態嵌套內的全部成員和方法默認爲靜態的了。同時注意,內部靜態類Person只在類StaticTest 範圍內可見,若在其它類中引用或初始化,均是錯誤的。
3、在外部類中定義內部類
以下所示代碼爲在外部類中定義兩個內部類及它們的調用關係:
public class Outer {
int outer_x = 100;
class Inner{
public int y = 10;
private int z = 9;
int m = 5;
public void display(){
System.out.println("display outer_x:"+ outer_x);
}
private void display2(){
System.out.println("display outer_x:"+ outer_x);
}
}
void test(){
Inner inner = new Inner();
inner.display();
inner.display2();
//System.out.println("Inner y:" + y);//不能訪問內部內變量
System.out.println("Inner y:" + inner.y);//能夠訪問
System.out.println("Inner z:" + inner.z);//能夠訪問
System.out.println("Inner m:" + inner.m);//能夠訪問
InnerTwo innerTwo = new InnerTwo();
innerTwo.show();
}
class InnerTwo{
Inner innerx = new Inner();
public void show(){
//System.out.println(y);//不可訪問Innter的y成員
//System.out.println(Inner.y);//不可直接訪問Inner的任何成員和方法
innerx.display();//能夠訪問
innerx.display2();//能夠訪問
System.out.println(innerx.y);//能夠訪問
System.out.println(innerx.z);//能夠訪問
System.out.println(innerx.m);//能夠訪問
}
}
public static void main(String args[]){
Outer outer = new Outer();
outer.test();
}
}
以上代碼須要說明有,對於內部類,一般在定義類的class關鍵字前不加public 或 private等限制符,若加了沒有任何影響,同時好像這些限定符對內部類的變量和方法也沒有影響(?)。另外,就是要注意,內部類Inner及InnterTwo只在類Outer的做用域內是可知的,若是類Outer外的任何代碼嘗試初始化類Inner或使用它,編譯就不會經過。同時,內部類的變量成員只在內部內內部可見,若外部類或同層次的內部類須要訪問,需採用示例程序中的方法,不可直接訪問內部類的變量。
4、在外部類中定義內部類
匿名類就是沒有名字的內部類,是內部類的一種特殊狀況。????????? 這句話對嗎???
前端時間在寫.net項目中,一直錯將.cs裏的兩個class看成內部類,原來是一個文件裏的兩個類而已,這讓我想起了Java中的內部類,比較內部類,那麼還有兩個類,那就是匿名類和匿名內部類。今天我想就Java中的這三種類進行個比較。
咱們知道在Java語言規範中能夠作不少事,例如一個類或一個接口中能夠聲明一個類或接口,在一個方法中能夠聲明一個類,類與接口聲明能夠嵌套任意深度等。
匿名類:
一、new <類或接口><類的主體>,匿名類的聲明是在編譯時進行的,實例化是在運行時進行的,因此在for循環中一個new語句會建立相同匿名類的幾個實例,而不是建立幾個不一樣匿名類的一個實例。
二、若是要執行的對象須要一個對象,但卻不值得建立全新的對象(多是由於該對象只在一個方法內部使用),在這個時候使用匿名類就會很是合適,因此說,匿名類通常會在swing程序中快速建立事件處理程序。
firstButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getTxtValue().setText("第一個按鈕觸發的事件!");
}
});
三、從技術上說,匿名類能夠被看做非靜態的內部類,因此他們具備方法內部聲明的非靜態內部類相同的權限和限制。
內部類:
內部類顧名思義就是在一個類的內部還有一個類
package com.iflytek.innerclass;
/**
* @author xudongwang 2012-1-11
*
* Email:xdwangiflytek@gmail.com
*/
public class InnerClassDemo {
public static void main(String[] args) {
new Outer().fun();
}
}
class Outer {
private String name = "Hello 內部類";
class Inner {
public void print() {
System.out.println("name = " + name);
}
};
public void fun() {
new Inner().print();
}
}
內部類生成的.class文件名爲:Outer$Inner.class,從上面的結構發現內部類的的缺點是「結構很是的混亂」。
package com.iflytek.innerclass;
/**
* @author xudongwang 2012-1-11
*
* Email:xdwangiflytek@gmail.com
*/
public class InnerClassDemo02 {
public static void main(String[] args) {
new Outer02().fun();
}
}
class Outer02 {
private String name = "Hello 內部類";
public void fun() {
new Inner02(this).print();
}
public String getName() {
return this.name;
}
};
class Inner02 {
private Outer02 out;
public Inner02(Outer02 out) {
this.out = out;
}
public void print() {
System.out.println("name = " + this.out.getName());
}
};
從上能夠看出內部類的優勢是「能夠方便的訪問外部類中的私有成員」;
若是要在外部直接使用內部類的實例化對象:
外部類.內部類 內部類對象 = 外部類實例.new 內部類實例();
package com.iflytek.innerclass;
/**
* @author xudongwang 2012-1-11
*
* Email:xdwangiflytek@gmail.com
*/
public class InnerClassDemo03 {
public static void main(String[] args) {
Outer03 out = new Outer03();//外部類實例
Outer03.Inner inner = out.new Inner();//實例化內部類對象
inner.print();
}
}
class Outer03{
private String name = "Hello 內部類";
class Inner {
public void print() {
System.out.println("name = " + name);
}
}
}
一個內部類若是使用static關鍵字聲明的話,則此內部類就將成爲外部類,能夠直接經過外部類.內部類的形式訪問
package com.iflytek.innerclass;
/**
* @author xudongwang 2012-1-11
*
* Email:xdwangiflytek@gmail.com
*/
public class InnerClassDemo04 {
public static void main(String[] args) {
Outer04.Inner inner = new Outer04.Inner();// 實例化內部類對象
inner.print();
}
}
class Outer04 {
private static String name = "Hello 內部類";
static class Inner {
public void print() {
System.out.println("name = " + name);
}
}
}
內部類能夠在任意的地方使用,例如方法中聲明
package com.iflytek.innerclass;
/**
* @author xudongwang 2012-1-11
*
* Email:xdwangiflytek@gmail.com
*/
public class InnerClassDemo05 {
public static void main(String[] args) {
new Outer05().fun();
}
}
class Outer05 {
private static String name = "Hello 內部類";
public void fun() {
class Inner {
public void print() {
System.out.println("name = " + name);
}
}
new Inner().print();
}
}
在方法中定義的內部類,能夠直接訪問外部類中的各個成員,可是若是要訪問方法中的參數,則須要在參數上加上final關鍵字聲明;
package com.iflytek.innerclass;
/**
* @author xudongwang 2012-1-11
*
* Email:xdwangiflytek@gmail.com
*/
public class InnerClassDemo06 {
public static void main(String[] args) {
new Outer06().fun(20);
}
}
class Outer06 {
private static String name = "Hello 內部類";
public void fun(final int temp) {
class Inner {
public void print() {
System.out.println("temp = " + temp);
System.out.println("name = " + name);
}
}
new Inner().print();
}
}
匿名類與內部的聯繫與區別:
按所在位置能夠分爲兩大類:
一、在類的方法中
特色:
a、能夠訪問宿主類的全部元素 ;
b、保存宿主類對象的引用,建立對象時必須有宿主類對象;
c、 不能有靜態數據;
繼續劃分:
A、本地內部類;
B、匿名內部類
二者的區別在於本地內部類有構造方法,而匿名內部類只能實例初始化;
二、在類或接口做用域中;
繼續劃分:
A、普通內部類
B、靜態內部類
匿名內部類:
匿名內部類是在抽象類和接口的基礎之上發展起來的。
package com.iflytek.innerclass;
/**
* @author xudongwang 2012-1-11
*
* Email:xdwangiflytek@gmail.com
*/
public class NoNameClass01 {
public static void main(String[] args) {
new X().fun2();
}
}
interface A {
public void fun();
}
class B implements A {
public void fun() {
System.out.println("Hello 準備匿名內部類");
}
}
class X {
public void fun1(A a) {
a.fun();
}
public void fun2() {
this.fun1(new B());
}
}
經過上面的Demo,若是如今假設B類只使用一次,那麼還有必要將其定義成一個單獨的類麼?
呵呵,此時就可使用匿名內部類:
package com.iflytek.innerclass;
/**
* @author xudongwang 2012-1-11
*
* Email:xdwangiflytek@gmail.com
*/
public class NoNameClass02 {
public static void main(String[] args) {
new XX().fun2();
}
}
interface AA {
public void fun();
}
class XX {
public void fun1(AA a) {
a.fun();
}
public void fun2() {
this.fun1(new AA() {
public void fun() {
System.out.println("Hello 準備匿名內部類");
}
});
}
}
其實在真正的項目開發中匿名內部類使用的很是之少,通常在Java的圖形界面和如今的Android中使用的比較多點。
最後給一個內部類實現的簡單鏈表:
package com.iflytek.innerclass;
/**
* @author xudongwang 2012-1-11
*
* Email:xdwangiflytek@gmail.com
*/
public class LinkDemo {
public static void main(String args[]) {
Link link = new Link();
link.add("A");
link.add("B");
link.add("C");
link.add("D");
link.add("E");
link.print();
}
};
class Link {
class Node {
private String name;
private Node next; // 單向鏈表,每一個節點指向下一個節點
public Node(String name) {
this.name = name; // 經過構造方法爲name屬性賦值
}
public void addNode(Node newNode) { // 增長節點
if (this.next == null) {
this.next = newNode; // 保存節點
} else {
this.next.addNode(newNode); // 繼續向下查找
}
}
public void printNode() { // 輸出節點
System.out.println(this.name);
if (this.next != null) { // 此節點以後還存在其餘的節點
this.next.printNode();
}
}
};
private Node root; // 鏈表的頭
public void add(String name) { // 增長節點
Node newNode = new Node(name); // 定義一個新的節點
/*
* 若是是第一個節點,則確定是根節點, 若是是第二個節點,則確定放在根節點next中 若是是第三個節點,則確定放在第二個節點的next中
*/
if (this.root == null) {
this.root = newNode; // 將第一個節點設置成根節點
} else {
// 確定要放在最後一個節點以後
// 經過節點.next來不斷的判斷
this.root.addNode(newNode);
}
}
public void print() {
if (this.root != null) { // 若是根節點爲空了,則沒有任何內容
this.root.printNode();
}
}
};