一、介紹
面向?qū)ο蟪绦蛟O(shè)計(jì)中,可以在一個(gè)類的內(nèi)部定義另一個(gè)類。嵌套類分為兩種,即靜態(tài)嵌套類和非靜態(tài)嵌套類。靜態(tài)嵌套類使用很少,最重要的是非靜態(tài)嵌套類,也即是被稱作為內(nèi)部類(inner)。內(nèi)部類是JAVA語言的主要附加部分。內(nèi)部類幾乎可以處于一個(gè)類內(nèi)部任何位置,可以與實(shí)例變量處于同一級(jí),或處于方法之內(nèi),甚至是一個(gè)表達(dá)式的一部分。
內(nèi)部類的共性編輯
(1)內(nèi)部類仍然是一個(gè)獨(dú)立的類,在編譯之后內(nèi)部類會(huì)被編譯成獨(dú)立的.class文件,但是前面冠以外部類的類名和$符號(hào) 。
(2)內(nèi)部類不能用普通的方式訪問。內(nèi)部類是外部類的一個(gè)成員,因此內(nèi)部類可以自由地訪問外部類的成員變量,無論是否是private的 。
(3)內(nèi)部類聲明成靜態(tài)的,就不能隨便的訪問外部類的成員變量了,此時(shí)內(nèi)部類只能訪問外部類的靜態(tài)成員變量 。
二、知識(shí)點(diǎn)介紹
1、成員內(nèi)部類
2、局部?jī)?nèi)部類
3、靜態(tài)內(nèi)部類
4、匿名內(nèi)部類
三、上課對(duì)應(yīng)視頻的說明文檔
1、成員內(nèi)部類
成員內(nèi)部類是最普通的內(nèi)部類,它的定義為位于另一個(gè)類的內(nèi)部,形如下面的形式:
class Circle {
double radius = 0;
public Circle(double radius) {
this.radius = radius;
}
class Draw {? ? //內(nèi)部類
public void drawSahpe() {
System.out.println("drawshape");
}
}
}
這樣看起來,類Draw像是類Circle的一個(gè)成員,Circle稱為外部類。成員內(nèi)部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態(tài)成員)。
class Circle {
private double radius = 0;
public static int count =1;
public Circle(double radius) {
this.radius = radius;
}
class Draw {? ? //內(nèi)部類
public void drawSahpe() {
System.out.println(radius);? //外部類的private成員
System.out.println(count);? //外部類的靜態(tài)成員
}
}
}
不過要注意的是,當(dāng)成員內(nèi)部類擁有和外部類同名的成員變量或者方法時(shí),會(huì)發(fā)生隱藏現(xiàn)象,即默認(rèn)情況下訪問的是成員內(nèi)部類的成員。如果要訪問外部類的同名成員,需要以下面的形式進(jìn)行訪問:
外部類.this.成員變量
外部類.this.成員方法
雖然成員內(nèi)部類可以無條件地訪問外部類的成員,而外部類想訪問成員內(nèi)部類的成員卻不是這么隨心所欲了。在外部類中如果要訪問成員內(nèi)部類的成員,必須先創(chuàng)建一個(gè)成員內(nèi)部類的對(duì)象,再通過指向這個(gè)對(duì)象的引用來訪問:
class Circle {
private double radius = 0;
public Circle(double radius) {
this.radius = radius;
getDrawInstance().drawSahpe();? //必須先創(chuàng)建成員內(nèi)部類的對(duì)象,再進(jìn)行訪問
}
private Draw getDrawInstance() {
return new Draw();
}
class Draw {? ? //內(nèi)部類
public void drawSahpe() {
System.out.println(radius);? //外部類的private成員
}
}
}
成員內(nèi)部類是依附外部類而存在的,也就是說,如果要?jiǎng)?chuàng)建成員內(nèi)部類的對(duì)象,前提是必須存在一個(gè)外部類的對(duì)象。創(chuàng)建成員內(nèi)部類對(duì)象的一般方式如下:
public class Test {
public static void main(String[] args)? {
//第一種方式:
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner();? //必須通過Outter對(duì)象來創(chuàng)建
//第二種方式:
Outter.Inner inner1 = outter.getInnerInstance();
}
}
class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
//內(nèi)部類
class Inner {
public Inner() {
}
}
}
內(nèi)部類可以擁有private訪問權(quán)限、protected訪問權(quán)限、public訪問權(quán)限及包訪問權(quán)限。比如上面的例子,如果成員內(nèi)部類Inner用private修飾,則只能在外部類的內(nèi)部訪問,如果用public修飾,則任何地方都能訪問;如果用protected修飾,則只能在同一個(gè)包下或者繼承外部類的情況下訪問;如果是默認(rèn)訪問權(quán)限,則只能在同一個(gè)包下訪問。這一點(diǎn)和外部類有一點(diǎn)不一樣,外部類只能被public和包訪問兩種權(quán)限修飾。我個(gè)人是這么理解的,由于成員內(nèi)部類看起來像是外部類的一個(gè)成員,所以可以像類的成員一樣擁有多種權(quán)限修飾。
2、局部?jī)?nèi)部類
局部?jī)?nèi)部類是定義在一個(gè)方法或者一個(gè)作用域里面的類,它和成員內(nèi)部類的區(qū)別在于局部?jī)?nèi)部類的訪問僅限于方法內(nèi)或者該作用域內(nèi)。
class People{
public People() {
}
}
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{? //局部?jī)?nèi)部類
int age =0;
}
return new Woman();//返回局部?jī)?nèi)部類對(duì)象
}
}
注意,局部?jī)?nèi)部類就像是方法里面的一個(gè)局部變量一樣,是不能有public、protected、private以及static修飾符的。
3、靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類也是定義在另一個(gè)類里面的類,只不過在類的前面多了一個(gè)關(guān)鍵字static。靜態(tài)內(nèi)部類是不需要依賴于外部類的,這點(diǎn)和類的靜態(tài)成員屬性有點(diǎn)類似,并且它不能使用外部類的非static成員變量或者方法,這點(diǎn)很好理解,因?yàn)樵跊]有外部類的對(duì)象的情況下,可以創(chuàng)建靜態(tài)內(nèi)部類的對(duì)象,如果允許訪問外部類的非static成員就會(huì)產(chǎn)生矛盾,因?yàn)橥獠款惖姆莝tatic成員必須依附于具體的對(duì)象。
public class Test {
public static void main(String[] args)? {
//產(chǎn)生靜態(tài)內(nèi)部類對(duì)象
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
//靜態(tài)內(nèi)部類
static class Inner {
public Inner() {
}
}
}
綜合案例:
public class Inner {
private int num = 3;
class Limian{
public void show(){
//內(nèi)部類可以訪問外部類的私有變量
System.out.println(num);
}
}
//局部?jī)?nèi)部類
public void method(){
int num2 = 44;
class JuIn{
public void zhanshi(){
/*
* 按理說局部?jī)?nèi)部類訪問局部變量,局部變量應(yīng)該用final修飾,但是不用final修飾也是可以訪問的,
* 這是因?yàn)樵贘DK8以下必須用final修飾,不然會(huì)報(bào)錯(cuò),
* Cannot refer to a non-final variable a inside an inner class defined in a different method,
* 但是在JDK8之后就不會(huì)出現(xiàn)這種狀況
* */
System.out.print(num2);
}
}
System.out.println("訪問局部變量"+num2);
//在局部創(chuàng)建內(nèi)部類對(duì)象
JuIn ji = new JuIn();
ji.zhanshi();
}
}
class StaticTest{
private static int num1 = 4;
//內(nèi)部類用靜態(tài)變量修飾
public static class Test{
public static void show(){
//靜態(tài)內(nèi)部類訪問外部變量必須用static修飾
System.out.println(num1);
}
}
}
class InnerDemo{
public static void main (String[] args){
//非靜態(tài)內(nèi)部類創(chuàng)建方法
Inner.Limian l = new Inner().new Limian();
l.show();
//靜態(tài)內(nèi)部類創(chuàng)建方式
StaticTest.Test t = new StaticTest.Test();
//調(diào)用方法一
t.show();
//調(diào)用方法二
StaticTest.Test.show();
//局部?jī)?nèi)部類的方法調(diào)用
Inner i = new Inner();
i.method();
}
}
4、內(nèi)部類的實(shí)際使用——匿名內(nèi)部類
(1)匿名內(nèi)部類概念
內(nèi)部類是為了應(yīng)對(duì)更為復(fù)雜的類間關(guān)系。我們?cè)谕瓿捎?jì)算機(jī)語言相對(duì)底層的位置才會(huì)涉及,日常業(yè)務(wù)中很難遇到,這里不做贅述。
最常用到的內(nèi)部類就是匿名內(nèi)部類,是局部?jī)?nèi)部類的一種。
匿名內(nèi)部類有兩個(gè)步驟:
a.臨時(shí)定義一個(gè)類型的子類
b.定義后即刻創(chuàng)建剛剛定義的這個(gè)類的對(duì)象
(2)匿名內(nèi)部類作用與格式
作用:匿名內(nèi)部類是創(chuàng)建某個(gè)類型子類對(duì)象的快捷方式。
格式:
new 父類或接口(){
//進(jìn)行方法重寫
};
代碼示例:
//已經(jīng)存在的父類:
public abstract class Person{
public abstract void eat();
}
//定義并創(chuàng)建該父類的子類對(duì)象,并用多態(tài)的方式賦值給父類引用變量
Person? p = new Person(){
public void eat() {
System.out.println(“我吃了”);
}
};
//調(diào)用eat方法
p.eat();
使用匿名對(duì)象的方式,將定義子類與創(chuàng)建子類對(duì)象兩個(gè)步驟由一個(gè)格式一次完成,。雖然是兩個(gè)步驟,但是兩個(gè)步驟是連在一起完成的。
匿名內(nèi)部類如果不定義變量引用,則也是匿名對(duì)象。代碼如下:
new Person(){
public void eat() {
System.out.println(“我吃了”);
}
}.eat();
/*
* 定義Fly接口
*/
public interface Fly {
public abstract void open();
public abstract void fly();
public abstract void close();
}
public class YanZi implements Fly{
@Override
public void open() {
System.out.println("張開小翅膀");
}
@Override
public void fly() {
System.out.println("能飛3000米高空");
}
@Override
public void close() {
System.out.println("關(guān)閉小翅膀,安全著陸");
}
//一個(gè)類中可以定義多個(gè)類,但只能有一個(gè)類public的
class Person()
}
}
/*
* 匿名內(nèi)部類
*
* new 父類/接口(){
*? //重寫需要重寫的方法
* };
*/
public class Test {
public static void main(String[] args) {
Fly yz = new YanZi();
yz.open();
yz.fly();
yz.close();
new YanZi().open();
System.out.println("-------------------");
//實(shí)現(xiàn)類對(duì)象賦值給父接口
Fly fj = new Fly(){
@Override
public void open() {
System.out.println("不需要張開翅膀,一直都是張開狀態(tài)");
}
@Override
public void fly() {
System.out.println("噴氣式助力飛行!");
}
@Override
public void close() {
System.out.println("不需要關(guān)閉翅膀,得哪撞哪");
}
};
fj.open();
fj.fly();
fj.close();
System.out.println("-----------------------------");
//實(shí)現(xiàn)類對(duì)象直接以匿名對(duì)象的方式調(diào)用方法
new Fly() {
@Override
public void open() {
System.out.println("小翅膀");
}
@Override
public void fly() {
System.out.println("亂飛");
}
@Override
public void close() {
System.out.println("各種撞樹");
}
}.fly();
}
}