內部類(Nested Class)仍是獨立的類袁辈,只不過被包含于其他類中。編譯之后內部類會被編譯成獨立的.class
文件。但是前面冠以外部類的類名和$
符號.
成員內部類:
- 便于訪問外部類屬性页徐。
- 內部類輔助外部類完成某些功能。
如同一個人是由大腦银萍、肢體变勇、器官等身體結果組成,而內部類相當于其中的某個器官之一贴唇,例如心臟:它也有自己的屬性和行為(血液搀绣、跳動)。顯然戳气,此處不能單方面用屬性或者方法表示一個心臟链患,而需要一個類。而心臟又在人體當中瓶您,正如同是內部類在外部內當中麻捻。
實例1:內部類的基本結構
//外部類
class Out {
private int age = 12;
//內部類
class In {
public void print() {
System.out.println(age);
}
}
}
public class Demo {
public static void main(String[] args) {
Out.In in = new Out().new In();
in.print();
//或者采用下種方式訪問
/*
Out out = new Out();
Out.In in = out.new In();
in.print();
*/
}
}
運行結果:12
從上面的例子不難看出,內部類其實嚴重破壞了良好的代碼結構呀袱,但為什么還要使用內部類呢贸毕?
因為內部類可以隨意使用外部類的成員變量(包括私有)而不用生成外部類的對象,這也是內部類的唯一優(yōu)點
如同心臟可以直接訪問身體的血液夜赵,而不是通過醫(yī)生來抽血
程序編譯過后會產生兩個.class文件明棍,分別是Out.class
和Out$In.class
其中$
代表了上面程序中Out.In
中的那個.
Out.In in = new Out().new In()
可以用來生成內部類的對象,這種方法存在兩個小知識點需要注意
- 1.開頭的Out是為了標明需要生成的內部類對象在哪個外部類當中
- 2.必須先有外部類的對象才能生成內部類的對象寇僧,因為內部類的作用就是為了訪問外部類中的成員變量
實例2:內部類中的變量訪問形式
class Out {
private int age = 12;
class In {
private int age = 13;
public void print() {
int age = 14;
System.out.println("局部變量:" + age);
System.out.println("內部類變量:" + this.age);
System.out.println("外部類變量:" + Out.this.age);
}
}
}
public class Demo {
public static void main(String[] args) {
Out.In in = new Out().new In();
in.print();
}
}
運行結果:
局部變量:14
內部類變量:13
外部類變量:12
從實例1中可以發(fā)現(xiàn)摊腋,內部類在沒有同名成員變量和局部變量的情況下,內部類會直接訪問外部類的成員變量婉宰,而無需指定Out.this.屬性名
否則歌豺,內部類中的局部變量會覆蓋外部類的成員變量
而訪問內部類本身的成員變量可用this.屬性名
,訪問外部類的成員變量需要使用Out.this.屬性名
靜態(tài)內部類
class Out {
private static int age = 12;
static class In {
public void print() {
System.out.println(age);
}
}
}
public class Demo {
public static void main(String[] args) {
Out.In in = new Out.In();
in.print();
}
}
可以看到心包,如果用static
將內部內靜態(tài)化,那么內部類就只能訪問外部類的靜態(tài)成員變量馒铃,具有局限性
其次蟹腾,因為內部類被靜態(tài)化痕惋,因此Out.In
可以當做一個整體看,可以直接new
出內部類的對象(通過類名訪問static
娃殖,生不生成外部類對象都沒關系)
實例4:私有內部類
class Out {
private int age = 12;
private class In {
public void print() {
System.out.println(age);
}
}
public void outPrint() {
new In().print();
}
}
public class Demo {
public static void main(String[] args) {
//此方法無效
/*
Out.In in = new Out().new In();
in.print();
*/
Out out = new Out();
out.outPrint();
}
}
如果一個內部類只希望被外部類中的方法操作值戳,那么可以使用private
聲明內部類
上面的代碼中,我們必須在Out
類里面生成In
類的對象進行操作炉爆,而無法再使用Out.In in = new Out().new In()
生成內部類的對象
也就是說堕虹,此時的內部類只有外部類可控制
如同是,我的心臟只能由我的身體控制芬首,其他人無法直接訪問它
實例5:方法內部類
class Out {
private int age = 12;
public void Print(final int x) {
class In {
public void inPrint() {
System.out.println(x);
System.out.println(age);
}
}
new In().inPrint();
}
}
public class Demo {
public static void main(String[] args) {
Out out = new Out();
out.Print(3);
}
}
在上面的代碼中赴捞,我們將內部類移到了外部類的方法中,然后在外部類的方法中再生成一個內部類對象去調用內部類方法
如果此時我們需要往外部類的方法中傳入?yún)?shù)郁稍,那么外部類的方法形參必須使用final
定義
至于final
在這里并沒有特殊含義赦政,只是一種表示形式而已
匿名內部類
匿名內部類也就是沒有名字的內部類
正因為沒有名字,所以匿名內部類只能使用一次耀怜,它通常用來簡化代碼編寫
但使用匿名內部類還有個前提條件:必須繼承一個父類或實現(xiàn)一個接口
實例1:不使用匿名內部類來實現(xiàn)抽象方法
abstract class Person {
public abstract void eat();
}
class Child extends Person {
public void eat() {
System.out.println("eat something");
}
}
public class Demo {
public static void main(String[] args) {
Person p = new Child();
p.eat();
}
}
運行結果:eat something
可以看到恢着,我們用Child繼承了Person類,然后實現(xiàn)了Child的一個實例财破,將其向上轉型為Person類的引用
但是掰派,如果此處的Child類只使用一次,那么將其編寫為獨立的一個類豈不是很麻煩左痢?
這個時候就引入了匿名內部類
實例2:匿名內部類的基本實現(xiàn)
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
運行結果:eat something
可以看到靡羡,我們直接將抽象類Person中的方法在大括號中實現(xiàn)了
這樣便可以省略一個類的書寫
并且,匿名內部類還能用于接口上
實例3:在接口上使用匿名內部類
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
由上面的例子可以看出抖锥,只要一個類是抽象的或是一個接口亿眠,那么其子類中的方法都可以使用匿名內部類來實現(xiàn)
最常用的情況就是在多線程的實現(xiàn)上,因為要實現(xiàn)多線程必須繼承Thread
類或是繼承Runnable
接口
實例4:Thread類的匿名內部類實現(xiàn)
public class Demo {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
t.start();
}
}
實例5:Runnable接口的匿名內部類實現(xiàn)
public class Demo {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
Thread t = new Thread(r);
t.start();
}
}
實例6:運用內部類調用其他包類中的protected
的方法
當你想使用一個類的protected
方法時磅废,但是又不和這個類在同一個包下纳像,你是沒辦法調用的。
這時候匿名類就派上用場了拯勉,你可以聲明一個匿名類繼承該類竟趾,并定義一個方法,在這個方法內使用super
調用你想調用的那個方法(其實你也可以寫個類繼承這個類宫峦,就能調用父類的protected
方法了岔帽,但是匿名類更簡潔,因為你只想調用這個方法而已)导绷。例如:
public class Testclass {
protected void test(){
System.out.println("test...");
}
}
這個類有一個protected
方法test
犀勒,如果你在其他包下想調用這個protected
方法是不行的
這時候你可以使用匿名類繼承這個類,定義一個方法callParentTest()
,在這個方法體內調用super.test()
贾费,最后調用這個callParentTest()
即可钦购。
public class UserOthreMethod{
public static void main(String[] args){
new Testclass{
void callParentTest(){
super.test();
}
}.callParentTest();
}
}
內部類(Nested Class)仍是獨立的類,只不過被包含于其他類中褂萧。編譯之后內部類會被編譯成獨立的.class
文件押桃。但是前面冠以外部類的類名和$
符號.
成員內部類:
- 便于訪問外部類屬性。
- 內部類輔助外部類完成某些功能导犹。
如同一個人是由大腦唱凯、肢體、器官等身體結果組成谎痢,而內部類相當于其中的某個器官之一磕昼,例如心臟:它也有自己的屬性和行為(血液、跳動)舶得。顯然掰烟,此處不能單方面用屬性或者方法表示一個心臟,而需要一個類沐批。而心臟又在人體當中纫骑,正如同是內部類在外部內當中。
實例1:內部類的基本結構
//外部類
class Out {
private int age = 12;
//內部類
class In {
public void print() {
System.out.println(age);
}
}
}
public class Demo {
public static void main(String[] args) {
Out.In in = new Out().new In();
in.print();
//或者采用下種方式訪問
/*
Out out = new Out();
Out.In in = out.new In();
in.print();
*/
}
}
運行結果:12
從上面的例子不難看出九孩,內部類其實嚴重破壞了良好的代碼結構先馆,但為什么還要使用內部類呢?
因為內部類可以隨意使用外部類的成員變量(包括私有)而不用生成外部類的對象躺彬,這也是內部類的唯一優(yōu)點
如同心臟可以直接訪問身體的血液煤墙,而不是通過醫(yī)生來抽血
程序編譯過后會產生兩個.class文件,分別是Out.class
和Out$In.class
其中$
代表了上面程序中Out.In
中的那個.
Out.In in = new Out().new In()
可以用來生成內部類的對象宪拥,這種方法存在兩個小知識點需要注意
- 1.開頭的Out是為了標明需要生成的內部類對象在哪個外部類當中
- 2.必須先有外部類的對象才能生成內部類的對象仿野,因為內部類的作用就是為了訪問外部類中的成員變量
實例2:內部類中的變量訪問形式
class Out {
private int age = 12;
class In {
private int age = 13;
public void print() {
int age = 14;
System.out.println("局部變量:" + age);
System.out.println("內部類變量:" + this.age);
System.out.println("外部類變量:" + Out.this.age);
}
}
}
public class Demo {
public static void main(String[] args) {
Out.In in = new Out().new In();
in.print();
}
}
運行結果:
局部變量:14
內部類變量:13
外部類變量:12
從實例1中可以發(fā)現(xiàn),內部類在沒有同名成員變量和局部變量的情況下她君,內部類會直接訪問外部類的成員變量脚作,而無需指定Out.this.屬性名
否則,內部類中的局部變量會覆蓋外部類的成員變量
而訪問內部類本身的成員變量可用this.屬性名
缔刹,訪問外部類的成員變量需要使用Out.this.屬性名
靜態(tài)內部類
class Out {
private static int age = 12;
static class In {
public void print() {
System.out.println(age);
}
}
}
public class Demo {
public static void main(String[] args) {
Out.In in = new Out.In();
in.print();
}
}
可以看到球涛,如果用static
將內部內靜態(tài)化,那么內部類就只能訪問外部類的靜態(tài)成員變量校镐,具有局限性
其次亿扁,因為內部類被靜態(tài)化,因此Out.In
可以當做一個整體看鸟廓,可以直接new
出內部類的對象(通過類名訪問static
从祝,生不生成外部類對象都沒關系)
實例4:私有內部類
class Out {
private int age = 12;
private class In {
public void print() {
System.out.println(age);
}
}
public void outPrint() {
new In().print();
}
}
public class Demo {
public static void main(String[] args) {
//此方法無效
/*
Out.In in = new Out().new In();
in.print();
*/
Out out = new Out();
out.outPrint();
}
}
如果一個內部類只希望被外部類中的方法操作襟己,那么可以使用private
聲明內部類
上面的代碼中,我們必須在Out
類里面生成In
類的對象進行操作哄褒,而無法再使用Out.In in = new Out().new In()
生成內部類的對象
也就是說稀蟋,此時的內部類只有外部類可控制
如同是煌张,我的心臟只能由我的身體控制呐赡,其他人無法直接訪問它
實例5:方法內部類
class Out {
private int age = 12;
public void Print(final int x) {
class In {
public void inPrint() {
System.out.println(x);
System.out.println(age);
}
}
new In().inPrint();
}
}
public class Demo {
public static void main(String[] args) {
Out out = new Out();
out.Print(3);
}
}
在上面的代碼中,我們將內部類移到了外部類的方法中骏融,然后在外部類的方法中再生成一個內部類對象去調用內部類方法
如果此時我們需要往外部類的方法中傳入?yún)?shù)链嘀,那么外部類的方法形參必須使用final
定義
至于final
在這里并沒有特殊含義,只是一種表示形式而已