樓上真牛...貼這么多...
10年積累的網(wǎng)站設(shè)計、成都網(wǎng)站設(shè)計經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有肥城免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
簡單的說,內(nèi)部類就是類中的類,舉個例子:
class A {
private int i;
private void m() {
}
class B {
mm(int j) {
i = j;
m();
}
}
}
這里,B就是A的內(nèi)部類
內(nèi)部類的特點就是,可以方便的訪問外部類里面的私有方法和屬性,比如,這里B里面可以直接訪問A里面的私有屬性i,和私有方法m()
在java語言中,有一種類叫做內(nèi)部類(inner class),也稱為嵌入類(nested class),它是定義在其他類的內(nèi)部。內(nèi)部類作為其外部類的一個成員,與其他成員一樣,可以直接訪問其外部類的數(shù)據(jù)和方法。只不過相比較外部類只有public和默認(rèn)的修飾符不同,內(nèi)部類作為一個成員,可以被任意修飾符修飾。編譯器在編譯時,內(nèi)部類的名稱為OuterClass$InnerClass.class 。
1、內(nèi)部類訪問數(shù)據(jù)變量
當(dāng)在某些時候,內(nèi)部類中定義的變量與外部類中變量名稱相同時,如何確保正確地訪問每一個變量呢?
1.1在main中直接從外部類調(diào)用內(nèi)部類的方法
class Outer
{
private int index = 10;
class Inner
{
private int index = 20;
void print()
{
int index = 30;
System.out.println(this); // the object created from the Inner
System.out.println(Outer.this); // the object created from the Outer
System.out.println(index); // output is 30
System.out.println(this.index); // output is 20
System.out.println(Outer.this.index); // output is 10
}
}
void print()
{
Inner inner = new Inner();//得到內(nèi)部類的引用
inner.print();
}
}
class Test
{
public static void main(String[] args)
{
Outer outer = new Outer();
outer.print();
}
}
在這里內(nèi)部類Inner中關(guān)鍵字this指向內(nèi)部類Inner的對象,如果要想指向外部類的對象,必須在this指針前加上外部類名稱,表示this是指向外部類構(gòu)造的碎屑,如Outer.this 。
1.2在main中顯式返回內(nèi)部類引用
class Outer
{
private int index = 10;
class Inner
{
private int index = 20;
void print()
{
int index = 30;
System.out.println(index);
System.out.println(this.index);
System.out.println(Outer.this.index);
}
}
Inner getInner()
{
return new Inner();//返回一個內(nèi)部類的引用
}
}
class Test
{
public static void main(String[] args)
{
Outer outer = new Outer();
Outer.Inner inner = outer.getInner();
inner.print();
}
}
Inner是Outer的內(nèi)部類,所以在類Test中必須用屬性引用符來標(biāo)識出內(nèi)部類。
1.3當(dāng)main方法在Outer類內(nèi)部
class Outer
{
private int index = 10;
class Inner
{
private int index = 20;
void print()
{
int index = 30;
System.out.println(index);
System.out.println(this.index);
System.out.println(Outer.this.index);
}
}
Inner getInner()
{
return new Inner();//返回一個內(nèi)部類的引用
}
public static void main(String[] args)
{
Outer outer = new Outer();
Inner inner = outer.getInner(); // 注意此處變化
inner.print();
}
}
因為main方法在Outer內(nèi)部,故可以直接引用,不需要屬性引用符。
1.4在main方法中直接產(chǎn)生內(nèi)部類對象
class Test
{
public static void main(String[] args)
{
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // 注意此處變化
inner.print();
}
}
在利用new構(gòu)造方法構(gòu)造一個外部類對象時,并沒有連帶著構(gòu)造一個內(nèi)部類對象,故需要訪問內(nèi)部類方法時,必須使用new操作符為這個外部類對象再構(gòu)造一個內(nèi)部類對象。
2、局部內(nèi)部類
在方法中定義的內(nèi)部類是局部內(nèi)部類,它只能訪問方法中的final類型的局部變量,因為用final定義的局部變量相當(dāng)于是一個常量,延長了其生命周期,使得方法在消亡時,其內(nèi)部類仍可以訪問該變量。另外,它同樣也可以引用定義在外部類的變量和方法。而且方法體中的局部內(nèi)部類不允許有訪問修飾符。
class Outer
{
int num=10;
public void print(final int aArgs)
{
class Inner
{
int num=20;
public Inner()
{
System.out.println("This is Inner.");//此句可看出它與匿名內(nèi)部類用法的不同。
}
public void print()
{
int num=30;
System.out.println(this); // the object created from the local Inner
System.out.println(num);
System.out.println(this.num);
System.out.println(Outer.this.num);
System.out.println(aArgs);
}
}
Inner inner=new Inner();//此句必須放在定義類Inner的后面
inner.print();
}
public static void main(String[] args)
{
Outer outer=new Outer();
outer.print(40);
}
}
對于局部類的命名,不管是在一個方法中定義多個類還是在幾個方法中分別定義類,其編譯后命名是:OuterClass$1InnerClass.class
3、匿名內(nèi)部類
匿名內(nèi)部類作為一種特殊的內(nèi)部類,除了具有普通內(nèi)部類的特點,還有自己的一些獨(dú)有特性:
匿名內(nèi)部類必須擴(kuò)展一個基類或?qū)崿F(xiàn)一個接口,但是不能有顯式的extends和implements子句;
匿名內(nèi)部類必須實現(xiàn)父類以及接口中的所有抽象方法;
匿名內(nèi)部類總是使用父類的無參構(gòu)造方法來創(chuàng)建實例。如果是實現(xiàn)了一個接口,則其構(gòu)造方法是Object();
匿名內(nèi)部類編譯后的命名為:OuterClass$n.class,其中n是一個從1開始的整數(shù),如果在一個類中定義了多個匿名內(nèi)部類,則按照他們的出現(xiàn)順序從1開始排號。
abstract class A
{
abstract public void sayHello();
}
class Outer
{
public static void main(String[] args)
{
new Outer().callInner(new A()
{
public void sayHello()
{
System.out.println(this); // the object created from the anonymous Inner
System.out.println("Hello!");
}
});
}
public void callInner(A a)
{
a.sayHello();
}
}
4、靜態(tài)內(nèi)部類
和非靜態(tài)內(nèi)部類相比,區(qū)別就在于靜態(tài)內(nèi)部類沒有了指向外部類的引用。除此之外,在任何非靜態(tài)內(nèi)部類中,都不能有靜態(tài)數(shù)據(jù),靜態(tài)方法或者又一個靜態(tài)內(nèi)部類(內(nèi)部類的嵌套可以不止一層)。不過靜態(tài)內(nèi)部類中卻可以擁有這一切。這也算是兩者的第二個區(qū)別吧。一個靜態(tài)的內(nèi)部類,才可以聲明一個static成員,靜態(tài)內(nèi)部類可以訪問外圍類的靜態(tài)方法、成員(包括private static的成員)。靜態(tài)內(nèi)部類實例化的時候不必先實例化外圍類,可以直接實例化內(nèi)部類。而對于非靜態(tài)內(nèi)部類則必須先實例化其外部類,才能再實例化本身。
5.內(nèi)部類的繼承
當(dāng)一個類繼承自一個內(nèi)部類時,缺省的構(gòu)造器不可用。必須使用如下語法:
class WithInner
{
class Inner
{
public void sayHello()
{
System.out.println("Hello.");
}
}
}
public class Test extends WithInner.Inner
{
Test(WithInner wi)
{
wi.super();
}
public static void main(String[] args)
{
WithInner wi=new WithInner();
Test test=new Test(wi);
test.sayHello();
}
}
因為每一個內(nèi)部類都有一個指向外部類的引用,在繼承一個內(nèi)部類,必須先創(chuàng)建一個外部類,通過這個外部類引用來調(diào)用其內(nèi)部類的構(gòu)造方法。如果繼承的內(nèi)部類是一個靜態(tài)內(nèi)部類,則就不需要這樣,直接super()調(diào)用即可;
6、內(nèi)部類的2種特殊用法
一個類從另一個類派生出來,又要實現(xiàn)一個接口。但在接口中定義的方法與父類中定義的方法的意義不同,則可以利用內(nèi)部類來解決這個問題。
interface Machine
{
void run();
}
class Person
{
void run()
{
System.out.println("run");
}
}
class Robot extends Person
{
private class MachineHeart implements Machine
{
public void run()
{
System.out.println("heart run");
}
}
Machine getMachine()
{
return new MachineHeart();
}
}
class Test
{
public static void main(String[] args)
{
Robot robot = new Robot();
Machine m = robot.getMachine();
m.run();
robot.run();
}
}
在Robot類內(nèi)部使用內(nèi)部類MachineHeart來實現(xiàn)接口Machine的run方法。同時Robot類又繼承了父類Person的run方法。如果不使用內(nèi)部類MachineHeart而使Robot直接實現(xiàn)接口Machine,則該如何調(diào)用父類的run方法?
利用內(nèi)部類可解決c++中多重繼承所解決的問題
class A
{
void fn1()
{
System.out.println("It' s fn1.");
}
}
abstract class B
{
abstract void fn2();
}
class C extends A
{
B getB()
{
return new B()
{
public void fn2()
{
System.out.println("It' s fn2.");
}
};
}
}
class Test
{
public static void main(String[] args)
{
C c = new C();
c.fn1();
c.getB().fn2();
}
}
類C既要繼承類A又要繼承類B,則可將類B的定義放入類C內(nèi)部,使之成為內(nèi)部類。
一般情況下 當(dāng)我們需要在某一情形下實現(xiàn)一個接口,而在另一情形下又不需要實現(xiàn)這個接口時,我們可以使用內(nèi)部類來解決這一問題。讓內(nèi)部類來實現(xiàn)這個接口。另外一個很好的理由是java內(nèi)部類加上接口可以有效地實現(xiàn)多重繼承。
對普通類(沒有內(nèi)部類的類)來說,內(nèi)部類和外部類都與他無關(guān);對有內(nèi)部類的類來說,它們就是其內(nèi)部類的外部類,外部類是個相對的說法,其實就是有內(nèi)部類的類。
所以,要回答這個問題,只需要講解內(nèi)部類是什么:
Java中的內(nèi)部類共分為四種:
靜態(tài)內(nèi)部類static inner class (also called nested class)
成員內(nèi)部類member inner class
局部內(nèi)部類local inner class
匿名內(nèi)部類anonymous inner class
靜態(tài)內(nèi)部類Static Inner Class
最簡單的內(nèi)部類形式。
類定義時加上static關(guān)鍵字。
不能和外部類有相同的名字。
被編譯成一個完全獨(dú)立的.class文件,名稱為OuterClass$InnerClass.class的形式。
只可以訪問外部類的靜態(tài)成員和靜態(tài)方法,包括了私有的靜態(tài)成員和方法。
生成靜態(tài)內(nèi)部類對象的方式為:
OuterClass.InnerClass inner = new OuterClass.InnerClass();
示例代碼:
package com.learnjava.innerclass;
class StaticInner
{
private static int a = 4;
// 靜態(tài)內(nèi)部類
public static class Inner
{
public void test()
{
// 靜態(tài)內(nèi)部類可以訪問外部類的靜態(tài)成員
// 并且它只能訪問靜態(tài)的
System.out.println(a);
}
}
}
public class StaticInnerClassTest
{
public static void main(String[] args)
{
StaticInner.Inner inner = new StaticInner.Inner();
inner.test();
}
}
成員內(nèi)部類Member Inner Class
成員內(nèi)部類也是定義在另一個類中,但是定義時不用static修飾。
成員內(nèi)部類和靜態(tài)內(nèi)部類可以類比為非靜態(tài)的成員變量和靜態(tài)的成員變量。
成員內(nèi)部類就像一個實例變量。
它可以訪問它的外部類的所有成員變量和方法,不管是靜態(tài)的還是非靜態(tài)的都可以。
在外部類里面創(chuàng)建成員內(nèi)部類的實例:
this.new Innerclass();
在外部類之外創(chuàng)建內(nèi)部類的實例:
(new Outerclass()).new Innerclass();
在內(nèi)部類里訪問外部類的成員:
Outerclass.this.member
示例代碼:
package com.learnjava.innerclass;
class MemberInner
{
private int d = 1;
private int a = 2;
// 定義一個成員內(nèi)部類
public class Inner2
{
private int a = 8;
public void doSomething()
{
// 直接訪問外部類對象
System.out.println(d);
System.out.println(a);// 直接訪問a,則訪問的是內(nèi)部類里的a
// 如何訪問到外部類里的a呢?
System.out.println(MemberInner.this.a);
}
}
}
public class MemberInnerClassTest
{
public static void main(String[] args)
{
// 創(chuàng)建成員內(nèi)部類的對象
// 需要先創(chuàng)建外部類的實例
MemberInner.Inner2 inner = new MemberInner().new Inner2();
inner.doSomething();
}
}
局部內(nèi)部類Local Inner Class
局部內(nèi)部類定義在方法中,比方法的范圍還小。是內(nèi)部類中最少用到的一種類型。
像局部變量一樣,不能被public, protected, private和static修飾。
只能訪問方法中定義的final類型的局部變量。
局部內(nèi)部類在方法中定義,所以只能在方法中使用,即只能在方法當(dāng)中生成局部內(nèi)部類的實例并且調(diào)用其方法。
示例代碼:
package com.learnjava.innerclass;
class LocalInner
{
int a = 1;
public void doSomething()
{
int b = 2;
final int c = 3;
// 定義一個局部內(nèi)部類
class Inner3
{
public void test()
{
System.out.println("Hello World");
System.out.println(a);
// 不可以訪問非final的局部變量
// error: Cannot refer to a non-final variable b inside an inner
// class defined in a different method
// System.out.println(b);
// 可以訪問final變量
System.out.println(c);
}
}
// 創(chuàng)建局部內(nèi)部類的實例并調(diào)用方法
new Inner3().test();
}
}
public class LocalInnerClassTest
{
public static void main(String[] args)
{
// 創(chuàng)建外部類對象
LocalInner inner = new LocalInner();
// 調(diào)用外部類的方法
inner.doSomething();
}
}
匿名內(nèi)部類Anonymous Inner Class
匿名內(nèi)部類就是沒有名字的局部內(nèi)部類,不使用關(guān)鍵字class, extends, implements, 沒有構(gòu)造方法。
匿名內(nèi)部類隱式地繼承了一個父類或者實現(xiàn)了一個接口。
匿名內(nèi)部類使用得比較多,通常是作為一個方法參數(shù)。
生成的.class文件中,匿名類會生成OuterClass$1.class文件,數(shù)字根據(jù)是第幾個匿名類而類推。
示例代碼:
package com.learnjava.innerclass;
import java.util.Date;
public class AnonymouseInnerClass
{
@SuppressWarnings("deprecation")
public String getDate(Date date)
{
return date.toLocaleString();
}
public static void main(String[] args)
{
AnonymouseInnerClass test = new AnonymouseInnerClass();
// 打印日期:
String str = test.getDate(new Date());
System.out.println(str);
System.out.println("----------------");
// 使用匿名內(nèi)部類
String str2 = test.getDate(new Date()
{
});// 使用了花括號,但是不填入內(nèi)容,執(zhí)行結(jié)果和上面的完全一致
// 生成了一個繼承了Date類的子類的對象
System.out.println(str2);
System.out.println("----------------");
// 使用匿名內(nèi)部類,并且重寫父類中的方法
String str3 = test.getDate(new Date()
{
// 重寫父類中的方法
@Override
@Deprecated
public String toLocaleString()
{
return "Hello: " + super.toLocaleString();
}
});
System.out.println(str3);
}
}