Java 枚举

枚举enum可以将一组具名的值得有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能。

Java 泛型

一般的类和方法,只能使用具体的类型,如果要编写可以应用于多种类型的代码,那么这种刻板的限制对代码的限制就会很大。

在面向对象编程语言中,多态算是一种泛化机制。可以将方法的参数类型设为基类,那么该方法就可以接受从这个基类导出的任何类作为参数。但程序还是会受到继承的限制,比如java中就是单继承体系。如果将方法的参数设为一个接口,那么限制会松很多,任何实现了该接口的类都能满足该方法,包括暂时那些还不存在的类。

但有时即便使用了接口,对程序的约束还是太强。因为一旦指明了接口,它就要求你的代码必须使用特定的接口。而我们希望能编写更通用的代码,能够应用于”某种不具体的类型”,而不是一个具体的接口或者类。

泛型实现了”参数化类型”的概念,使代码可以应用于多种类型。其最初的目的是希望类或方法能够具备最广泛的表达能力,通过解耦类或方法与所使用的类型之间的约束。 只是java中的泛型并没有这样高的追求,它的目的只是用来告诉编译器类或方法希望使用的参数类型,以便编译器能够确保编译时参数都是期望的类型。实际上在编译之后参数的类型信息都会被擦除成边界类型,这样保证在运行时不会出现类型错误。

Java Exception

发现错误的理想时机是在编译阶段,即在运行程序之前。然而,编译期间并不能找出所有的错误,有些问题只能在运行期间解决。那么,希望通过某种方式,让错误源能够传递给适当的接收者,该接收者知道如何正确地处理这个问题,java中异常处理的一个重要目标就是把错误处理的代码与错误发生的位置相分离

另外,java的主要目标之一就是创建供他人使用的程序构件,要想创建健壮的系统,其每一个构件都必须是健壮的。可以通过异常建立供统一的错误报告模型,使得构件能够与客户端代码可靠地沟通,最终目的在于通过少数代码来简化大型、可靠程序的生成,并且通过这种方式可以使你更加自信,即程序中没有未处理的错误。

Java String

String是Java中使用最频繁的对象之一,其本质上是维护了一个char或byte数组,并提供了基于这个数组的一些操作

《Java并发编程实战》 Java内存模型

假设一个线程为变量赋值var = 3,那么内存模型需要解决一个问题:在什么条件下,读取var的线程能看到这个值为3

这看上去理所当然,但如果缺少内存同步,那么将有许多因素使得线程无法立即看到,甚至永远看不到另一个线程的操作结果:

  • 在编译器中生成的指令顺序,可以与源代码中的顺序不同,此外编译器还会将变量保存在寄存器而不是内存中;
  • 处理器可以采用乱序或并行等方式来执行指令;
  • 缓存可能会改变将写入变量提交到内存的次序;
  • 而且保存在处理器本地缓存中的值,对于其他处理器是不可见的;

这些因素都会使得一个线程无法看到变量的最新值,并且会导致其他线程中的内存操作看起来似乎在乱序执行。

Jvm规定了一组最小保证,这组保证规定了对变量的写入操作将在何时对于其他线程可见。Jvm在设计时就在可预测性和程序的易于开发性之间进行了权衡,从而在各种主流的处理器体系架构上都能实现高性能的Jvm。Java语言规范要求Jvm在线程中维护一种类似串行的语义:只要程序的最终结果与严格串行环境中执行的结果相同,那么上面所有的操作都是允许的

这确实是一件好事,因为计算机在性能上的提升很大程度要归功于这些重排序措施。在单线程环境中,我们无法看到所有这些底层技术,它们除了提高程序的执行速度外,不会产生其他影响。而在多线程环境中,要维护程序的串行性将导致很大的性能开销。对于并发应用程序中的线程来说,它们在大部分时间里都执行各自的任务,因此,在线程之间的协调操作只会降低应用程序的运行速度,而不会带来任何好处。只有当多个线程要共享数据时,才必须协调它们之间的操作,并且Jvm依赖程序也是通过同步操作来找出这些协调操作将在何时发生。

《Java并发编程实战》 非阻塞的同步

非阻塞算法可以使多个线程在竞争共享的数据时不发生阻塞,因此它能在粒度更细的层次上进行协调,并且极大地减少调度开销。在基于锁的算法中,如果一个线程在休眠或者自旋时持有锁,那么其他线程都无法执行下去,而非阻塞算法则不会受到单个线程失败的影响。