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的时候, 就不是这样了。嵌套类意味着:


  1. 要创建嵌套类的对象, 并不需要外围类的对象。


  1. 不能从嵌套类的对象中访问非静态的对象


  1. 普通的内部类不能有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

相关文章
|
2月前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
2月前
|
安全 Java UED
深入浅出Java多线程编程
【10月更文挑战第40天】在Java的世界中,多线程是提升应用性能和响应能力的关键。本文将通过浅显易懂的方式介绍Java中的多线程编程,从基础概念到高级特性,再到实际应用案例,带你一步步深入了解如何在Java中高效地使用多线程。文章不仅涵盖了理论知识,还提供了实用的代码示例,帮助你在实际开发中更好地应用多线程技术。
59 5
|
1月前
|
Java 程序员
Java编程中的异常处理:从基础到高级
在Java的世界中,异常处理是代码健壮性的守护神。本文将带你从异常的基本概念出发,逐步深入到高级用法,探索如何优雅地处理程序中的错误和异常情况。通过实际案例,我们将一起学习如何编写更可靠、更易于维护的Java代码。准备好了吗?让我们一起踏上这段旅程,解锁Java异常处理的秘密!
|
14天前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
Java 并发编程——volatile 关键字解析
|
18天前
|
算法 Java 调度
java并发编程中Monitor里的waitSet和EntryList都是做什么的
在Java并发编程中,Monitor内部包含两个重要队列:等待集(Wait Set)和入口列表(Entry List)。Wait Set用于线程的条件等待和协作,线程调用`wait()`后进入此集合,通过`notify()`或`notifyAll()`唤醒。Entry List则管理锁的竞争,未能获取锁的线程在此排队,等待锁释放后重新竞争。理解两者区别有助于设计高效的多线程程序。 - **Wait Set**:线程调用`wait()`后进入,等待条件满足被唤醒,需重新竞争锁。 - **Entry List**:多个线程竞争锁时,未获锁的线程在此排队,等待锁释放后获取锁继续执行。
52 12
|
14天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
97 2
|
2月前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
2月前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
1月前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
1月前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
51 3