外部类的创建
直接在 外部类里面 像定义其他类一样地去定义。
在外部类的非static方法中,要用自己定义的内部类就和用普通类一样,直接拿来就new。
除了外部类的feistatic方法,在其他地方像其他类中的方法或者是外部类的static方法中,要使用内部类则要用完整的 外部类.内部类名 这样的格式来标识一个内部类。
引用外部类的变量
内部类可以自动获得创建他的那个类中的类变量,这是因为内部类会暗中抓住 外部类对象 的引用,当你要用到外部类的 类变量的适合,这个引用会帮你选择正确的类变量。 因此 当你要创建一个 非static的内部类的对象的时候,一定只有在它和外部类的对象相关联的情况下,才能被创建。
.this和.new
上面说了,之所以内部类可以使用外部类的 类变量,是因为 偷偷抓住了 外部类对象的引用。 那么当你想要用到这个引用的时候,只需要OutClass.this就可以。 注意,直接在内部类中用this关键字,返回的引用是这个内部类对象的引用。
怎么直接创建内部类的对象呢??用.new关键字,下面看个例子:
DotNew.Inner dni = dn.new Inner();
这是在一个static方法中,前面要描述内部类,肯定要外部类.内部类名 这样,然后后面 new对象就要用这个语法,我们前面说过一定要通过外部类的 对象 才能建立内部类的对象,所以要用 外部类对象 dn 然后再.new + 内部类()。 注意这里 不用再 外部类.内部类()。
内部类可以实现某个接口,然后向上转型
一般的类的访问权限只能是public和default的package范围的嘛,但 内部类可以是private,protected的。再结合 接口实现和转型,可以生成更高效的代码。
方法内和作用域内的内部类
方法内的内部类例子:
//: innerclasses/Parcel5.java // Nesting a class within a method. public class Parcel5 { public Destination destination(String s) { class PDestination implements Destination { private String label; private PDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } return new PDestination(s); } public static void main(String[] args) { Parcel5 p = new Parcel5(); Destination d = p.destination("Tasmania"); } } ///:
还有贴一个笔记:
还有在作用域中 使用内部类的例子:
//: innerclasses/Parcel6.java // Nesting a class within a scope. public class Parcel6 { private void internalTracking(boolean b) { if(b) { class TrackingSlip { private String id; TrackingSlip(String s) { id = s; } String getSlip() { return id; } } TrackingSlip ts = new TrackingSlip("slip"); String s = ts.getSlip(); } // Can’t use it here! Out of scope: //! TrackingSlip ts = new TrackingSlip("x"); } public void track() { internalTracking(true); } public static void main(String[] args) { Parcel6 p = new Parcel6(); p.track(); } } ///:
匿名内部类
下面的例子是一个实现了Contents接口的匿名类,类的定义和return语句结合在了一起,注意后面还要有个分号:
public Contents contents() { return new Contents() { // Insert a class definition private int i = 11; public int value() { return i; } }; // Semicolon required in this case }
这是用默认的构造器来生成Contents,那么如果基类的构造器是需要参数的呢?
public Wrapping wrapping(int x) { // Base constructor call: return new Wrapping(x) { // Pass constructor argument. public int value() { return super.value() * 47; } }; // Semicolon required } //: innerclasses/Wrapping.java /** *基类 Wrapping */ public class Wrapping { private int i; public Wrapping(int x) { i = x; } public int value() { return i; } } ///:
在 匿名类中 初始化一些类变量或者干点什么:
// Argument must be final to use inside // anonymous inner class: public Destination destination(final String dest) { return new Destination() { private String label = dest; public String readLabel() { return label; } }; }
如果你在匿名类里面,要用到一个外面的定义的对象,那么编译器要求这个参数的引用是final的
匿名类是没有构造器的,那么如果你想像 构造器一样,做一些复杂点的 初始化工作呢?可以用 实力初始化——instance initialization来实现:
public Destination destination(final String dest, final float price) { return new Destination() { private int cost; // Instance initialization for each object: { cost = Math.round(price); if(cost > 100)System.out.println("Over budget!"); } private String label = dest; public String readLabel() { return label; } }; }
匿名类一般就是这样的语法来用的,要么是继承一个基类,像上面的 return new 基类(); 要么就实现一个接口 return new 接口();
但只能是一个操作,即匿名类要么继承一个基类,要么实现一个接口。
嵌套类(nested classes)
如果不需要内部类对象和外部类对象有联系的话,可以把内部类声明为static——这通常被称为是嵌套类。 我们知道,普通的内部类会偷偷抓个 外部类对象的引用,而嵌套类nested classes就不是这样了,当一个内部类被声明为static时,意味着:
- 要创建内部类的对象,不需要外部类的对象。
- 不能从内部类的对象中访问非static的外部类对象。
嵌套类和普通类还有个区别是,普通类的字段和方法只能放在外部层次上,所以普通内部类中不能有static字段和static数据,也不能包含嵌套类。 但是!!!嵌套类可以包含所有这些东西!!
所以内部的static类也就是嵌套类 有点像是一个static的方法。
interface里面的类
interface里面的东西,会自动变成public static,所以把嵌套类放在接口中,其实是不违背规则的! 甚至可以在内部嵌套类中实现外部的接口,看看例子:
public interface ClassInInterface { void howdy(); class Test implements ClassInInterface { public void howdy() { System.out.println("Howdy!"); } public static void main(String[] args) { new Test().howdy(); } } }
书上说,就很方便喔,如果你有些公共的代码,想所有的实现这个接口的类都共用,那么就可以这样 在j接口中放个嵌套类喔~
多层内部类中访问外部类成员
一个内部类不管在里面多少层,都可以访问它外部类的成员,哪怕是private的东西。
class MNA { private void f() {} class A { private void g() {} public class B { void h() { g(); f(); } } } } public class MultiNestingAccess { public static void main(String[] args) { MNA mna = new MNA(); MNA.A mnaa = mna.new A(); MNA.A.B mnaab = mnaa.new B(); mnaab.h(); } } ///:~