java编程思想第四版第十章总结
1. 内部类的特性
- 他允许你把一些逻辑相关的类组织在一起。
2. 使用.this
- 如果你需要在内部类中堆外部类进行应用,可以使用外部类的名字后面加.this。下面展示了如何使用 .this
package net.mindview.innerclasses; public class DotThis { void f(){ System.out.println("DotThis.f()"); } public class Inner { public DotThis outer() { System.out.println(DotThis.this); return DotThis.this; } } public Inner inner(){ return new Inner(); } public static void main(String[] args) { DotThis dt = new DotThis(); DotThis.Inner di = dt.inner(); di.outer().f(); } }
3.使用.new
- 如果想要创建某个外部类的内部类,可以使用外部类对象.new 内部类:
- 如果想new一个内部类, 不能使用外部类.new 内部类。必须使用外部类的对象来创建内部类的对象。 用法如下:
package net.mindview.innerclasses; public class DotNew { public class Inner { } public static void main(String[] args) { DotNew dn = new DotNew(); DotNew.Inner di = dn.new Inner(); } }
4. 方法的内部类
- 这里只说两点:
- 方法的内部类有效作用域是在方法内,方法外部可以调用
- 方法的内部类,并不是说方法被调用的时候才创建了,实际上,这个类和其他类没有什么不同,他们在使用之前,已经经过编译了.
package net.mindview.innerclasses; /** * 方法内部类的作用域就在方法内,方法外不可以访问. * @author samsung * */ public class Parcel5 { public Destination destination(String s){ //在方法里定义了一个内部类 class PDestination implements Destination{ private String label; public PDestination(String label){ System.out.println(this); this.label = label; } @Override public String readLabel() { return label; } } return new PDestination(s); } public static void main(String[] args) { Parcel5 p = new Parcel5(); System.out.println(p.destination("上海").readLabel()); System.out.println(p.destination("北京").readLabel()); } /** * 注意:PDestination定义在方法里面,并不是说只有调用方法的时候,这个类才被创建. * 实际上,这个类和其他类一样,已经经过编译了. */ }
5. 定义在作用域内的内部类, 此作用域在方法的内部.
- 定义在方法作用域内部的类, 只在作用域内部有效
package net.mindview.innerclasses; 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("100"); String s = ts.getSlip(); } //作用域外不可使用 //TrackingSlip ts = new TrackingSlip("100"); } public void track(){ internalTracking(true); } public static void main(String[] args) { Parcel6 p = new Parcel6(); p.track(); } }
6.匿名内部类
- 默认构造器匿名内部类
package net.mindview.innerclasses; public class Parcel7 { public Contents contents(){ //定义了一个匿名内部类.将返回值和创建类放在了一起 return new Contents(){ private int i = 11; @Override public int value() { return i; } }; } public static void main(String[] args) { Parcel7 p = new Parcel7(); Contents c = p.contents(); System.out.println(c.value()); } }
- 代参数构造器的匿名内部类
package net.mindview.innerclasses; public class Wrapping { private int i; public Wrapping(int x){ this.i = x; } public int value(){ return i; } }
package net.mindview.innerclasses; public class Parcel8 { public Wrapping wrapping(int x){ return new Wrapping(x){ @Override public int value(){ return super.value()*47; } }; } public static void main(String[] args) { Parcel8 p = new Parcel8(); Wrapping w = p.wrapping(20); System.out.println(w.value()); } }
这里需要注意的是, 虽然Wrapping是一个导出类, 却依然被当成了一个接口来使用.
- 匿名内部类中使用外部对象, 这外部的这个对象必须是final的
package net.mindview.innerclasses; public class Parcel9 { public Destination destination(final String x){ final String m = null; //匿名内部类 return new Destination(){ //在内部类中使用到了外部的对象 private String label = m; private String abc = x; @Override public String readLabel() { return label; } }; } public static void main(String[] args) { Parcel9 p = new Parcel9(); System.out.println(p.destination("20").readLabel()); } /** * 定义一个匿名内部类, 如果希望在匿名内部类中使用外部的对象, * 那么编译器要求外部类的这个参数必须是final的. 如果你没有将这个类定义为final * 编译器会报错 */ }
- 在匿名内部类中使用类似构造器的行为. 我们知道匿名内部类没有类名, 因此他不可能有命名构造器. 但通过实例初始化可,就鞥够达到为匿名内部类创建一个构造器的效果
package net.mindview.innerclasses; abstract class Base{ public Base(int i){ System.out.println("Base构造器, i=" + i); } public abstract void f(); } public class AnonymousConstructor { /** * 此处的i不要求是final的,因为这个i只是传递给了匿名 * 变量的构造器,并没有在匿名内部类内部使用. */ public static Base getBase(int i){ return new Base(i){ { System.out.println("这里可以类似构造器进行初始化"); } @Override public void f() { System.out.println("匿名函数f()"); } }; } public static void main(String[] args) { AnonymousConstructor amc = new AnonymousConstructor(); amc.getBase(100).f(); } }
7. 再谈工厂设计模式.
再上一章中说了工厂设计模式. 本书中的案例是对象工厂设计模式. 来看看是怎么写的
package net.mindview.innerclasses.factory.MethodFactory; /** * 服务类 */ interface Service{ void method1(); void method2(); } /** * 工厂类 */ interface ServiceFactory { Service getService(); } class Implementation1 implements Service{ @Override public void method1() { System.out.println("Implementation1 method1"); } @Override public void method2() { System.out.println("Implementation1 method1"); } } class Implementation2 implements Service{ @Override public void method1() { System.out.println("Implementation2 method1"); } @Override public void method2() { System.out.println("Implementation2 method1"); } } class ImplementationFactory1 implements ServiceFactory{ @Override public Service getService() { // TODO Auto-generated method stub return new Implementation1(); } } class ImplementationFactory2 implements ServiceFactory{ @Override public Service getService() { // TODO Auto-generated method stub return new Implementation2(); } } public class Factories { public static void serviceSustomer(ServiceFactory factory){ factory.getService().method1(); factory.getService().method2(); } public static void main(String[] args) { serviceSustomer(new ImplementationFactory1()); serviceSustomer(new ImplementationFactory2()); } }
我们还可以将这种方式以内部类的方式来实现
package net.mindview.innerclasses.factory.methodFactoryInnerClass; /** * 服务类 */ interface Service{ void method1(); void method2(); } /** * 工厂类 */ interface ServiceFactory { Service getService(); } /** * 每一种服务,提供一种工厂. 这种工厂专门创建这种服务. */ class Implementation1 implements Service{ private Implementation1(){} @Override public void method1() { System.out.println("Implementation1 method1"); } @Override public void method2() { System.out.println("Implementation1 method1"); } //让工厂在内部实现 public static ServiceFactory factory = new ServiceFactory(){ @Override public Service getService() { return new Implementation1(); } }; } class Implementation2 implements Service{ @Override public void method1() { System.out.println("Implementation2 method1"); } @Override public void method2() { System.out.println("Implementation2 method1"); } //让工厂在内部实现 public static ServiceFactory factory = new ServiceFactory(){ @Override public Service getService() { return new Implementation2(); } }; } public class Factories { public static void serviceSustomer(ServiceFactory factory){ factory.getService().method1(); factory.getService().method2(); } public static void main(String[] args) { serviceSustomer(Implementation1.factory); serviceSustomer(Implementation2.factory); } }
我的理解是: 第一种工厂的含义是: 我现在需要一种服务, 然后我找到对应的工厂, 为我提供服务. 工厂再去找对应这种服务的实体.
而第二种方式呢, 我现在需要服务. 直接就去找这种服务对应的工厂就可以了. 也就是工厂内置了. 就像大公司下有多个子公司, 每个子公司都有自己的工厂.我要那种类型的东西,他就自己给生产了
8. 嵌套类
如果内部类对象预期外围类对象之间不需要有联系, 那么可以将内部类声明为static的。这种累通常称为嵌套类。要想理解static定义的内部类的含义,就必须记住,普通的内部类对象隐式地保存了一个引用,指向创建他的外围类对象。然而,当内部类是static的时候, 就不是这样了。嵌套类意味着:
- 要创建嵌套类的对象, 并不需要外围类的对象。
- 不能从嵌套类的对象中访问非静态的对象
- 普通的内部类不能有static数据和static字段,也不能包含嵌套类,但是嵌套类可以有这些东西
package net.mindview.innerclasses; public class Parcel11 { //ParcelContent被定义为static的,所以是一个嵌套类 private static class ParcelContent implements Contents { int i = 11; @Override public int value() { return i; } } //ParcelDestination 是一个嵌套类. 被定义为static的.所以,它内部可以的有static的成员和方法 private static class ParcelDestination implements Destination { private String label; private ParcelDestination(String label){ this.label = label; } @Override public String readLabel() { return label; } public static void f(){ System.out.println(AnotherLabel.x); //b()方法是访问不到的 //AnotherLabel.b(); } static int x = 10; //他是嵌套在嵌套类内部的嵌套类. static class AnotherLabel{ //内部定义了两个和外部一样的成员方法, 竟然不冲突 public static void f(){ System.out.println("这时静态类的静态方法"); } static int x = 10; //嵌套类中的非静态方法不能被外部访问到. 所以这个方法没有任何意义 public void b(){ System.out.println("这时静态类中的静态方法b()"); } } } public static Contents getContents(){ return new ParcelContent(); } public static Destination getDestination(String s){ return new ParcelDestination(s); } public static void main(String[] args) { System.out.println(getContents().value()); System.out.println(getDestination("北京").readLabel()); //嵌套类中,不能访问非静态方法 //ParcelDestination.readLabel(); //但是可以方法静态方法 ParcelDestination.f(); //嵌套类的使用方式是,类似于静态方法. 将其作为静态方法来使用. ParcelDestination.AnotherLabel.x=1; System.out.println(ParcelDestination.AnotherLabel.x); ParcelDestination.AnotherLabel.f(); //下面这样写是不对的 //ParcelDestination.AnotherLabel.b(); } }
观看上面说的文字,会有些难以理解,所以, 将这段代码敲一遍,就理解什么意思了。动手很重要啊
9. 接口内部的类
- 首先,接口里不能放置任何代码, 但是嵌套类可以.
- 你放到接口中的任何类都自动式public static的.
- 你可以在内部类中实现外围类的接口. 示例如下:
package net.mindview.innerclasses; /** * 定义在接口内部的类 */ public interface ClassInInterface { void howdy(); //这里static必须是显示标记出来的,否则这个类将不能运行 static class Test implements ClassInInterface { @Override public void howdy() { System.out.println("Howdy!"); } public static void main(String[] args) { Test t = new Test(); t.howdy(); } } }
注意, 如果想运行main方法, 这里的嵌套类必须是static的.
- 如果想创建某些公共代码, 使得他们可以被某个接口的所有实现类所共用, 那么使用接口内部的嵌套类会显得很方便.
- 例如: 我们可以在每个类中写一个mian方法用来测试这个类, 这样做有一个缺点, 那就是要写好多遍,而且, 必须通过编译器的编译, 我们可以使用嵌套类改善
package net.mindview.innerclasses; public class TestBed { public void f(){ System.out.println("f()"); } static class Testers{ public static void main(String[] args) { TestBed t = new TestBedTest(); t.f(); } } }
再说的白话一点,就是在接口中定义一个这样的嵌套类. 然后定义mian方法, 在main方法中使用嵌套类. 当有一个新的对象继承了这个类的时候, 就在这个类中的main方法进行测试就好了. 这样的好处是, 当我打包发布到正式环境的时候, 我想删除所有的main方法,因为他们的存在也会被编译器编译, 降低效率. 如果只有一个接口的嵌套类中定义的main方法,那么删起来就方便很多了。不明白的话,在看下面这个例子,就懂了
package net.mindview.innerclasses; /** * 定义在接口内部的类 */ public interface ClassInInterface { void howdy(); //这里static必须是显示标记出来的,否则这个类将不能运行 static class Test implements ClassInInterface { @Override public void howdy() { System.out.println("Howdy!"); } public static void main(String[] args) { //测试第一个实现了接口的类 ClassInInterface t = new Test(); t.howdy(); //测试第二个实现了接口的类 ClassInInterface t1 = new ClassInInterfaceTest(); t1.howdy(); } } }
package net.mindview.innerclasses; public class ClassInInterfaceTest implements ClassInInterface{ @Override public void howdy() { System.out.println("hhhh"); } }
- 接口中嵌套类如何创建实例化对象。 参考习题20
package net.mindview.innerclasses.test20; interface InnerInInterface{ static class Inner{ public Inner(){ System.out.println("嵌套类构造方法"); } } } public class Test20 { public static void main(String[] args) { //直接使用 new 外围类.嵌套类 InnerInInterface.Inner inner = new InnerInInterface.Inner(); } }
10. 从多层嵌套类中访问外部类的成员
注意下面这个例子是如何创建内部类的。
package net.mindview.innerclasses; /** * 多层嵌套类访问外部成员 */ class A{ private void f(){}; class B{ private void b(){}; class C { void c(){ f(); b(); }; } } } public class MutliNestingAccess { public static void main(String[] args) { A a = new A(); A.B b = a.new B(); A.B.C c = b.new C(); c.c(); } }
iooo
![](https://img2020.cnblogs.com/blog/1187916/202106/1187916-20210627082053046-596566365.jpg)