一、什么是內部類
內部類是指在一個外部類的內部再定義一個類闯估。內部類作為外部類的一個成員灼舍,并且依附于外部類而存在的。內部類可為靜態(tài)涨薪,可用protected和private修飾(而外部類只能使用public和缺省的包訪問權限)骑素。
內部類主要有一下幾種:成員內部類、局部內部類刚夺、靜態(tài)內部類献丑、匿名內部類。
二侠姑、內部類的共性
(1)创橄、內部類仍然是一個獨立的類,在編譯之后內部類會被編譯成獨立的.class文件莽红,但是前面冠以外部類的類名和$符號 妥畏。
(2)、內部類不能用普通的方式訪問安吁。
(3)咖熟、內部類聲明成靜態(tài)的,就不能隨便的訪問外部類的成員變量了柳畔,此時內部類只能訪問外部類的靜態(tài)成員變量 馍管。
(4)、外部類不能直接訪問內部類的的成員薪韩,但可以通過內部類對象來訪問
三确沸、為什么需要內部類
其主要原因有以下幾點:
1、內部類方法可以訪問該類定義所在的作用域的數(shù)據俘陷,包括私有的數(shù)據
2罗捎、內部類可以對同一個包中的其他類隱藏起來,一般的非內部類,是不允許有 private 與protected權限的拉盾,但內部類可以
3桨菜、可以實現(xiàn)多重繼承
4、當想要定義一個回調函數(shù)且不想編寫大量代碼時捉偏,使用匿名內部類比較便捷
使用內部類最吸引人的原因是:
每個內部類都能獨立地繼承自一個(接口的)實現(xiàn)倒得,所以無論外圍類是否已經繼承了某個(接口的)實現(xiàn),對于內部類都沒有影響夭禽。大家都知道Java只能繼承一個類霞掺,它的多重繼承在我們沒有學習內部類之前是用接口來實現(xiàn)的。但使用接口有時候有很多不方便的地方讹躯。比如我們實現(xiàn)一個接口就必須實現(xiàn)它里面的所有方法菩彬。而有了內部類就不一樣了缠劝。它可以使我們的類繼承多個具體類或抽象類。
四骗灶、內部類分類
1惨恭、成員內部類
即在一個類中直接定義的內部類,成員內部類與普通類的成員沒什么區(qū)別耙旦,可以與普通成員一樣進行修飾和限制喉恋。成員內部類不能含有static的變量和方法。
package com.test;
?
public class Outer {
?? private static int number = 100;
?? private int j = 20;
?? private String name = "Java";
?
?? public static void outer_funOne(){
? ? ?? System.out.println("外部類Outer的靜態(tài)方法:outer_funOne");
?? }
?
?? public void outer_funTwo(){
? ? ?? System.out.println("外部類的普通方法:outer_funTwo");
?? }
?
?? //成員內部類母廷,可以訪問外部類的所有成員
?? class Demo{
? ? ?? //內部類不允許定義靜態(tài)變量
? ? ?? //static int demo_i = 100;
? ? ?? int j =50; //內部類和外部類的實例變量可以共存
?
? ? ?? //成員內部類中的方法定義
? ? ?? public void demo_funOne(){
? ? ? ? ?? //內部類中訪問內部類自己的變量直接用變量名
? ? ? ? ?? //也可以用? this.j
? ? ? ? ?? System.out.println(j);
?
? ? ? ? ?? //內部類中訪問外部類的成員變量語法:外部類類名.this.變量名
? ? ? ? ?? System.out.println("內部類訪問外部類變量:"+Outer.this.j);
?
? ? ? ? ?? //如果內部類中沒有與外部類中有相同的變量,則可以直接用變量名使用
? ? ? ? ?? System.out.println(name);
?
? ? ? ? ?? //內部類調用外部類方法
? ? ? ? ?? outer_funOne();? //靜態(tài)方法
? ? ? ? ?? outer_funTwo();? //非靜態(tài)方法
?
? ? ?? }
?
?? }
?
?? public static void outer_funThree(){
? ? ?? //外部類靜態(tài)方法訪問成員內部類
? ? ?? // 1糊肤、建立外部類對象
? ? ?? Outer out = new Outer();
? ? ?? //? 2琴昆、根據外部類建立內部類對象
? ? ?? Demo demo = out.new Demo();
? ? ?? // 訪問內部類方法
? ? ?? demo.demo_funOne();
? ? ?? //訪問內部類字段
? ? ?? System.out.println("內部類成員字段:"+demo.j);
?? }
?
?? public static void main(String[] args) {
? ? ?? //調用內部類的方法
? ? ?? // 1、創(chuàng)建外部類對象
? ? ?? Outer out = new Outer();
? ? ?? // 2馆揉、通過外部類對象創(chuàng)建內部類對象
? ? ?? Outer.Demo demo = out.new Demo();
?
? ? ?? // 1业舍、2步簡寫
? ? ?? // Outer.Demo demo1 = new Outer().new Demo();
?
? ? ?? //方法調用
? ? ?? demo.demo_funOne();
?
?? }
?
}
2、局部內部類
在方法中定義的內部類稱為局部內部類升酣。與局部變量類似舷暮,局部內部類不能有訪問說明符,因為它不是外圍類的一部分噩茄,但是它可以訪問當前代碼塊內的常量下面,和此外圍類所有的成員。
需要注意的是:
(1)绩聘、局部內部類只能在定義該內部類的方法內實例化沥割,不可以在此方法外對其實例化。
(2)凿菩、局部內部類對象不能使用該內部類所在方法的非final局部變量机杜。
package com.test;
?
public class Outer {
?? private static int number = 100;
?? private int j = 20;
?? private String name = "Java";
?
?? //定義外部類方法
?? public void outer_funOne(int k){
? ? ?? final int number = 100;
? ? ?? int j = 50;
?
? ? ?? //方法內部的類(局部內部類)
? ? ?? class Demo{
? ? ? ? ?? public Demo(int k){
? ? ? ? ? ? ?? demo_funOne(k);
? ? ? ? ?? }
?
? ? ? ? ?? int number = 300; //可以定義與外部類同名的變量
? ? ? ? ?? // static int j = 10;? //不可以定義靜態(tài)變量
?
? ? ? ? ?? //內部類的方法
? ? ? ? ?? public void demo_funOne(int k){
? ? ? ? ? ? ?? System.out.println("內部類方法:demo_funOne");
? ? ? ? ? ? ?? //訪問外部類的變量,如果沒有與內部類同名的變量衅谷,則可直接用變量名
? ? ? ? ? ? ?? System.out.println(name);
? ? ? ? ? ? ?? //訪問外部類與內部類同名的變量
? ? ? ? ? ? ?? System.out.println(Outer.this.number);
? ? ? ? ? ? ?? System.out.println("內部類方法傳入的參數(shù)是:"+k);
? ? ? ? ?? }
? ? ?? }
?
? ? ?? new Demo(k);
?? }
?
?? public static void main(String[] args) {
? ? ?? //訪問內部類必須要先有外部類對象
? ? ?? Outer out = new Outer();
? ? ?? out.outer_funOne(11);
?? }
?
}
3椒拗、靜態(tài)內部類(嵌套類)
如果你不需要內部類對象與其外圍類對象之間有聯(lián)系,那你可以將內部類聲明為static获黔。這通常稱為嵌套類(nested class)蚀苛。想要理解static應用于內部類時的含義,你就必須記住玷氏,普通的內部類對象隱含地保存了一個引用枉阵,指向創(chuàng)建它的外圍類對象。然而预茄,當內部類是static的時兴溜,就不是這樣了侦厚。嵌套類意味著:
1、 要創(chuàng)建嵌套類的對象拙徽,并不需要其外圍類的對象刨沦。
2、不能從嵌套類的對象中訪問非靜態(tài)的外圍類對象膘怕。
package com.test;
?
public class Outer {
?? private static int number = 100;
?? private int j = 20;
?? private String name = "Java";
?
?? public static void outer_funOne(){
? ? ?? System.out.println("外部類靜態(tài)方法:outer_funOne");
?? }
?
?? public void outer_funTwo(){
?
?? }
?
?? //靜態(tài)內部類可以用public想诅、protected、private修飾
?? //靜態(tài)內部類可以定義靜態(tài)類或非靜態(tài)內部類
?? private static class Demo{
? ? ?? static int j = 100;
? ? ?? String name = "C#";
?
? ? ?? //靜態(tài)內部類里的靜態(tài)方法
? ? ?? static void demo_funOne(){
? ? ? ? ?? //靜態(tài)內部類只能訪問外部類的靜態(tài)成員(靜態(tài)變量岛心、靜態(tài)方法)
? ? ? ? ?? System.out.println("靜態(tài)內部類訪問外部類靜態(tài)變量:"+number);
? ? ? ? ?? outer_funOne();//訪問外部類靜態(tài)方法
?
? ? ?? }
?
? ? ?? //靜態(tài)內部類非靜態(tài)方法
? ? ?? void demo_funTwo(){
?
? ? ?? }
?
?? }
?
?? public void outer_funThree(){
? ? ?? //外部類訪問內部類靜態(tài)成員:內部類.靜態(tài)成員
? ? ?? System.out.println(Demo.j);
? ? ?? //訪問靜態(tài)方法
? ? ?? Demo.demo_funOne();
? ? ?? //訪問靜態(tài)內部類的非靜態(tài)成員来破,實例化內部類即可
? ? ?? Demo demo = new Demo();
? ? ?? //訪問非靜態(tài)變量
? ? ?? System.out.println(demo.name);
? ? ?? //訪問非靜態(tài)方法
? ? ?? demo.demo_funTwo();
?
?? }
?
?
?? public static void main(String[] args) {
? ? ?? new Outer().outer_funThree();
?? }
?
}
4、匿名內部類
匿名內部類就是沒有名字的內部類忘古。什么情況下需要使用匿名內部類徘禁?如果滿足下面的一些條件,使用匿名內部類是比較合適的:
1髓堪、只用到類的一個實例送朱。
2、類在定義后馬上用到干旁。
3驶沼、類非常小(SUN推薦是在4行代碼以下)
4争群、給類命名并不會導致你的代碼更容易被理解回怜。
在使用匿名內部類時,要記住以下幾個原則:
1换薄、 匿名內部類不能有構造方法鹉戚。
2、 匿名內部類不能定義任何靜態(tài)成員专控、方法和類抹凳。
3、 匿名內部類不能是public,protected,private,static伦腐。
4赢底、 只能創(chuàng)建匿名內部類的一個實例。
5柏蘑、? 一個匿名內部類一定是在new的后面幸冻,用其隱含實現(xiàn)一個接口或實現(xiàn)一個類。
6咳焚、 因匿名內部類為局部內部類洽损,所以局部內部類的所有限制都對其生效。
public????class????Demo{
public????static????void????main(String[]args){
//我們要求是調用PersonDemo中的method方法
PersonDemo????pd=new????PersonDemo();
//這里要求我們傳一個抽象類對象革半,但是抽象類對象不能夠初始化碑定。
//所以要我們傳一個匿名內部類進去,這里不能直接傳抽象類對象流码,我們可以
//傳兩種,要么傳有名的子類對象延刘,要么傳匿名內部對象
// ? ? ?? Person p = new Student();
// ? ? ?? pd.method(p);
?
//我們用匿名內部類來做一下--匿名內部類當做參數(shù)傳遞漫试,把匿名內部類當做一個對象
pd.method(new????Person(){
//重寫show()方法
public????void????show(){
System.out.println("匿名內部類實現(xiàn)");
? ? ? ? ?? }
? ? ?? });
?
?? }
}
?
//寫個抽象類
abstract????class????Person{
public????abstract????void????show();
}
?
//普通類
class Person Demo{
public????void????method(Person????p){
p.show();
?? }
}
//再創(chuàng)建個子類對象去繼承抽象類
class????Student????extends????Person{
public????void????show(){
System.out.println("我是一個有名的子類");
?? }
}