首页 > 编程 > Java > 正文

《Thinking In Java》内部类

2019-11-08 01:04:54
字体:
来源:转载
供稿:网友

《Thinking In java》内部类

定义:可以将一个类的定义放在另一个类的内部,这就是内部类。

创建内部类

public class OuterTest1 {PRivate String name = "王天逾";//创建内部类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();}}

打印结果:

姓名:王天逾 年龄:22

外部类有一个方法getInnerClass1()返回一个内部类的引用。在内部类有个普通方法f1(),它可以访问外部类变量name,即使它在外围类中是private修饰符。也就是说,当生成一个内部类对象时,此对象与制造它的外围类对象直接就有了联系,它能够访问外围类对象的所有成员,内部类还拥有其外围类的所有的访问权。

.this 和 .new用法

.this用法介绍

如果你想在内部类中返回外部类对象的引用,可以使用外部类的名字.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用法介绍

有时候你想要告知某些其他对象去创建其某个内部类对象,要实现这个目的,就必须在new表达式中提供对其外部类对象的引用,这就需要.new用法

此时删掉getInnerInstance()方法,在main()中创建内部类对象,看一下代码

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(); }}

注意: 这里必须使用外部类的对象来创建该内部类对象,之所以这么做,是因为内部类对象会默认连接到外部类对象中。但是,如果创建的是静态内部类,那么它就不需要对外部类对象的引用了。

对于后半句,来写一下。是可以编译运行的。

public class OuterTest1 { static class InnerClass{public void getSomething(){ System.out.println("这是静态内部类。。。"); }}public static void main(String[] args) {InnerClass innerClass = new InnerClass();innerClass.getSomething(); }}

内部类与向上转型

public class OuterTest2 {private class DestinationImpl implements Destination {String s;DestinationImpl(String s) {this.s = s;}@Overridepublic void readDestination() {System.out.println(s);}}protected class ContentsImpl implements Contents {@Overridepublic 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();}}

内部类实现了接口,得到了对此接口的引用,与向上转型为这个对象的基类,是一样的。

在方法的内部类(局部内部类)

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()之外是无法访问MyDestinationImpl的。return的时候使用了向上转型,因为Destination是MyDestinationImpl的基类。

在特定的作用域内的内部类

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语句的作用域内,在定义MyClass类之外的作用域是不可用的,除此之外,它与普通类没区别。

匿名内部类

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()); }}

匿名内部类:创建一个继承自父类的匿名内对象,通过new表达式返回的引用被自动向上转型为对父类(这里是Contents)的引用。

将上面匿名内部类改成正常形式。

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不需要接收参数,使用了默认构造,那么,想要为父类传递参数呢?

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) {@Overridepublic int f() {return super.f() * 100; } };}public static void main(String[] args) {OuterTest3 outerTest3 = new OuterTest3();System.out.println(outerTest3.getFuObject(2).f()); }}

只需简单的传递合适的参数给基类的构造器就好了。

在匿名内部类中定义字段时,还能够对其进行初始化操作

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()); }}

如果定义一个匿名内部类,并且希望其使用外部定义的对象,那么参数引用必须是final类型。

为匿名内部类创建”构造器效果”

匿名内部类不可能有命名构造器(因为它没有名字),但可以通过实例初始化,就能够达到为匿名内部类创建构造器效果。

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();}}

打印结果:

10insideanonymous

这里没有为参数设置final int i,是因为匿名内部类中没有使用i,只是传递给了父类构造。

嵌套类

定义:如果不需要内部类对象与其外围类对象之间有关系,那么可以将内部类声明为static

普通内部类对象隐式地保存了一个引用,指向创建他的外围类对象,然而,当内部类为static时,就不是这样了。

要创建嵌套类对象,并不需要其外围类的对象不能从嵌套类的对象中访问非静态的外围类对象

普通内部类不能包含static数据和字段,而静态内部类则可以

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()中,根本就没有生成外部类对象,而是使用static成员的普通语法来调用一个返回对Contents接口的引用。

接口内部的类

通常情况下,接口内部不能放置任何代码,但嵌套类可以,在接口里面,默认类是public static,由于是static,只是将嵌套类置于接口的命名空间内,这并不违反接口的规则。

interface ClassInterfaces {void f();class OuterTest3 implements ClassInterfaces { @Override public void f() { System.out.println("接口内部类测试。。。"); } public static void main(String[] args) { new OuterTest3().f(); }}}

从多层嵌套类中访问外部类成员

一个内部类被嵌套多少层并不重要,它总能访问外部类的所有成员

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();}}

内部类的继承

内部类的构造器必须连接到外围类的对象的引用,所以,那个指向外围类对象的引用必须被初始化,而导出类中在不再存在可连接的默认对象,要解决这个问题,需要使用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(); }}

通过i.super(),提供了必要的引用,然后程序编译通过。

内部类标识符

每个类都会产生一个.class文件,内部类也不例外.

外部类的名字+”$”+内部类的名字

如果是匿名内部类,编译器会简单的产生一个数字作为其标识符。

如果内部类嵌套在别的内部类中,只需将他们的名字加在外围类标识符与$的后面

声明

这篇博文是《Thinking in Java》内部类读书笔记。还有几个内部类知识点没有搞明白,这里没做笔记,等下次充分理解后,再补充。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表