
几乎每一个人在他的学生时代就已经开始了对于Java的使用过程, 我们始终都在持续地学习Java知识, 然而在Java的学习过程中总会存在着一些概念被表达得不够清晰明确的现象存在, 不论是在初级程序员层面还是在高级程序员层面都是能够观察到这种现象的, 因此, 撰写这篇文章的主要目的就是为了把这些概念给弄清楚明白。当你把这本文读完, 你能够对相关的这些概念进行更加深入的了解, 同时也能够将所有那些模糊不清的灰色区域进行完全清楚的弄明白。在这本书里面, 我们会针对匿名内联类、多线程操作、同步机制以及序列化问题进行详细的讨论。匿名类Java里的匿名类挺像那种局部类的, 又或者说有点像内联类, 区别就在于它没有具体的名字。咱们能够借助匿名类这种机制来干的事儿是什么? 就是可以一边把类给定义出来, 一边就把它实例化了。那么, 什么时候才适合去用这种方式? 条件只有一个, 那就是这个局部类在整个程序里只会被用到一次, 只有在这种情况之下, 才应该这样去做。匿名类的构造函数不能由用户去显式地明确定义, 而每一类这样的匿名类在背后都会被自动地生成一个没有名字的隐式构造函数的。创建匿名类这两种方法是存在的, 接下来我们将看到具体是哪一些。在扩展已经有的类的时候, 这个类既可以是抽象类, 也可以是具体的类, 并且同时还要去创建接口。如果要搞清楚代码, 最核心的途径就是去读, 因此在当下这一步, 我们的操作重点自然就是先看一下这堆代码到底是什么模样。匿名类能够在代码块里进行创建, 这些代码块既可以是普通类的内部, 也可以是函数的部分。或许你已经了解情况了, 匿名类的生成方式不止一种, 它既能够通过实现指定的接口来完成搭建, 也能够通过继续抽象类和具体类的形式来达成目标。在上文提到的那个例子之中, 笔者首先构建出了一个接口的具体形态, 紧接着, 便在类的存在范围以及名为main()的函数模块之内, 执行了针对匿名类的实际操作步骤。当然, 这个过程中的替代选项依然存在, 你完全可以选择抽象类作为基础, 亦或者是将那些处于平行状态的顶层类纳入考虑范围。它也可以是一个抽象类, 具体的实现情况可以参照下方所提供的这段程序代码。public abstract class Football{abstract void kick();}匿名类这个东西, 它不仅仅能够作为抽象类出现, 另外, 它也同样可以作为一个具体类的形式来存在。// normal or concrete classpublic class Football{ public void kick(){}}// end of class scope.如果一个类之中不存在不带参数的构造方法, 那该出现怎样的状况? 我们是否能够在一个匿名类的内部去访问那个类的成员变量, 也就是所说的类变量? 再者说, 在我们的这个匿名类里面, 是不是非得把这个类中的所有方法全部都重新实现一遍, 也就是进行重载操作不可。在创建匿名类的时候, 可以使用任何已经定义的构造方法, 并且在这过程当中, 同时也涉及到了对构造方法的参数的使用操作, 从理论上面来说, 匿名类的功能范围比较广, 不仅可以用来扩展那些属于顶层类别类, 还可以负责来实现相关的抽象类内容或者接口体系内容, 因此, 整个体系中关于访问控制方面的一系列规则都是持续有效的, 处于正常状态下的我们是可以去直接访问特定变量的值存在的, 但是如果是面对需要更改其内容的情况时, 那么就不具备访问权限能力了, 鉴于上述所提供的代码文本中确实包含了继承某个已有类这一行为动作的发生现象的存在, 由此我们可以知道对于开发人员而言完全不需要再去做将所有相关方法都重新进行重载这样一个冗杂且耗时的工作处理过程出来, 但是如果当前所讨论的对象本质上是一个纯粹的接口或者是某种形式的抽象类的话, 那么针对所有那些尚未被真正落实并实现掉的方法模块来讲就必须逐一给出完整且具体的功能性实现细节方案才行。在匿名类当中, 是没办法去定义那种叫做静态初始化方法的玩意儿也是不能去定义成员接口的。另外说一点, 虽然匿名类里面可以有静态成员变量这个东西, 但是, 这些变量必须得是常量。使用匿名类的主要目的和作用。项目结构变得更加清晰了, 因为我们经常会用到匿名类, 就是为了在需要随时更改某个类的某些方法的实现的时候, 可以不用再去往项目里添加新的 Java 文件来定义顶层类了, 这特别是在顶层类只被使用一次的情况下, 这种方法会觉得非常好用, 而且在图形界面的应用程序里, 匿名类最常见的用途就是用来创建各种事件处理器, 例如下面这个代码示例:button.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {// your handler code here}});我们构建了一个匿名的类别, 并且让这个类别去执行接口的规定。只要使用者动一下手指按下那个按钮, 这个类别里面对应的动作就会被启动。多线程在Java里面多线程这个功能是可以让好几个线程一同去执行的。要说线程是怎么回事, 它是一种特别轻快的子进程, 而且是处理工作时候最小的那个单位。大家为什么要用多线程序? 主要目的是为了让CPU的使用率能达到最大化。那为什么选多线程而不是用多进程来着, 就是因为线程本身更轻巧一些, 另外它可以共享同一个进程里面内存里面的那些空间。总而言之, 多线程就是用来实现那些多个任务同时进行的操作的。线程的生命周期如上图所示, 线程的生命周期主要包含5个状态。我们接下来依次对每一个状态进行解释。新建: 创建线程的实例后, 它会进入新建状态。新建状态是第一个状态。但是, 此时线程还没有准备好运行。调用start()方法之后, 状态就会从新建变成可运行状态。这意味着线程可以运行了。但实际上, 什么时候开始运行, 取决于Java线程调度器。因为调度器可能在忙着执行其他线程。线程调度器会从线程池中挑选一个线程来运行。它的挑选方式是先进先出, 也就是FIFO, 有很多场景会让线程进入等待状态。例如, 线程需要等待I/O操作, 或者等待网络连接都会导致这种情况。并且, 拥有高优先级的线程, 可以改变当前正在运行的线程的状态。当线程调用wait方法时, 它也会进入等待状态。在其他线程执行通知动作后, 它就会重新回到运行状态。当start方法结束的时候, 创建的线程会进入就绪状态。为什么使用多线程使用线程可以让Java应用程序同时去做多件事情, 这样一来, 运行速度就得到了加快。用技术术语来说, 线程可以帮你在Java程序中实现并行操作。因为现代的CPU非常快, 还可能包含多个核心, 所以如果只有一个线程的话, 就没法去使用所有的核心了。需要记住的要点创建线程的办法, 主要就是两个种类:扩展类实现接口咱们可以通过把类进行扩展的方式, 来创建这个线程。去创建一个扩展类的类。这个类应该要重载类里面的.run()方法。线程会在run()这个方法里头开始它的生命周期。接下来, 我们去创建新类的对象, 然后调用.start()方法, 以此开始执行那个线程。在对象当中, .start()会去调用.run()。也可以通过进行接口的调用这种方式来完成对相应的类的创建。下面的代码创建出了一个类, 该类实现了java.lang.接口, 并且把run()方法进行了重载的操作, 然后我们把这个对象给实例化出来, 去调用这个对象的start()方法。类与接口同步所谓同步, 它指的就是多线程的那种同步情况。在那个代码块的同一时刻之下, 它是只能被一个线程来执行的这件事。在Java里面呢, 同步其实个是很重要的概念的, 这原因就在于Java它是一个多线程的语言, 所以多个线程可以并行执行。那么, 在多线程的这个环境之中的时候, 对于Java对象的这种同步, 或者说也是对Java类的的这种同步, 那是非常重要的。大家都会问为什么要进行同步处理这件事。如果代码在多线程环境下执行, 那么在多个线程中共享的对象之间需要同步。同步的目的是为了避免破坏状态。这样做还可以避免造成任何不可预料的行为。在去深入理解同步的这个概念之前, 大家先来搞清楚这个问题。class Table {void printTable(int n) {//method not synchronizedfor (int i 1; i 5; i) {System.out.print(n * i );try {Thread.sleep(400);} catch (Exception e) {System.out.println(e);}}}}class MyThread1 extends Thread {Table t;MyThread1(Table t) {this.t t;}public void run() {t.printTable(5);}}class MyThread2 extends Thread {Table t;MyThread2(Table t) {this.t t;}public void run() {t.printTable(100);}}class TestSynchronization1 {public static void main(String args[]) {Table obj new Table();//only one objectMyThread1 t1 new MyThread1(obj);MyThread2 t2 new MyThread2(obj);t1.start();t2.start();}}当你把这段代码运行起来之后, 你就应该会观察到输出结果是非常不稳定的, 这个状况出现的原因是因为缺乏了同步机制的支持。接下来我们一起把视线转移到程序的输出部分, 仔细地查看一下具体的表现情况。输出100 5 200 10 300 15 20 400 500 25给那个括号所代表的()方法, 加上相应的同步机制或者锁之类的东西之后, 那么这个方法在执行结束之前是不会让其他的线程进入来进行操作的, 这样的话下面的输出结果就变得非常稳定了。输出5 10 15 20 25 100 200 300 400 500就像我们前面提到的那样, 在Java这玩意儿里头, 类的对象同样也是可以进行同步操作的。注意, 我们并非在任何情况下都必须对整个方法进行同步。某些时候, 将同步的范围限制在方法内部的一个较小片段中, 可能是更为恰当的取舍。借助Java语言的特性, 开发者能够针对特定的代码段执行这一同步操作。序列化Java中的序列化是一种机制, 它能够将对象的状态写入到字节流中。与之相反的操作叫做反序列化, 这个操作就是把字节流转换成对象。所谓的序列化和反序列化, 这个操作的整个过程其实是跟具体的平台没关系的, 也就能这么说, 当你在某一个特定的平台上把一个对象进行序列化的时候, 那么日后是有可能在另一个不一样的平台上对这个对象实施反序列化操作的。当执行序列化操作的时候, 系统会去调用括号里面的那个方法, 而在进行反序列化的操作的过程中, 系统则是要去调用类里面的那个特定的方法。在下边这张图中, 会把那个叫做Java的对象转成字节流, 然后放到各种各样的存储器里头去存着, 这个事儿有一个专门的名词, 就叫作序列化。而在图的右边呢, 则是反过来的动作, 是把存在内存里面的那堆字节流再变回到Java对象的样子, 这个过程大家习惯叫它是反序列化。为什么要进行序列化这个处理呢?显然, 创建的Java类在程序执行结束或中止之后, 对象就不存在了, 为了防止这一现象发生, Java提供了序列化功能, 借助这一功能, 能够将对象保存下来, 同时也能够把状态进行持久化, 这样便可以让对象在稍后时刻使用, 或者可以在其他平台上得以应用。下面的代码部分, 对于这一整个操作流程的展示, 起到了一个演示的作用。输出Serialized data is saved in Employee.ser file.输出Serialized data is restored from Employee.ser fileName of employee is : AmanSalary of employee is : 0需要记住的重点如果一个父类已经实现了接口, 那么它的子类就不需要再实现这个接口了, 但是反过来并不是这样想的, 这是不完全成立的。在对象进行序列化的时候, 只有非静态的数据成员是可以保留下来的。如果是静态数据成员或者是临时的数据成员, 它们在序列化这个过程里面是不会被保存下来的。因此, 如果某人不想让某个非静态的数据成员被保存下去的话, 他就可以把它设置为特定的状态。在进行反序列化的时候, 程序是不会去调用那个对象的构造函数的。与当前的对象有相关联的对象, 是必须实现接口的。总结1、一开始, 我们给出了匿名类的解释, 并且说明了它有什么用途, 还有具体的使用方法是什么。2、其次, 我们对Java里面的多线程技术进行了讨论, 并且也探讨了线程所经历的生命周期阶段, 还有线程在实际应用场景里的具体使用情况。3、让那一个线程进入同步的那个方法或者那个代码块去访问资源, 这事情是只允许的, 其他的那些线程呢, 都必须在队列里面等待。4、所谓的序列化这个过程, 它其实就是把对象的那些状态给存储下来, 这样, 是为了以后能够拿出来继续使用。