西安网站改版的公司,pr,免费公众号编辑器哪个好,小程序致美发型设计CONTENTS 1. 创建内部类2. 内部类到外部类的连接3. 在内部类中生成外部类对象的引用4. 匿名内部类5. 嵌套类6. 接口中的类 1. 创建内部类
创建内部类的方式就是把类定义放在一个包围它的类之中#xff1a;
package com.yyj;public class Parcel1 {class Contests {private i… CONTENTS 1. 创建内部类2. 内部类到外部类的连接3. 在内部类中生成外部类对象的引用4. 匿名内部类5. 嵌套类6. 接口中的类 1. 创建内部类
创建内部类的方式就是把类定义放在一个包围它的类之中
package com.yyj;public class Parcel1 {class Contests {private int x 1;public int value() { return x; }}class Destination {private String dest;Destination(String dest) {this.dest dest;}String getDest() { return dest; }}public void ship(String dest) {Contests c new Contests();Destination d new Destination(dest);System.out.println(d.getDest());}public static void main(String[] args) {
// Contests c new Contests(); // 不能这么定义Parcel1 p new Parcel1();p.ship(XDU); // XDU}
}2. 内部类到外部类的连接
到目前为止内部类看上去就是一种名称隐藏和代码组织机制。当创建一个内部类时这个内部类的对象中会隐含一个链接指向用于创建该对象的外围对象。通过该链接无须任何特殊条件内部类对象就可以访问外围对象的成员。此外内部类拥有対外围对象所有元素的访问权
package com.yyj;interface Selector {boolean end(); // 是否到尾部Object current(); // 返回当前对象void next(); // 指向下一个对象
}public class Sequence {private Object[] objs;private int now 0;public Sequence(int size) {objs new Object[size];}public void add(Object x) { // 添加对象xif (now objs.length)objs[now] x;}private class SequenceSelector implements Selector { // 用于移动和选择每个元素private int i 0;Overridepublic boolean end() { return i objs.length; }Overridepublic Object current() { return objs[i]; }Overridepublic void next() {if (i objs.length) i;}}public Selector getSelector() {return new SequenceSelector();}public static void main(String[] args) {Sequence seq new Sequence(10);for (int i 0; i 10; i)seq.add(Integer.toString(i)); // 向Sequence中加入String对象Selector s seq.getSelector();while (!s.end()) {System.out.print(s.current() );s.next();}}
}Sequence 是以类的形式包装起来的定长 Object 数组可以调用 add() 向序列末尾增加一个新的 Object如果还有空间。要取得 Sequence 中的每一个对象可以使用名为 Selector 的接口这是迭代器Iterator设计模式的一个例子。
SequenceSelector 中的 end()、current() 和 next() 这些方法中的每一个都用到了外部类的字段 objs这个引用并不是 SequenceSelector 的一部分而是外围对象的一个 private 字段。然而内部类可以访问外围对象的所有方法和字段就好像拥有它们一样。
这是怎么做到的呢对于负责创建内部类对象的特定外围类对象而言内部类对象偷偷地获取了一个指向它的引用。然后当你要访问外围类的成员时该引用会被用于选择相应的外围类成员。幸运的是编译器会为你处理所有的这些细节。
3. 在内部类中生成外部类对象的引用
要生成外部类对象的引用可以使用外部类的名字后面加上 .this。这样生成的引用会自动具有正确的类型而且是可以在编译时确定并检查的所以没有任何运行时开销如下所示
package com.yyj;public class DotThis {void f() {System.out.println(DotThis.f());}public class Inner {public DotThis outer() {return DotThis.this; // 如果直接写this引用的是Inner的this}}public Inner getInner() { return new Inner(); }public static void main(String[] args) {DotThis dt new DotThis();DotThis.Inner dti dt.getInner(); // 使用外部类的对象来创建内部类dti.outer().f(); // DotThis.f()}
}有时我们想让其他某个对象来创建它的某个内部类的对象要实现这样的功能可以使用 .new 语法在 new 表达式中提供指向其他外部类对象的引用就像下面这样
// 在内部类中生成外部类对象的引用package com.yyj;public class DotNew {public class Inner {void f() {System.out.println(Inner.f());}}public static void main(String[] args) {DotNew dn new DotNew();DotNew.Inner dni dn.new Inner();dni.f(); // Inner.f()}
}我们要使用外部类的对象来创建内部类的对象正如我们在示例代码中所看到的那样这也解决了内部类的名字作用域问题。
除非已经有了一个外部类的对象否则创建内部类对象是不可能的这是因为内部类的对象会暗中连接到用于创建它的外部类对象。然而如果你创建的是嵌套类static 修饰的内部类它就不需要指向外部类对象的引用。
4. 匿名内部类
我们先来看一下如何创建匿名内部类
package com.yyj;interface AnonymousIf {int value();
}public class AnonymousClass {public AnonymousIf getAnanymousIf() {return new AnonymousIf() {private int x 1;Overridepublic int value() {return x;}};}public static void main(String[] args) {AnonymousClass ac new AnonymousClass();AnonymousIf ai ac.getAnanymousIf();System.out.println(ai.value());}
}这段代码的意思是创建一个继承自 AnonymousIf 的匿名类的对象通过 new 表达式返回的引用会被自动地向上转型为一个 AnonymousIf 引用。
在这个匿名内部类中AnonymousIf 是用无参构造器创建的如果基类需要带一个参数的构造器可以这么做
package com.yyj;class BaseAnonyClass {private int x;BaseAnonyClass(int value) {x value;System.out.println(Construct BaseAnonyClass with value);}int value() { return x; }
}public class AnonymousClass {public BaseAnonyClass getBaseAnonyClass(int value, final String str) { // 用到匿名类之外的对象需要用final修饰return new BaseAnonyClass(value) { // 基类构造器的调用private String name;{ // 匿名内部类的构造器name str;System.out.println(Anonymous class constructor);}Overridepublic int value() {return super.value() * 2;}Overridepublic String toString() {return name;}};}public static void main(String[] args) {AnonymousClass ac new AnonymousClass();BaseAnonyClass b ac.getBaseAnonyClass(10, AsanoSaki);System.out.println(b.value());System.out.println(b);/** Construct BaseAnonyClass with 10* Anonymous class constructor* 20* AsanoSaki*/}
}也可以在定义匿名类中的字段时执行初始化如果你正在定义一个匿名类而且一定要用到一个在该匿名类之外定义的对象编译器要求参数引用需要用 final 修饰或者是“实际上的最终变量”也就是说在初始化之后它永远不会改变所以它可以被视为 final 的。这里变量 value 被传给了匿名类的基类构造器并没有在匿名类的内部被直接用到因此不是必须为 final 变量。
如果必须在匿名类中执行某个类似构造器的动作该怎么办呢因为匿名类没有名字所以不可能有命名的构造器。我们可以借助实例初始化使用 {} 语句块在效果上为匿名内部类创建一个构造器。
5. 嵌套类
如果不需要内部类对象和外部类对象之间的连接可以将内部类设置为 static 的我们通常称之为嵌套类。要理解 static 应用于内部类时的含义请记住普通内部类对象中隐式地保留了一个引用指向创建该对象的外部类对象对于 static 的内部类来说情况就不是这样了嵌套类意味着
不需要一个外部类对象来创建嵌套类对象。无法从嵌套类对象内部访问非 static 的外部类对象。
从另一方面来看嵌套类和普通内部类还有些不同。普通内部类的字段和方法只能放在类的外部层次中所以普通内部类中不能有 static 数据、static 字段也不能包含嵌套类但是嵌套类中可以包含所有这些内容
package com.yyj;public class NestedClass {private static class StaticInner {static int x 10;public static void f() {System.out.println(StaticInner static f());}StaticInner() {System.out.println(Construct StaticInner);}static class AnotherStaticClass {public static void f() {System.out.println(AnotherStaticClass static f());}}}public static void main(String[] args) {StaticInner si new StaticInner();StaticInner.f();StaticInner.AnotherStaticClass.f();/** Construct StaticInner* StaticInner static f()* AnotherStaticClass static f()*/}
}可以看到我们在 main() 中并不需要创建 NestedClass 对象就能直接创建 static 的内部类对象。
6. 接口中的类
嵌套类可以是接口的一部分放到接口中的任何类都会自动成为 public 和 static 的因为类是 static 的所以被嵌套的类只是放在了这个接口的命名空间内甚至可以在内部类内实现包围它的这个接口就像这样
package com.yyj;public interface ClassInInterface {void f();class Inner implements ClassInInterface {Overridepublic void f() {System.out.println(ClassInInterface.Inner f());}public static void main(String[] args) {new Inner().f();}}
}