第一课: 数组与内存控制
1、数组的初始化有两种方式 静态和动态
2、Java的数组是静态的 JS的数组是动态的
3、java数组变量是引用型变量,并不是数组对象本身,只要让数组变量指向有效的数组对象即可。
4、所有局部变量都是放在栈内存中、不管是基本变量还是引用类型变量
都存在在各自的栈区,但引用类型变量所引用的对象(数组和普通的java对象)
则总是存储在堆内存之中。
5、引用类型变量只是栈内存中变量的本身,何时变为引用的实际对象?
引用变量本质上只是一个指针,只要通过引用变量访问属性,或者引用
变量来调用方法,则引用变量会由引用对象所替代
第二课:对象与内存控制
1、大量的创建对象,让系统分配内存有两点坏处
使得可用内存减少,降低运行的性能。
加重垃圾回收的负担,降低运行性能
2、静态先非静态 非静态先与构造器
平级的看源码顺序覆盖。
3、被final修饰的变量一旦被赋值就无法改变
4、两个变量的组合无法形成宏替换
5、对于普通局部变量而言,他们的作用域是在方法内部,当方法
执行结束也就消失了,但是内部类则可能产生闭包,闭包将
使得局部变量脱离它所在的方法存在。
第三课:常见的java集合实现细节
1、ArrayList初始长度为10
2、可以把Map集合中的Value当成Key的附属,当系统决定了key的存储位置之后
Value随之保存在那里即可.
3、put的过程是首先根据key的hashCode()返回值决定Entry的存储位置
如果两个Entry的key的返回值相同,那他们存储位置相同,如果两个
Entry的key通过equals返回为true那么key不会被覆盖,新添加
的Entry的Value覆盖原来Entry中的Value
如果equals比较返回为false,新添加的Entry将与集合中原来的Entry
形成Entry链而且新添加的Entry位于Entry链的头部
3、当size++>=threshold时,HashMap会自动调用resize方法扩充HashMap的
容量。每扩充一次,HashMap的容量就增大一倍。默认HashMap的初始容量为
16负载因子为0.75 threshold=16*0.75
4、无论何时 HashMap的每一个桶只存储一个元素Entry 由于Entry对象可以
包含一个引用变量用于指向下一个Entry,因此可能出现:HashMap的bucket
只有一个Entry但这个Entry指向另一个Entry这样就形成了Entry链
5、负载因子增加空间利用率变大 时间效率变小
负载因子减少空间利用率小 时间效率增加
6、HashSet底层完全依赖于HashMap 只不过value是用静态的new Object();
有一点不同 当key 完全相同(hashCode和equals)不会覆盖
7、TreeSet底层完全仿造HashSet是使用了TreeMap
8、TreeMap采用了一种红黑树的排序二叉树来保存Map中每一个Entry
9、ThreeMap比较耗能,因为底层是用一颗红黑树来保存集合中的Entry
添加、取出元素的性能都比HashMap低,但优势在于总能按key根据指定排序
规则保持有序状态,TreeSet中的所有元素总是根据指定排序规则保持有序状态
10、TreeMap这个工具类从内部结构看就是一颗红黑树,而TreeMap的每个Entry
就是该红黑树的一个节点。
11、ArrayList底层采用数组来保存每个集合元素 LinkedList则是一种链表存储的
线性表,本质是一种双向链表
12、对于ArrayList集合而言,当程序向ArrayList中添加、删除集合元素时,ArrayList
底层都与需要对数组进行‘整体搬家’因此性能非常差
13、ArrayList的get方法来取出ArrayList集合中的元素时 性能和数组几乎相同
非常快
14、LinkedList本质上就是一个双向链表 因此它使用内部类来保存每个集合元素
15、LinkedList获取指定索引处的元素是比较麻烦的,开销比较大。
16、从get角度来说ArrayList的性能要比LinkedList好很多
17、add(int index, Object obj)向List集合添加元素ArrayList需要整体搬家(写的时候)
18、当添加的元素超过原来list数组长度的时候 就建立新的数组长度1.5倍于
原来数组长度的新数组 原来数组需要垃圾回收器回收
19、LinkedList主要开销在于add时的entry(index)需要不断搜索过去 直到找到index
处的元素,然后再在该元素之前插入新元素。
20、总体来说ArrayList的性能要高于LinkedList的性能
但是若程序希望不断调用add、remove时需要考虑LinkedList
第四课:Java内存回收
1、Java内存管理包括内存分配创建Java对象和回收Java对象。这两方面都是
JVM自动完成。
2、强引用:程序创建一个对象,并把这个对象赋给一个引用变量。这个引用变量就是
强引用,当一个对象被一个或一个以上的强引用变量所引用时,它处于可达
状态,它不可能被系统垃圾回收机制回收
3、软引用需要通过SoftReference类来实现,对于软引用而言当系统内存空间
足够时,它不会被系统回收,程序可以使用该对象;当系统内存空间不足时,
系统将会回收它。
SoftReference
people = new SoftReference[1000];
4、创建100000个Person会导致内存不足而中止,而SoftReference就会很好的解决
这一问题。这就是软引用的原因所在。
5、如果存在无用的内存没有回收回来,那就是内存泄露.
6、Object obj = new Object(); obj = null; //执行耗时 耗费内存的操作。
7、尽量少用静态变量.
8、避免在经常调用的方法、循环中创建Java对象.
9、缓存经常使用的对象.
10.考虑使用SoftReference 当程序需要创建长度很长的数组时,可以保证项目
不会宕机。但是需要做出判空操作。
第五课: 表达式中的陷阱
1、String Integer 使用直接量 不需要new
2、StringBuffer是线程安全的
3、字符串底层实际上采用一个字符串数组来保存该字符串所包含
4、string使用compareTo比较
5、byte-short|char-int-long-float-double
6、String strArr[] = str.split("\\.");
7、启动线程用start()方法 不是用run方法.
8、静态类的同步方法(非静态类锁是类对象 静态类锁是类本身)
9、多线程的情景下应该使用线程安全的类。
第六课:流程控制的陷阱
第七课:面向对象的陷阱
1、instance of 可以保证不报NPE
2、创建Java对象可以 new 反序列化 反射 clone等方法
3、构造器中不能使用递归调用.
4、内部类的作用其实更多的是为了操作多继承这一功能。
5、被static关键字修饰的成员(Field 方法 内部类 初始化快 内部类枚举)
都属于类本身 而不是单个的Java对象 具体到静态方法也是 静态方法属于
类,而不是属于Java对象.
6、尽量使用静态内部类,而不是非静态内部类。对于静态内部类来说,外部类
相当于它的一个包,因此静态内部类的用法简单很多,限制少很多。
7、静态内部类不能访问外部类的非静态成员.
第八课:异常的陷阱
1、finally{if(null != oos){try{oos.close}catch(Exception ex){ex.print()}}}
1、保证关闭操作总是会被执行
2、关闭每个资源之前保证不为null
3、单独使用try catch保证关闭资源时引发的异常不会影响到其他资源的关闭
2、当程序执行try catch遇到throw 语句时 throw会导致该方法立即结束,系统
执行throw语句时不会立即抛出异常而是去找寻finally 如果 finally有立即
结束的方法 比如return 那么就立即结束。否则继续抛出之前没有执行的异常。
3、不要用catch代替流程控制
4、子类不能抛出比父类范围更多的异常
第九课: 线性表
1、线性表是数组的加强。
长度是动态的;可以插入元素;可以删除元素;可以搜索指定位置的元素
可以清空所有元素;
第十课:栈和队列
1、栈后进先出 Stack Dqueue
第11课:二叉树