Java拾遗

Java知识点繁多,如果不多加以实践会很容易忘记,这篇文章记录的是我遗忘了然后查了或者我根本不知道的知识点,会不定期更新

17.04.23 更

重读《疯狂java讲义》发现的遗忘点

  1. Lambda表达式和匿名内部类的区别:
    匿名内部类可以为所有接口,抽象类甚至普通类创建对象,而Lambda表达式只能为函数式接口创建对象;
    匿名内部类在方法实现的代码部分允许调用接口中的默认方法,而Lambda表达式不允许

  2. 方法引用和构造器引用,从形式上来说满足以下情况可用:当Lambda表达式只含有一句语句,且该语句是在调用方法。此时Lambda表达式可改为“调用者::调用方法”的形式,一般是”类名::类方法”(包括了”类名::new”,构造方法可以理解为通过类来调用)或”实例对象::实例方法”,例外是当方法调用者本身也是形参列表的一员时(例如那句语句可以是(a,b,c)->a.substring(b,c)),如果其是第一个参数,那么可改为“类名::实例方法”

  3. 枚举值实质上是所属枚举类(或其匿名子类)的实例,理解这点就可理解各种枚举类的写法,如含有构造器的枚举类,实现接口的并给不同枚举值重写不同方法的枚举类等等

  4. StringBuffer线程安全,StringBuilder线程不安全(更高效)

  5. ThreadLocalRandom是Random类在多线程环境下的线程安全版本

  6. 遍历Collection时,如果对每个元素操作只有一句可以考虑用Lambda表达式实现,调用Collection的forEach方法传入一个Consumer(一个函数式接口)实例即可

  7. 在遍历集合过程不可以调用Collection的改变集合内容的方法,否则抛出ConcurrentModificationException,如果要在遍历Collection的同时删除该Collection中元素,可以考虑用Iterator,调用其remove方法(删除上一个next()返回的元素)而不是调用集合的remove()方法

  8. 常用集合类型:HashSet基于哈希表储存,LinkedHashSet也一样,他们随机访问速度很快,但用链表来维护加入的顺序,由于有链表,遍历速度也更快,TreeSet使用红黑树维护顺序,性能比HashSet低一点;List推荐用ArrayList; Queue子接口Deque,其实现类ArrayDeque即可当栈使用也可当队列使用;而LinkedList实现了List和Deque,所以可以当List使用,也可当栈和队列使用;Map常用实现类:HashMap,LinkedHashMap,TreeMap,Properties,

  9. 不同实现的集合性能分析:基于数组的集合:随机访问性能较好,对于他们使用随机访问方法(get)来遍历较好;基于链表:插入删除操作速度较快,由于是基于链表实现,对于他们使用迭代器来遍历较好

  10. 使用Collections的synchronizedCollection,synchronizedSet,synchronizedList,synchronizedMap来获得线程安全的集合

  11. 创建对象的方式:new,反射(获得Class或者进一步获得Constructor后调用clazz.newInstance()或者constructor.newInstance()),反序列化,clone

  12. 反射操作:先获得Class对象,再clazz.getDeclaredXXX()获得无视权限的成员变量,方法或构造器,再调用setAccessible(true),进而可进行访问,成员变量可以getXXX()和SetXXX(),方法可以invoke(),构造器可以newInstance()

  13. 获得Class对象的方法,Class.forName(),类名.class,对象.getClass()

  14. 方法的重写要遵循“两同两小一大”规则。方法名和形参列表相同,子类抛出的异常和返回值类型应更更小或相等,访问权限应该更大

synchronize关键字细节

当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

五、以上规则对其它对象锁同样适用.

–摘录于原文,代码示例见原文

序列化机制与RMI

网上有一些很好的总结,链接如下:(如果链接失效可以到笔记中查看)

1.理解Java对象序列化
全方面覆盖序列化的基础知识

2.Java序列化的高级认识
对序列化的各个特点讲的很清晰

3.深入分析Java的序列化与反序列化介绍了部分机制的源码实现原理

4.对象序列化与RMI
介绍了RMI的原理与基本使用

5.Java RMI详解
RMI详解

6.Java RMI 框架(远程方法调用)
RMI详解

集合框架

基础;重新系统看一次《疯狂Java讲义》集合一章

网上的经验总结:

集合类操作优化经验总结

Java8时间日期处理

1.Java8使时间和日期API20例
文中错误:
示例3,LocalDate.of(2010, 01, 14);的01实际上为八进制,应该是作者笔误,直接用1就好,事实上文中其他地方就改正了这个错误。
示例6,打印出的时间16:33:33.369,369是毫秒,即10^-3秒,并非纳秒“nano seconds”
示例12,“在Java 8以前,一定要牢牢记住时区的名称”的“在Java 8以前”改为“在Java 8中,”

还有一些其他错误没有大碍,例如System.currentTimeInMillis()看得懂虽然错了但看得懂

2.Java 8新的日期和时间API

线程池的使用

1.Java线程池的分析和使用
这篇文章分析线程池的工作流程非常清楚,有源码分析
2.Java7之多线程线程池
这篇文章很有条理性,而且也有源码分析,分类型介绍了常用的线程池以及一些重要概念

PS:BlockingQuene与一般的队列不同之处在于,在队尾加入元素时如果当前元素数量达到了capacity,则会阻塞(可以指定最长阻塞时间)直到有位置加入新的元素;在队头删除元素时,如果队列为空,则会阻塞(可以指定最长阻塞时间)直到队列不为空