《Thinking In Java》內(nèi)部類
定義:可以將一個(gè)類的定義放在另一個(gè)類的內(nèi)部腻惠,這就是內(nèi)部類。
創(chuàng)建內(nèi)部類
public class OuterTest1 {
private String name = "王天逾";
//創(chuàng)建內(nèi)部類
class InnerClass1{
int i;
InnerClass1(int i){
this.i = i;
}
public void f1(){
System.out.println("姓名:"+name+" 年齡:"+this.i);
}
}
public InnerClass1 getInnerClass1(){
return new InnerClass1(22);
}
public static void main(String[] args) {
OuterTest1 outerTest1 = new OuterTest1();
outerTest1.getInnerClass1().f1();
}
}
打印結(jié)果:
姓名:王天逾 年齡:22
外部類有一個(gè)方法getInnerClass1()返回一個(gè)內(nèi)部類的引用乙各。在內(nèi)部類有個(gè)普通方法f1(),它可以訪問(wèn)外部類變量name,即使它在外圍類中是private修飾符爬骤。也就是說(shuō),當(dāng)生成一個(gè)內(nèi)部類對(duì)象時(shí)贱纠,此對(duì)象與制造它的外圍類對(duì)象直接就有了聯(lián)系峻厚,它能夠訪問(wèn)外圍類對(duì)象的所有成員,內(nèi)部類還擁有其外圍類的所有的訪問(wèn)權(quán)谆焊。
.this 和 .new用法
- .this用法介紹
如果你想在內(nèi)部類中返回外部類對(duì)象的引用惠桃,可以使用外部類的名字.this
public class OuterTest1 {
public void f1(){
System.out.println(".this用法。辖试。辜王。");
}
class InnerClass{
public OuterTest1 getOuterObject(){
return OuterTest1.this;
}
}
public InnerClass getInnerInstance(){
return new InnerClass();
}
public static void main(String[] args) {
OuterTest1 outerTest1 = new OuterTest1();
outerTest1.getInnerInstance().getOuterObject().f1();
}
}
- .new用法介紹
有時(shí)候你想要告知某些其他對(duì)象去創(chuàng)建其某個(gè)內(nèi)部類對(duì)象,要實(shí)現(xiàn)這個(gè)目的罐孝,就必須在new表達(dá)式中提供對(duì)其外部類對(duì)象的引用呐馆,這就需要.new用法
此時(shí)刪掉getInnerInstance()方法,在main()中創(chuàng)建內(nèi)部類對(duì)象莲兢,看一下代碼
public class OuterTest1 {
public void f1(){
System.out.println(".new用法汹来。。改艇。");
}
class InnerClass{
public OuterTest1 getOuterObject(){
return OuterTest1.this;
}
}
public static void main(String[] args) {
OuterTest1 outerTest= new OuterTest1();
outerTest.new InnerClass().getOuterObject().f1();
}
}
<font color=#f00 size=3>注意:
這里必須使用外部類的對(duì)象來(lái)創(chuàng)建該內(nèi)部類對(duì)象收班,之所以這么做,是因?yàn)閮?nèi)部類對(duì)象會(huì)默認(rèn)連接到外部類對(duì)象中遣耍。但是闺阱,如果創(chuàng)建的是靜態(tài)內(nèi)部類,那么它就不需要對(duì)外部類對(duì)象的引用了舵变。</font>
對(duì)于后半句酣溃,來(lái)寫(xiě)一下瘦穆。是可以編譯運(yùn)行的。
public class OuterTest1 {
static class InnerClass{
public void getSomething(){
System.out.println("這是靜態(tài)內(nèi)部類赊豌。扛或。。");
}
}
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
innerClass.getSomething();
}
}
內(nèi)部類與向上轉(zhuǎn)型
public class OuterTest2 {
private class DestinationImpl implements Destination {
String s;
DestinationImpl(String s) {
this.s = s;
}
@Override
public void readDestination() {
System.out.println(s);
}
}
protected class ContentsImpl implements Contents {
@Override
public int value() {
return 1;
}
}
public Destination getDestination() {
return new DestinationImpl("崇明島");
}
public Contents getContents() {
return new ContentsImpl();
}
public static void main(String[] args) {
OuterTest2 outerTest2 = new OuterTest2();
outerTest2.getDestination().readDestination();
outerTest2.getContents().value();
}
}
內(nèi)部類實(shí)現(xiàn)了接口碘饼,得到了對(duì)此接口的引用熙兔,與向上轉(zhuǎn)型為這個(gè)對(duì)象的基類,是一樣的艾恼。
在方法的內(nèi)部類(局部?jī)?nèi)部類)
public class OuterTest3 {
public Destination getDestination(){
class MyDestinationImpl implements Destination{
@Override
public void readDestination() {
System.out.println("111");
}
}
return new MyDestinationImpl();
}
public static void main(String[] args) {
OuterTest3 outerTest3 = new OuterTest3();
outerTest3.getDestination().readDestination();
}
}
MyDestinationImpl類是getDestination()的一部分住涉,而不是OuterTest3的一部分。所以钠绍,在getDestination()之外是無(wú)法訪問(wèn)MyDestinationImpl的舆声。return的時(shí)候使用了向上轉(zhuǎn)型,因?yàn)镈estination是MyDestinationImpl的基類柳爽。
在特定的作用域內(nèi)的內(nèi)部類
public class OuterTest3 {
private void f1(boolean b){
if(b){
class MyClass {
void f2(){
System.out.println("5201314");
}
}
MyClass myClass = new MyClass();
myClass.f2();
}
}
public static void main(String[] args) {
OuterTest3 outerTest3 = new OuterTest3();
outerTest3.f1(true);
}
}
MyClass是被嵌入在if語(yǔ)句的作用域內(nèi)媳握,在定義MyClass類之外的作用域是不可用的,除此之外磷脯,它與普通類沒(méi)區(qū)別蛾找。
匿名內(nèi)部類
public class OuterTest3 {
public Contents getContents() {
return new Contents() {
@Override
public int value() {
return 520;
}
};
}
public static void main(String[] args) {
OuterTest3 outerTest3 = new OuterTest3();
System.out.println(outerTest3.getContents().value());
}
}
匿名內(nèi)部類:創(chuàng)建一個(gè)繼承自父類的匿名內(nèi)對(duì)象,通過(guò)new表達(dá)式返回的引用被自動(dòng)向上轉(zhuǎn)型為對(duì)父類(這里是Contents)的引用赵誓。
將上面匿名內(nèi)部類改成正常形式打毛。
public class OuterTest3 {
public Contents getContents() {
return new ContentsImpl();
}
class ContentsImpl implements Contents {
@Override
public int value() {
return 520;
}
}
public static void main(String[] args) {
OuterTest3 outerTest3 = new OuterTest3();
System.out.println(outerTest3.getContents().value());
}
}
在這里父類Contents不需要接收參數(shù),使用了默認(rèn)構(gòu)造架曹,那么隘冲,想要為父類傳遞參數(shù)呢闹瞧?
class Fu {
int i;
Fu(int i) {
this.i = i;
}
public int f() {
return this.i;
}
}
public class OuterTest3 {
public Fu getFuObject(int i) {
return new Fu(i) {
@Override
public int f() {
return super.f() * 100;
}
};
}
public static void main(String[] args) {
OuterTest3 outerTest3 = new OuterTest3();
System.out.println(outerTest3.getFuObject(2).f());
}
}
只需簡(jiǎn)單的傳遞合適的參數(shù)給基類的構(gòu)造器就好了绑雄。
在匿名內(nèi)部類中定義字段時(shí),還能夠?qū)ζ溥M(jìn)行初始化操作
public class OuterTest3 {
public Contents getContents(final int i) {
return new Contents() {
int ii=i;
@Override
public int value() {
return ii;
}
};
}
public static void main(String[] args) {
OuterTest3 outerTest3 = new OuterTest3();
System.out.println(outerTest3.getContents(100).value());
}
}
如果定義一個(gè)匿名內(nèi)部類奥邮,并且希望其使用外部定義的對(duì)象万牺,那么參數(shù)引用必須是final類型。
為匿名內(nèi)部類創(chuàng)建"構(gòu)造器效果"
匿名內(nèi)部類不可能有命名構(gòu)造器(因?yàn)樗鼪](méi)有名字)洽腺,但可以通過(guò)實(shí)例初始化脚粟,就能夠達(dá)到為匿名內(nèi)部類創(chuàng)建構(gòu)造器效果。
abstract class BaseClass{
public abstract void f();
BaseClass(int i){
System.out.println(i);
}
}
public class OuterTest3 {
static class MyBase {
public BaseClass getBaseClass(int i){
return new BaseClass(i) {
{
System.out.println("inside");
}
@Override
public void f() {
System.out.println("anonymous");
}
};
}
}
public static void main(String[] args) {
MyBase myBase = new MyBase();
myBase.getBaseClass(10).f();
}
}
打印結(jié)果:
10
inside
anonymous
這里沒(méi)有為參數(shù)設(shè)置final int i,是因?yàn)槟涿麅?nèi)部類中沒(méi)有使用i,只是傳遞給了父類構(gòu)造蘸朋。
嵌套類
定義:如果不需要內(nèi)部類對(duì)象與其外圍類對(duì)象之間有關(guān)系核无,那么可以將內(nèi)部類聲明為static
普通內(nèi)部類對(duì)象隱式地保存了一個(gè)引用,指向創(chuàng)建他的外圍類對(duì)象藕坯,然而团南,當(dāng)內(nèi)部類為static時(shí)噪沙,就不是這樣了。
<font color=#f00 size=3>
- 要?jiǎng)?chuàng)建嵌套類對(duì)象吐根,并不需要其外圍類的對(duì)象
- 不能從嵌套類的對(duì)象中訪問(wèn)非靜態(tài)的外圍類對(duì)象
</font>
普通內(nèi)部類不能包含static數(shù)據(jù)和字段正歼,而靜態(tài)內(nèi)部類則可以
public class OuterTest3 {
private static class MyContentImpl implements Contents{
private static int i=1;
@Override
public int value() {
return 100+i;
}
}
public static Contents getContents(){
return new MyContentImpl();
}
public static void main(String[] args) {
Contents contents = getContents();
System.out.println(contents.value());
}
}
在main()中,根本就沒(méi)有生成外部類對(duì)象拷橘,而是使用static成員的普通語(yǔ)法來(lái)調(diào)用一個(gè)返回對(duì)Contents接口的引用局义。
接口內(nèi)部的類
通常情況下,接口內(nèi)部不能放置任何代碼冗疮,但嵌套類可以萄唇,在接口里面,默認(rèn)類是public static术幔,由于是static穷绵,只是將嵌套類置于接口的命名空間內(nèi),這并不違反接口的規(guī)則特愿。
interface ClassInterfaces {
void f();
class OuterTest3 implements ClassInterfaces {
@Override
public void f() {
System.out.println("接口內(nèi)部類測(cè)試仲墨。。揍障。");
}
public static void main(String[] args) {
new OuterTest3().f();
}
}
}
從多層嵌套類中訪問(wèn)外部類成員
一個(gè)內(nèi)部類被嵌套多少層并不重要目养,它總能訪問(wèn)外部類的所有成員
public class MNA {
private void f1() {
System.out.println("f1");
}
class A {
private void f2() {
System.out.println("f2");
}
public class B {
private void f3() {
f1();
f2();
}
}
}
public static void main(String[] args) {
MNA mna = new MNA();
A a = mna.new A();
A.B b = a.new B();
b.f3();
}
}
內(nèi)部類的繼承
內(nèi)部類的構(gòu)造器必須連接到外圍類的對(duì)象的引用,所以毒嫡,那個(gè)指向外圍類對(duì)象的引用必須被初始化癌蚁,而導(dǎo)出類中在不再存在可連接的默認(rèn)對(duì)象,要解決這個(gè)問(wèn)題兜畸,需要使用enclosingClassReference.super();
class WithInner {
class Inner {
public void f() {
System.out.println("hh");
}
}
}
public class InheritInner extends WithInner.Inner {
InheritInner(WithInner i) {
i.super();
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner inheritInner = new InheritInner(wi);
inheritInner.f();
}
}
通過(guò)i.super()努释,提供了必要的引用,然后程序編譯通過(guò)咬摇。
內(nèi)部類標(biāo)識(shí)符
每個(gè)類都會(huì)產(chǎn)生一個(gè).class文件伐蒂,內(nèi)部類也不例外.
外部類的名字+"$"+內(nèi)部類的名字
如果是匿名內(nèi)部類,編譯器會(huì)簡(jiǎn)單的產(chǎn)生一個(gè)數(shù)字作為其標(biāo)識(shí)符肛鹏。
如果內(nèi)部類嵌套在別的內(nèi)部類中逸邦,只需將他們的名字加在外圍類標(biāo)識(shí)符與$的后面
聲明
這篇博文是《Thinking in Java》內(nèi)部類讀書(shū)筆記。還有幾個(gè)內(nèi)部類知識(shí)點(diǎn)沒(méi)有搞明白在扰,這里沒(méi)做筆記缕减,等下次充分理解后,再補(bǔ)充芒珠。