java學(xué)習(xí)筆記系列:
java學(xué)習(xí)筆記8--接口總結(jié)
java學(xué)習(xí)筆記7--抽象類(lèi)與抽象方法
java學(xué)習(xí)筆記6--類(lèi)的繼承、Object類(lèi)
java學(xué)習(xí)筆記5--類(lèi)的方法
java學(xué)習(xí)筆記4--對(duì)象的初始化與回收
java學(xué)習(xí)筆記3--類(lèi)與對(duì)象的基礎(chǔ)
java學(xué)習(xí)筆記2--數(shù)據(jù)類(lèi)型、數(shù)組
java學(xué)習(xí)筆記1--開(kāi)發(fā)環(huán)境平臺(tái)總結(jié)
本文地址:http://m.survivalescaperooms.com/archimedes/p/java-study-note9.html,轉(zhuǎn)載請(qǐng)注明源地址。
java內(nèi)部類(lèi)分為: 非靜態(tài)內(nèi)部類(lèi)、靜態(tài)內(nèi)部類(lèi)、局部?jī)?nèi)部類(lèi)、匿名內(nèi)部類(lèi)
內(nèi)部類(lèi)的共性:
(1)內(nèi)部類(lèi)仍然是一個(gè)獨(dú)立的類(lèi),在編譯之后內(nèi)部類(lèi)會(huì)被編譯成獨(dú)立的.class文件,但是前面冠以外部類(lèi)的類(lèi)名和$符號(hào) 。
(2)內(nèi)部類(lèi)不能用普通的方式訪問(wèn)。內(nèi)部類(lèi)是外部類(lèi)的一個(gè)成員,因此內(nèi)部類(lèi)可以自由地訪問(wèn)外部類(lèi)的成員變量,無(wú)論是否是PRivate的 。
(3)內(nèi)部類(lèi)聲明成靜態(tài)的,就不能隨便的訪問(wèn)外部類(lèi)的成員變量了,此時(shí)內(nèi)部類(lèi)只能訪問(wèn)外部類(lèi)的靜態(tài)成員變量。
java 中的內(nèi)部類(lèi)和接口加在一起,可以的解決常被 C++ 程序員抱怨 java 中存在的一個(gè)問(wèn)題:沒(méi)有多繼承。實(shí)際上,C++ 的多繼承設(shè)計(jì)起來(lái)很復(fù)雜,而 java 通過(guò)內(nèi)部類(lèi)加上接口,可以很好的實(shí)現(xiàn)多繼承的效果。
非靜態(tài)內(nèi)部類(lèi)當(dāng)一個(gè)類(lèi)作為另一個(gè)類(lèi)的非靜態(tài)成員,則這個(gè)類(lèi)就是一個(gè)非靜態(tài)內(nèi)部類(lèi)。
創(chuàng)建非靜態(tài)內(nèi)部類(lèi)是很容易的,只需要定義一個(gè)類(lèi)讓該類(lèi)作為其他類(lèi)的非靜態(tài)成員。該非靜態(tài)內(nèi)部類(lèi)和成員變量或者成員方法沒(méi)有區(qū)別,同樣可以在非靜態(tài)內(nèi)部類(lèi)前面加可以修飾成員的修飾符。創(chuàng)建非靜態(tài)內(nèi)部類(lèi)的基本語(yǔ)法如下所示:
class OutClass { class InClass { //內(nèi)部類(lèi)成員 } //外部類(lèi)成員}在內(nèi)部類(lèi)的程序中,是經(jīng)常會(huì)進(jìn)行外部類(lèi)和內(nèi)部類(lèi)之間訪問(wèn)的。在外部類(lèi)中訪問(wèn)內(nèi)部類(lèi)是很容易的,只要把內(nèi)部類(lèi)看成一個(gè)類(lèi),然后創(chuàng)建該類(lèi)的對(duì)象,使用對(duì)象來(lái)調(diào)用內(nèi)部類(lèi)中的成員就可以了。
在外部類(lèi)中訪問(wèn)內(nèi)部類(lèi)的程序--舉個(gè)例子:
class OutClass { class InClass { //創(chuàng)建非靜態(tài)內(nèi)部類(lèi) int i = 5; //內(nèi)部類(lèi)成員 } public void fun() { //外部類(lèi)成員 InClass in = new InClass(); //創(chuàng)建一個(gè)內(nèi)部類(lèi)對(duì)象 int i = in.i; //訪問(wèn)內(nèi)部類(lèi)成員 System.out.println("InClass's var is: " + i); }}public class javatest { public static void main(String args[ ]) { OutClass out = new OutClass(); out.fun(); }}運(yùn)行結(jié)果:
InClass's var is: 5
分析:在main方法中,首先創(chuàng)建一個(gè)外部類(lèi)對(duì)象,然后訪問(wèn)外部類(lèi)的成員方法。在外部類(lèi)的成員方法中,創(chuàng)建了一個(gè)內(nèi)部類(lèi)對(duì)象,然后使用內(nèi)部類(lèi)對(duì)象調(diào)用內(nèi)部類(lèi)的成員變量,從而得到結(jié)果。編譯該程序?qū)a(chǎn)生三個(gè)class文件,分別是主類(lèi)、外部類(lèi)和內(nèi)部類(lèi)。內(nèi)部類(lèi)產(chǎn)生的class文件的名稱為OutClass$InClass.class,在該名稱中可以區(qū)分該內(nèi)部類(lèi)到底是哪一個(gè)類(lèi)的內(nèi)部類(lèi)。
不但可以在外部類(lèi)中訪問(wèn)內(nèi)部類(lèi),還可以在外部類(lèi)外訪問(wèn)內(nèi)部類(lèi)。在外部類(lèi)外訪問(wèn)內(nèi)部類(lèi)的基本語(yǔ)法如下所示。
OutClass.InClass oi=new OutClass().new InClass();
使用該方法就能夠創(chuàng)建一個(gè)內(nèi)部類(lèi)對(duì)象,使用該內(nèi)部類(lèi)對(duì)象就可以訪問(wèn)內(nèi)部類(lèi)的成員。該方法是不容易理解的,可以分為下面的兩條語(yǔ)句:
Wai w=new Wai();
Wai.Nei wn=w.new Nei();
這樣就很容易理解了。首先是創(chuàng)建一個(gè)外部類(lèi)的對(duì)象,然后讓該外部類(lèi)對(duì)象調(diào)用創(chuàng)建一個(gè)內(nèi)部類(lèi)對(duì)象。
在外部類(lèi)外訪問(wèn)內(nèi)部類(lèi)的程序--舉個(gè)例子:
class OutClass { class InClass { //創(chuàng)建非靜態(tài)內(nèi)部類(lèi) int i = 5; //內(nèi)部類(lèi)成員 int j = 6; }}public class javatest { public static void main(String args[ ]) { OutClass.InClass oi1 = new OutClass().new InClass(); OutClass ocClass = new OutClass(); OutClass.InClass oi2 = ocClass.new InClass(); System.out.println("InClass's var i is: " + oi1.i); System.out.println("InClass's var j is: " + oi1.j); }}在示例代碼中使用了兩種方法來(lái)從外部類(lèi)外訪問(wèn)內(nèi)部類(lèi)。在外部類(lèi)外訪問(wèn)內(nèi)部類(lèi)時(shí),是不能夠直接創(chuàng)建內(nèi)部類(lèi)對(duì)象的,因?yàn)閮?nèi)部類(lèi)只是外部類(lèi)的一個(gè)成員。所以要想創(chuàng)建內(nèi)部類(lèi)對(duì)象,首先要?jiǎng)?chuàng)建外部類(lèi)對(duì)象,然后以外部類(lèi)對(duì)象為標(biāo)識(shí)來(lái)創(chuàng)建內(nèi)部類(lèi)對(duì)象。
在內(nèi)部類(lèi)中訪問(wèn)外部類(lèi)
在內(nèi)部類(lèi)中訪問(wèn)外部類(lèi),就像所有的同一個(gè)類(lèi)中成員互相訪問(wèn)一樣,這樣是沒(méi)有限制的,包括將成員聲明為private私有的。
舉個(gè)例子:
class OutClass { int i = 8; //外部類(lèi)成員變量 class InClass { //創(chuàng)建非靜態(tài)內(nèi)部類(lèi) public void fun() { System.out.println("OutClass's var is: " + i); } }}public class javatest { public static void main(String args[ ]) { OutClass oc = new OutClass(); //創(chuàng)建外部類(lèi)對(duì)象 OutClass.InClass oi = oc.new InClass(); //創(chuàng)建內(nèi)部類(lèi)對(duì)象 oi.fun(); //調(diào)用內(nèi)部類(lèi)中的成員 }}在示例代碼中,在內(nèi)部類(lèi)中定義了一個(gè)fun來(lái)訪問(wèn)外部類(lèi)中的成員變量i。可以看到從內(nèi)部類(lèi)中訪問(wèn)外部類(lèi)是非常容易的,不需要添加任何內(nèi)容,就像成員方法間調(diào)用一樣。如果外部類(lèi)中也有一個(gè)成員變量i,得到的是內(nèi)部類(lèi)成員變量的值。下面通過(guò)示例代碼解決這個(gè)問(wèn)題:
class OutClass { int i = 8; //外部類(lèi)成員變量 class InClass { //創(chuàng)建非靜態(tài)內(nèi)部類(lèi) int i = 9; OutClass oc = new OutClass(); public void fun() { //內(nèi)部類(lèi)成員 System.out.println("InClass's var is: " + i); System.out.println("OutClass's var is: " + oc.i); } }}public class javatest { public static void main(String args[ ]) { OutClass oc = new OutClass(); //創(chuàng)建外部類(lèi)對(duì)象 OutClass.InClass ic = oc.new InClass(); //創(chuàng)建內(nèi)部類(lèi)對(duì)象 ic.fun(); //調(diào)用內(nèi)部類(lèi)中的成員 }}在本程序中先定義了一個(gè)外部類(lèi)的成員變量,接著定義了一個(gè)內(nèi)部類(lèi)的成員變量,這兩個(gè)成員變量的名稱是相同的。而在內(nèi)部直接訪問(wèn)時(shí),將訪問(wèn)的是內(nèi)部類(lèi)的成員變量。要想訪問(wèn)外部類(lèi)成員變量,就需要首先創(chuàng)建一個(gè)外部類(lèi)對(duì)象,然后使用該對(duì)象調(diào)用外部類(lèi)成員變量。
局部?jī)?nèi)部類(lèi)局部?jī)?nèi)部類(lèi)的作用范圍是和局部變量的作用范圍相同的,只在局部中起作用,所以對(duì)局部?jī)?nèi)部類(lèi)進(jìn)行訪問(wèn)時(shí),只能在該局部?jī)?nèi)部類(lèi)的作用范圍內(nèi)。
舉個(gè)例子:
class OutClass { public void fun() { class InClass { //定義一個(gè)局部?jī)?nèi)部類(lèi) int i = 5; //局部?jī)?nèi)部類(lèi)的成員變量 } InClass ic = new InClass(); System.out.println("InClass's var is: " + ic.i); }}public class javatest { public static void main(String args[ ]) { OutClass oc = new OutClass(); oc.fun(); }}在本程序中定義了一個(gè)局部?jī)?nèi)部類(lèi),并進(jìn)行了對(duì)該局部?jī)?nèi)部類(lèi)的訪問(wèn)。對(duì)該內(nèi)部類(lèi)進(jìn)行訪問(wèn)必須在該內(nèi)部類(lèi)所在的方法中通過(guò)創(chuàng)建內(nèi)部類(lèi)對(duì)象來(lái)進(jìn)行訪問(wèn)。這是因?yàn)檫@里的內(nèi)部類(lèi)是作為局部成員的形式出現(xiàn)的,只能在它所在的方法中進(jìn)行調(diào)用。
局部?jī)?nèi)部類(lèi)中訪問(wèn)外部類(lèi)成員變量
在局部?jī)?nèi)部類(lèi)中訪問(wèn)外部類(lèi)成員變量是很容易實(shí)現(xiàn)的,并不需要進(jìn)行過(guò)多操作。在局部?jī)?nèi)部類(lèi)中可以直接調(diào)用外部類(lèi)的成員變量。
舉個(gè)例子:
class OutClass { int i = 9; //定義一個(gè)外部類(lèi)的成員變量 public void fun() { class InClass { //定義一個(gè)局部?jī)?nèi)部類(lèi) public void Infun() { System.out.println("OutClass's var is: " + i); //訪問(wèn)外部類(lèi)中的成員變量 } } InClass ic = new InClass(); //創(chuàng)建內(nèi)部類(lèi)對(duì)象 ic.Infun(); //調(diào)用內(nèi)部類(lèi)中的成員方法 }}public class javatest { public static void main(String args[ ]) { OutClass oc = new OutClass(); //創(chuàng)建外部類(lèi)對(duì)象 oc.fun(); //調(diào)用內(nèi)部類(lèi)中的成員 }}在示例代碼中定義了一個(gè)局部?jī)?nèi)部類(lèi),在該局部?jī)?nèi)部類(lèi)中定義了一個(gè)方法來(lái)訪問(wèn)外部類(lèi)的成員變量。
在局部?jī)?nèi)部類(lèi)中訪問(wèn)外部類(lèi)的局部變量
和訪問(wèn)外部類(lèi)的成員變量不同,在局部?jī)?nèi)部類(lèi)中訪問(wèn)外部類(lèi)中和局部?jī)?nèi)部類(lèi)在同一局部的局部變量是不能夠直接訪問(wèn)的。
舉個(gè)例子(下面是一段錯(cuò)誤的代碼):
class OutClass { public void OutFun() { int i = 9; class InClass { public void InFun() { System.out.println("OutClass's var is: " + i);//訪問(wèn)外部類(lèi)的成員變量 } } InClass ic = new InClass(); //創(chuàng)建內(nèi)部類(lèi)對(duì)象 ic.InFun(); //調(diào)用內(nèi)部類(lèi)中的成員方法 }}public class javatest { public static void main(String args[ ]) { OutClass oc = new OutClass(); //創(chuàng)建外部類(lèi)對(duì)象 oc.OutFun(); //調(diào)用內(nèi)部類(lèi)中的成員 }}運(yùn)行產(chǎn)生異常:
Exception in thread "main" java.lang.Error: Unresolved compilation problem: Cannot refer to a non-final variable i inside an inner class defined in a different method
運(yùn)行該程序是會(huì)發(fā)生錯(cuò)誤的,錯(cuò)誤信息為“從內(nèi)部類(lèi)中訪問(wèn)局部變量i;需要被聲明為最終類(lèi)型”。在局部?jī)?nèi)部類(lèi)中訪問(wèn)外部類(lèi)的局部變量是不能夠訪問(wèn)普通的局部變量的,必須將該局部變量聲明為final。
靜態(tài)方法中的局部?jī)?nèi)部類(lèi)
局部?jī)?nèi)部類(lèi)定義在非靜態(tài)方法和靜態(tài)方法中是不同的,在前面例子都是將局部?jī)?nèi)部類(lèi)定義在非靜態(tài)方法中,下面就來(lái)學(xué)習(xí)靜態(tài)方法中定義局部?jī)?nèi)部類(lèi)的情況。在靜態(tài)方法中定義的局部?jī)?nèi)部類(lèi)要想訪問(wèn)外部類(lèi)中的成員,該成員必須是靜態(tài)成員。
class OutClass { static int i = 4; public static void OutFun() { //外部類(lèi)成員 class InClass { public void InFun() { System.out.println("OutClass's local var is: " + i); } } InClass ic = new InClass(); ic.InFun(); }}public class javatest { public static void main(String args[ ]) { OutClass.OutFun(); }}靜態(tài)內(nèi)部類(lèi)前面已經(jīng)學(xué)習(xí)了非靜態(tài)內(nèi)部類(lèi),接下來(lái)就來(lái)學(xué)習(xí)什么是靜態(tài)內(nèi)部類(lèi)。靜態(tài)內(nèi)部類(lèi)就是在外部類(lèi)中扮演一個(gè)靜態(tài)成員的角色。創(chuàng)建靜態(tài)內(nèi)部類(lèi)的形式和創(chuàng)建非靜態(tài)內(nèi)部類(lèi)的形式很相似的,只是需要將該內(nèi)部類(lèi)使用static修飾成靜態(tài)的形式。使用static修飾類(lèi),這在正常類(lèi)中是不可能的。定義靜態(tài)內(nèi)部類(lèi)的語(yǔ)法如下所示:class OutClass { static class InClass { //內(nèi)部類(lèi)成員 } //外部類(lèi)成員}在外部類(lèi)中訪問(wèn)靜態(tài)內(nèi)部類(lèi)
在外部類(lèi)中訪問(wèn)靜態(tài)內(nèi)部類(lèi)和在外部類(lèi)中訪問(wèn)非靜態(tài)內(nèi)部類(lèi)一樣的,只需要從成員間訪問(wèn)的角度就可以考慮到這一點(diǎn)。舉個(gè)例子:
class OutClass { static class InClass { //創(chuàng)建靜態(tài)內(nèi)部類(lèi) int i = 5; //內(nèi)部類(lèi)成員 } public void OutFun() { //外部類(lèi)成員 InClass ic = new InClass(); //創(chuàng)建一個(gè)內(nèi)部類(lèi)對(duì)象 int ii = ic.i; //訪問(wèn)內(nèi)部類(lèi)成員 System.out.println("static InClass's var is: " + ii); }}public class javatest { public static void main(String args[ ]) { OutClass oc = new OutClass(); //創(chuàng)建外部類(lèi)對(duì)象 oc.OutFun(); //調(diào)用內(nèi)部類(lèi)中的成員 }}在外部類(lèi)中訪問(wèn)靜態(tài)內(nèi)部類(lèi)和訪問(wèn)非靜態(tài)內(nèi)部類(lèi)是相同的,但是在外部類(lèi)中訪問(wèn)靜態(tài)內(nèi)部類(lèi)和非靜態(tài)內(nèi)部類(lèi)就不再相同。因?yàn)殪o態(tài)內(nèi)部類(lèi)是外部類(lèi)的靜態(tài)成員,靜態(tài)成員是不需要外部類(lèi)對(duì)象而存在的,所以在外部類(lèi)外,對(duì)靜態(tài)內(nèi)部類(lèi)進(jìn)行訪問(wèn)時(shí)是不需要?jiǎng)?chuàng)建外部類(lèi)對(duì)象的。
注意:因?yàn)殪o態(tài)內(nèi)部類(lèi)是外部類(lèi)的靜態(tài)成員,靜態(tài)成員是不需要外部類(lèi)對(duì)象而存在的,所以在外部類(lèi)外,對(duì)靜態(tài)內(nèi)部類(lèi)進(jìn)行訪問(wèn)時(shí)是不需要?jiǎng)?chuàng)建外部類(lèi)對(duì)象的。
匿名內(nèi)部類(lèi)在所有的內(nèi)部類(lèi)中最難的就應(yīng)該是匿名內(nèi)部類(lèi)。匿名內(nèi)部類(lèi)從名字上看就知道是沒(méi)有類(lèi)名的內(nèi)部類(lèi)。正因?yàn)闆](méi)有名字,所以匿名內(nèi)部類(lèi)只能使用一次,它通常用來(lái)簡(jiǎn)化代碼編寫(xiě),
但使用匿名內(nèi)部類(lèi)還有個(gè)前提條件:必須繼承一個(gè)父類(lèi)或?qū)崿F(xiàn)一個(gè)接口
創(chuàng)建匿名內(nèi)部類(lèi)
在創(chuàng)建匿名內(nèi)部類(lèi)中將使用到繼承父類(lèi)或者實(shí)現(xiàn)接口的知識(shí),匿名內(nèi)部類(lèi)是沒(méi)有名字的,所以在創(chuàng)建匿名內(nèi)部類(lèi)時(shí)同時(shí)創(chuàng)建匿名內(nèi)部類(lèi)的對(duì)象。創(chuàng)建匿名內(nèi)部類(lèi)的語(yǔ)法格式如下:
new InFather() { //匿名內(nèi)部類(lèi)};在創(chuàng)建匿名內(nèi)部類(lèi)的語(yǔ)法中,InFather是匿名內(nèi)部類(lèi)繼承的父類(lèi)的類(lèi)名,使用new同時(shí)創(chuàng)建了匿名內(nèi)部類(lèi)的對(duì)象。在匿名內(nèi)部類(lèi)中可以重寫(xiě)父類(lèi)中的方法,也可以定義自己的方法。
實(shí)例1:不使用匿名內(nèi)部類(lèi)來(lái)實(shí)現(xiàn)抽象方法
abstract class Person { public abstract void eat();} class Child extends Person { public void eat() { System.out.println("eat something"); }}public class test { public static void main(String[] args) { Person p = new Child(); p.eat(); }}運(yùn)行結(jié)果:
eat something
可以看到,我們用Child繼承了Person類(lèi),然后實(shí)現(xiàn)了Child的一個(gè)實(shí)例,將其向上轉(zhuǎn)型為Person類(lèi)的引用。但是,如果此處的Child類(lèi)只使用一次,那么將其編寫(xiě)為獨(dú)立的一個(gè)類(lèi)會(huì)很麻煩。這個(gè)時(shí)候就引入了匿名內(nèi)部類(lèi)
實(shí)例2:匿名內(nèi)部類(lèi)的基本實(shí)現(xiàn)
abstract class Person { public abstract void eat();}public class test { public static void main(String[] args) { Person p = new Person() { public void eat() { System.out.println("eat something"); } }; p.eat(); }}運(yùn)行結(jié)果:
eat something
可以看到,我們直接將抽象類(lèi)Person中的方法在大括號(hào)中實(shí)現(xiàn)了,這樣便可以省略一個(gè)類(lèi)的書(shū)寫(xiě),并且匿名內(nèi)部類(lèi)還能用于接口上
實(shí)例3:在接口上使用匿名內(nèi)部類(lèi)
interface Person { public void eat();}public class test { public static void main(String[] args) { Person p = new Person() { public void eat() { System.out.println("eat something"); } }; p.eat(); }}運(yùn)行結(jié)果:
eat something
由上面的例子可以看出,只要一個(gè)類(lèi)是抽象的或是一個(gè)接口,那么其子類(lèi)中的方法都可以使用匿名內(nèi)部類(lèi)來(lái)實(shí)現(xiàn)。最常用的情況就是在多線程的實(shí)現(xiàn)上,因?yàn)橐獙?shí)現(xiàn)多線程必須繼承Thread類(lèi)或是繼承Runnable接口
實(shí)例4:Thread類(lèi)的匿名內(nèi)部類(lèi)實(shí)現(xiàn)
public class test { 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(); }}運(yùn)行結(jié)果:
1 2 3 4 5
實(shí)例5:Runnable接口的匿名內(nèi)部類(lèi)實(shí)現(xiàn)
public class test { 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(); }}運(yùn)行結(jié)果:
1 2 3 4 5
參考資料:1、http://m.survivalescaperooms.com/nerxious/archive/2013/01/25/2876489.html
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注