• 1. Lesson 11: Nested Types嵌套类型Shanghai University2008Inner Classes and Interfaces 内部类和内部接口
  • 2. 内部类内部类,是在一个类的内部定义的类。 匿名类是一种特殊的内部类。 内部类的特性 内部类的实例化,参见InnerInit.java
  • 3. Nested Types嵌套类型嵌套类型(Nested Types)指声明在其它类或接口中的类或接口 Java语言在1.2版本以后才提供对嵌套类型的支持 提供对嵌套类型的支持有以下目的: (1) 使类型(类或接口)构成不同的逻辑分组 (2) 以简单有效的方式将逻辑上相关的对象组织在一起
  • 4. 嵌套类型的分类嵌套类型包括嵌套类和嵌套接口(少见) 注意:嵌套类有时用内部类Inner class称呼,而把嵌套类专门指静态成员类。 根据嵌套类型声明的位置,可以分为成员类型和局部类型 与嵌套类型相对,包含嵌套类型的类型称为封装类(Enclosing Types),最外层的是顶级类/顶级接口。
  • 5. Member Types (成员类型)成员类型(Member Types)指定义在其它类型中,与其它类型的域和方法同级的类型 成员类型分为成员类(Member Classes)和成员接口(Member Interfaces) 成员类分为静态成员类( 也称为Nested Classes)和非静态成员类(实例成员类) 成员接口只能是静态成员接口
  • 6. Next10.14
  • 7. Static Member Classes (静态成员类)静态成员类可以声明在类或接口中,与类的静态域和静态方法相似,被static关键字修饰 除了类名表达方式外,静态成员类与一般的非嵌套类相同,可以被final或abstract修饰 静态成员类与其封装类型一般具有紧密的逻辑相关性 静态成员类中能直接访问其封装类中静态成员,但不能访问非静态成员package bank; public class BankAccount{ private long number; private long balance; public static class Permissions{ public boolean canDeposite, canWithdraw, canClose; } …… }
  • 8. Static Member Classes (静态成员类)可以使用与类的静态成员相同的访问控制修饰符来控制对静态成员类的访问 静态成员类的类名表达有两种方式: (1) <封装类型名>.<静态成员类类名> (2) 当封装类在包中时,可以导入静态成员类,直接使用类名 静态成员类的引用类型变量的声明和静态成员类的对象创建与一般非嵌套类相同 import bank.BankAccount; …… BankAccount.Permissions perms=new BankAccount.Permissions(); ……import bank.BankAccount.Permissions; …… Permissions perms=new Permissions(); ……
  • 9. Non-static Member Classes (非静态成员类)非静态成员类只能声明在类中 非静态成员类的对象总是与其封装类的对象相关联,在语义上,没有封装类的对象就不能存在非静态成员类的对象 非静态成员类中可以直接访问其封装类的所有成员,除非被非静态成员类中声明的同名成员隐藏 非静态成员类中不能包含static的成员public class BankAccount{ private long number; private long balance; private Action lastAct; public class Action{ private String act; private long amount; Action(String act, long amount){ this.act=act; this.amount=amount; } public String toString(){ return number+ “: ”+act+ “ ”+amount; } } public void deposite(long amount){ balance+=amount; lastAct=new Action(“deposite”,amount); } …… }
  • 10. Non-static Member Classes (非静态成员类)非静态成员类中的this引用只能访问非静态成员类实例本身,要访问其封装类实例必须使用以下语法格式:<封装类类名>.this 例如:BankAccount.this.balance 非静态成员类的类名表达方式与静态成员类相同,但创建对象要按照以下语法格式: <封装类对象引用>.new <非静态成员类构造函数>import bank.BankAccount; import bank.BankAccount.Action; …… BankAccount account=new BankAccount(); Action act=account.new Action(); ……
  • 11. (本页无文本内容)
  • 12. 内部类的特性内部类可以直接访问外部类的成员。如果是定义在方法中的内部类,还可以访问该方法中的final型的局部变量和final型的方法参数。参见ClassA.java
  • 13. 内部类的特性非静态的内部类不能声明任何static成员;静态的内部类中可以声明static成员。 class A{ class B{static int var; //ERROR } } class C{ static class D{ static int v; //CORRECT static class E{} //CORRECT } }
  • 14. (本页无文本内容)
  • 15. Nested Interfaces (嵌套接口)嵌套接口可以声明在类或接口中 嵌套接口只能作为封装类或封装接口的静态成员,通常static修饰符被忽略 在面向接口的设计原则中,嵌套接口通常作为其封装类或封装接口中方法的返回类型
  • 16. Local Types (局部类型)局部类型(Local Types)指定义在其它类的方法或初始化块中的类型 局部类型只能是类不能是接口,声明在静态方法或静态初始化块中的局部类称为静态局部类,声明在非静态方法或非静态初始化块中的局部类称为非静态局部类 非静态局部类和非静态成员类又统称为内部类(Inner Classes)
  • 17. Local Types (局部类型)局部类中不能包含静态成员 局部类只能使用final或abstract关键字修饰,不能使用public或static修饰 非静态局部类可以使用与非静态成员类相同的方式访问其封装类的实例 非静态局部类中可以直接访问其封装方法的局部变量或参数变量,但局部变量或参数变量必须声明为final
  • 18. Local Types (局部类型)局部类的域可以隐藏其封装方法中的同名局部变量或参数变量,其封装方法中的同名局部变量或参数变量一旦被隐藏则无法访问 局部类只能在其封装方法或封装块中使用package java.util.Iterator; public interface Iterator{ boolean hasNext(); Object next() throws NoSuchElementException; void remove() throws NoSuchElementException; }public static Iterator walkThrough(final Object[] objs){ class Iter implements java.util.Iterator{ private int pos=0; public boolean hasNext(){ return (pos=objs.length) throw new NoSuchElementException(); return objs[pos++]; } public void remove(){…} } return new Iter(); }
  • 19. Anonymous Classes (匿名类)匿名类是一种特殊的局部类 匿名类通常作为抽象类或接口的实现类使用 匿名类不能定义自己的构造函数,只能使用父类或默认的构造函数 匿名类对象的创建的同时也提供了对接口或抽象类的实现public static Iterator walkThrough(final Object[] objs){ return new Iterator(){ private int pos=0; public boolean hasNext(){ return (pos=objs.length) throw new NoSuchElementException(); return objs[pos++]; } public void remove(){…} } }package java.util.Iterator; public interface Iterator{ boolean hasNext(); Object next() throws NoSuchElementException; void remove() throws NoSuchElementException; }
  • 20. 内部匿名类interface OuterIFC { void method(); } abstract public class Outer{ void method(){}; class Inner1{} //在类的方法外部定义的内部类 OuterIFC o = new OuterIFC(){ int i = 1; void method() { i++; } }; //一个覆盖了Outer类的method()方法的匿名类 OuterIFC getInstance(){}
  • 21. 内部匿名类void outerMethod() { class Inner2{}; OuterIFC ifc= new OuterIFC(){ int i=1; public void method(){i++;} }; //一个实现了OuterIFC接口的匿名类 } }//end of class Outer
  • 22. 匿名类– 一次性使用的类匿名类不用class关键字还没有修饰符。 匿名类没有名字,也就没有构造函数,定义初始化块相当于匿名类的构造函数,也不能包含静态成员。static fields / methods can only be declared in a static or top level type inner class 与 inner class 之间不会构成override关系。OuterFather.In.class; OuterSon.In.class. package:代表同事fellow(group)关系;嵌套类(Nested static class静态成员内部类,不能匿名)代表朋友关系,可以相互说悄悄话;内部类(inner class:含实例成员内部类/局部内部类/实参匿名内部类)代表夫妻关系,其不能单独存在,“财产共用”不必显式指明OuterXXX.this。 匿名内部类是一次性用品,只能在其创建处直接用new新建实例。比private类的作用域(授权范围)还小。
  • 23. Inheritanting Nested Types继承静态成员类或实现成员接口遵循一般的继承类或实现接口的规则 内部类的子类必须与被继承的内部类的封装类的实例关联 内部类的子类不一定也是内部类class Outer{ class Inner{} } class ExtendedOuter extends Outer{ class ExtendedInner extends Inner{} } Outer outerRef=new ExtendedOuter(); Outer.Inner innerRef=outerRef.new ExtendedInner();class Unrelated extends Outer.Inner{ Unrelated(Outer ref){ ref.super(); } } Outer outerRef=new Outer(); Unrelated ref=outerRef.new Unrelated(); 错误Unrelated ref=new Unrealted(outerRef);
  • 24. abstract class Device{ abstract class Port{ …… } }class Printer extends Device{ class SerialPort extends Port{ public String toString(){ return “Printer.Port”; } } public Port serial=new SerialPort(); }class HighSpeedPrinter extends Printer{ class SerialPort extends Printer.Port{ public String toString(){ return “HighSpeedPrinter.Port”; } } } HighSpeedPrinter printer=new HighSpeedPrinter(); System.out.println(printer.serial); 例子
  • 25. (本页无文本内容)
  • 26. Class A {//编译生成一个A.class文件 … class B { //编译生成一个A$B.class,与外部类A属于同一个包. … } … } 内部类可作为类的一个成员使用。一般只在包容类中调用。 内部类可以访问外包类的所有成员。 类里面除了有成员变量、成员函数,还有成员类。 实际上内部类可以称之为成员类,成员类也具有成员函数和成员变量一样的属性。成员类可以访问私有变量,成员类里面的所有的成员函数可以访问内部类外面那个类的所有私有变量。内部类的编译与使用
  • 27. Typically, an outer class will have a method that returns a reference to an inner class, like this:public class Parcel2 {//包裹 class Contents { private int i = 11; public int value() { return i; } } class Destination { private String label; Destination(String whereTo) { label = whereTo; } String readLabel() { return label; } } public Destination to(String s) { return new Destination(s); } public Contents cont() { return new Contents(); } public void ship(String dest) {//航运, 载运 Contents c = cont(); Destination d = to(dest); System.out.println(d.readLabel()); } public static void main(String[] args) { Parcel2 p = new Parcel2(); p.ship("Tanzania"); Parcel2 q = new Parcel2(); // Defining references to inner classes: Parcel2.Contents c = q.cont(); Parcel2.Destination d = q.to("Borneo"); } } ///:~
  • 28. Anonymous inner classes//A method that returns an anonymous inner class. public class Parcel6 { public Contents cont() { return new Contents() { //实现一个接口或继承一个基类 private int i = 11; public int value() { return i; } }; // Semicolon required in this case } public static void main(String[] args) { Parcel6 p = new Parcel6(); Contents c = p.cont(); } }// cont方法等价于: public Contents cont() { class MyContents implements Contents { private int i = 11; public int value() { return i; } } return new MyContents(); }public interface Contents { int value(); }
  • 29. Why inner classes?Each inner class can independently inherit from an implementation. Thus, the inner class is not limited by whether the outer class is already inheriting from an implementation. Without the ability that inner classes provide to inherit—in effect—from more than one concrete or abstract class, some design and programming problems would be intractable. So one way to look at the inner class is as the rest of the solution of the multiple-inheritance problem. Interfaces solve part of the problem, but inner classes effectively allow “multiple implementation inheritance.” That is, inner classes effectively allow you to inherit from more than one non-interface.
  • 30. Why inner classes?An object of an inner class can access the implementation of the object that created it—including data that would otherwise be private. 内部类对象能够访问创建它的对象的实现--包括那些私有数据! Inner classes can be hidden from other classes in the same package. 内部类能够隐藏起来,不为同一包的其他类所见。 Anonymous inner classes are handy when you want to define callbacks on the fly. 匿名内部类可以方便的定义运行时回调。 Inner classes are very convenient when you are writing event-driven programs. 使用内部类在编写事件驱动时的程序时用起来很方便。 新的消息机制需要有一个类能够访问另外一个类的私有成员。为了解决因为多个类同时继承一个很小的类时,所带来的命名问题。
  • 31. 本章小结2成员嵌套类 (嵌套成员类Nested static class)代表朋友关系, 知己private(C++的友元)。顶级类和static类才能有static成员。(而C#不支持除Nested class之外的内部类,并采用统一的嵌套作用域规则) 成员内部类(内部成员类inner class)代表夫妻关系,其不能单独存在,“财产共用,不用借”,不必显式指明OuterXXX.this。 局部内部类只能用abstract和final修饰。(方法内使用) 匿名内部类不能有任何修饰符。只能在其创建处建实例。比private类的作用域(授权范围)还小。 一次性用品。 在java中可以利用Inner class 部分实现Closure(闭包)和 Callback(回调)语义。
  • 32. 函数闭包普通函数运行结束后栈中局部变量就清除了,但是函数返回一个内部函数,此内部函数使用外部函数了局部变量,所以需要保存好内部函数使用的(外部函数了局部变量)。 Essentially a closure is a block of code that can be passed as an argument to a function call. 闭包是可以包含自由(未绑定)变量的代码块(不是函数或类)。更好开发小粒度并行机制。
  • 33. 嵌套类型的分类3内部 / 嵌套接口(必须有名字):成员接口只能是静态成员接口和局部接口。2内部 / 嵌套类有名字 / 匿名类成员类 和 局部类1与嵌套/内部 类/接口相对,包含嵌套类/接口的类型称为封装类(Enclosing Types)或外部 类/接口/方法,最外层的是顶级 类/接口。成员类分为静态成员类( 也称为Nested Classes,必须有名字) 和非静态成员类(实例成员类)声明在静态方法或静态初始化块中的局部类称为静态局部类,声明在非静态方法或非静态初始化块中的局部类称为非静态局部类
  • 34. Assignments (作业)重新设计前面例子中的类Printer和类HighSpeedPrinter,使HighSpeedPrinter类对象中继承父类的域serial为HighSpeedPrinter.SerialPort类的实例