基础篇
(1)== vs equals()
==是操作符(可比较primitive),equals()是方法(继承自java.lang.Object,比较对象)
==比较对象在heap中的引用或内存中的位置(new一个对象会产生一个新的对象),equals()比较对象的状态和内容
==行为不可复写(Java不支持操作符重载),equals()可以覆写改变其比较行为
集合类一般使用compareTo()来比较对象
包装类用==比较时会先转成primitive后比较,所以要避免NPE;而且比较的是引用
Integer包装类对于-128到127有cache,所以结果会是true
(2)String literal vs new String()
new String("Java")会在heap中创建两个对象,一个String对象一个String常量。
literal会从String常量池中返回一个存在的对象(如果池中没有会默认创建一个自动调用intern()方法放入池中)
也可以自己调用intern()方法把任意对象放入池中:
String s1 = "Java";
String s2 = new String("Java");
s2 = s2.intern(); // 这里s1==s2为true
(3)String vs StringBuffer vs StringBuilder
String是immutable/final,StringBuffer是mutable
String通过+操作符连接,StringBuffer使用append()
String和StringBuffer不能强制转换,需要StringBuffer的toString()
StringBuffer同步且线程安全,StringBuilder不同步不线程安全
StringBuffer和StringBuilder都继承自AbstractStringBuilder
String/StringBuffer/StringBuilder内部都是用字符数组实现
StringBuffer/StringBuilder有初始容量capacity
(4)Interface vs Abstract Class
抽象类只能extend一个,接口可以implement多个
抽象类中可以定义非抽象方法,接口中不能定义非抽象方法(JDK8默认方法除外)
抽象类中即使没有抽象方法也可以标记为abstract
抽象类可以添加方法不影响子类,接口中添加方法需要修改所以它的实现类
抽象类适合代码重用,接口适合类型同一
接口没有方法实现更易于解耦
接口可以实现依赖注入
接口里的变量默认是public final
接口不可实例化,抽象类不可实例化但可以invoked
(5)Static vs Non Static class
类分为顶级类和嵌套内部类(还有特殊的匿名类)
顶级类不能被定义为static,嵌套内部类可以选择是否为static
嵌套内部类如果是static的话一般叫嵌套类,非static的叫内部类
嵌套类和内部类的创建方法不同:
Outer.Nested nested = new Outer.Nested();
Outer.Inner inner = new Outer().new Inner();
嵌套类可以被看做外部类的一个静态成员,可以在static方法中被使用
嵌套类不可以访问外部类的非static成员,内部类可以
(6)Primitive vs Reference variable
primitive变量有默认值
primitive变量存储值,reference变量存储对象在heap中的handle
primitive变量赋值是值的拷贝(互不影响),reference变量赋值是handle的拷贝(操作会影响另一方)
primitive变量使用==比较,reference变量使用equals()比较
primitive变量作为参数传递的是值,reference变量作为参数传递的是handle的拷贝
primitive变量参数的值在方法内被修改不影响原有值,reference变量参数修改handle不影响原有值但使用handle可以修改内部的值
primitive变量作为方法的返回值时返回的是值,返回reference变量时返回的是handle可以继续在方法外使用
primitive变量存储在stack,reference变量存储在heap
(7)Static vs Non Static method
static方法隶属于class,通过Class名直接调用(多用于工厂和单例),非static方法需要通过创建的对象来调用
static方法中不能访问非static变量
static方法不能被override
static方法多用于utility类
(8)transient vs volatile
transient变量不会被序列化(值是默认值)
volatile变量用于并发编程,被保存在单线程中,取值时也是从主线程中获取和当前线程栈无关(线程共享)
volatile经常用于实现单例来代替static final
transient和volatile只能用于变量不能用于方法或类
(9)throw vs throws
throw是在方法内部抛出异常,throws是在方法定义上标示该方法会抛出什么样的异常
throw一次只能抛出一个异常,throws可以通过逗号分隔标示多个异常
throw可以用于switch语句,throws只能用于方法定义处
throws只是标示给编译器用,并不会处理异常
方法内部抛出的需要checked的异常都要在方法定义处通过throws标示
不管是需要checked的或运行时异常都可以在throws标示,但运行时异常可以不标示
throws也可以只标示方法内部所有异常的父类
throw异常需要注意方法override引起的异常继承关系
(10)final vs finally vs finalize()
final用于变量/方法/类,finally用于try-catch,finalize()方法给GC调用
final变量不可修改,final方法不可override,final类不可继承
(11)Error vs Exception
常见Error:OutOfMemoryError
Error不需要try-catch即使catch了也无法解决,Exception异常catch后可做后续处理
RuntimeException表示的是程序代码的错误,Erro多为系统环境上致命错误
(12)Runtime Exception vs Checked Exception
常见Runtime异常:NullPointerException、ArrayIndexOutOfBoundException
常见Checked异常:ClassNotFoundException、IOException
Checked异常需要在调用处try-catch,Runtime异常不需要
Checked异常继承自Exception, Runtime异常继承自RuntimeException
自定义异常时需要注意标示异常是否为RuntimeException
(13)NoClassDefFoundError vs ClassNotFoundExcepiton
NoClassDefFoundError是Error不需要try-catch,ClassNotFoundException是Checked异常
NoClassDefFoundError出现在JVM或ClassLoader无法找到类(静态块初始化),ClassNotFoundException出现在程序动态加载类时
ClassNotFoundException多来自于Class.forName(),ClassLoader.findSystemClass(),ClassLoader.loadClass()
(14)Serializable vs Externalizable
Serializable是标记接口没有任何需要实现的方法,Externalizable继承自Serializable有两个需要实现的方法writeExternal()、readExternal()
Externalizable的子类JVM在序列化和反序列化对象时会调用writeExternal()、readExternal()
Serializable默认序列化所有类信息,Externalizable可以自定义序列化过程
Serializable序列化性能慢,可以通过使用transient或static
减少序列化字段来提高性能
Serializable由于字段的改变会变得不可维护
Externalizable可以处理transient变量或static变量
(15)Stack and Heap
stack存储本地变量和函数调用,heap存储对象
JVM启动可指定栈和堆得大小:stack(-Xss) heap(-Xms-Xmx)
stack空间不足时java.lang.StackOverFlowError
heap空间不足时java.lang.OutOfMemoryError: Java Heap Space
使用递归调用会让stack急剧变小
stack中的变量只能自己线程访问,stack中的对象所有线程都能访问
stack所需大小远小于heap
集合篇
(1)Enumeration vs Iterator vs ListIterator
Iterator支持在遍历集合时删除元素,Enumeration不支持
Enumeration是JDK早期的遍历集合类的方法现在很少用
Enumeration是早期的类现在不是所有集合都支持Vector支持ArrayList不支持
Enumeration是一个只读接口用来遍历获取集合中的元素
Iterator在遍历集合时不允许其他线程修改集合中的元素
ListIterator是针对List类型集合的
Enumeration和Iterator是单向的,ListIterator是双向的
Enumeration的方法:xxx.elements(); hasMoreElement(),nextElement()
Iterator的方法:xxx.iterator(); hasNext(), next(), remove()
ListIterator的方法:xxx.listIterator(); hasNext(),next(),previous(),hasPrevious(),remove(),nextIndex(),previousIndex()
(2)Collection vs Collections
Collection是集合类的顶级接口,除过Map其他大部分实现在该接口
Collections是一个utility类,提供一些静态方法来处理集合类
(3)Comparator vs Comparable
Package不一样:java.lang.Comparable,java.util.Comparator
被排序的Object需要实现Comparable,新建一个类实现Comparator接口
Comparable实现的方法:compareTo(Object obj1) 比较当前对象和参数对象
Comparator实现的方法:compare(Object obj1, Object obj2) 比较参数的两个对象
compareTo(Object o1)返回值:正数-当前对象大于o1 0-相等 负数-当前对象小于o1
compare(Object o1,Object o2)返回值:正数-o1大于o2 0-相等 负数-o1小于o2
Collections.sort(List)调用Comparable比较元素
Collections.sort(List, Comparator)调用Comparator比较元素
Comparable:对Object只能写一套比较方法
Comparator:对Object可以写多个比较方法多次排序
(4)List vs Set vs Map
List有序可重复,可存多个null元素,主要实现:ArrayList, Vector, LinkedList
Set无序不可重复,只能存一个null元素,主要实现:HashSet, TreeSet, LinkedHashSet
Map键值对,键不可重复,键只有一个null,主要实现:HashMap, LinkedHashMap, Hashtable and TreeMap
(5)Array vs ArrayList
Array固定长度,ArrayList不固定长度(后台通过数组实现)
Array创建时需要指定长度,ArrayList不需要(JDK有默认初始容量并会自动扩容)
Array不支持泛型,ArrayList支持泛型
Array长度:arr.length; ArrayList大小:list.size();
ArrayList只能存对象不能存primitive变量(自动装箱除外)
(6)ArrayList vs LinkedList
ArrayList后台通过数组实现,LinkedList通过链表实现(嵌套类存储前后节点)
LinkedList不只是实现了List还实现了Deque(FIFO)。add(),poll()
添加元素:ArrayList-O(1) LinkedList-O(1)
删除元素:ArrayList-O(n) LinkedList-O(n/2)
获取元素:ArrayList-O(1) LinkedList-O(n/2)
(7)HashSet vs TreeSet
HashSet比TreeSet性能好
HashSet后台用Hashtable实现,TreeSet后台用红黑树实现
HashSet允许null,TreeSet不允许null
HashSet使用equals()比较对象,TreeSet使用compareTo()比较对象
(8)Fail-Safe vs Fail-Fast Iterator
安全失败(fail-safe)和快速失败(fail-fast)
fail-safe Iterator:集合元素被修改时不抛出异常
fail-fast Iterator:集合元素被修改时抛出异常ConcurrentModificationException
fail-safe iterator:遍历的是集合的一个副本
fail-fast iterator:遍历的是集合自身
fail-safe:CopyOnWriteArrayList,CopyOnWriteArraySet,ConcurrentHashMap
fail-fast:HashMap,ArrayList,HashSet
线程篇
(1)wait() vs sleep() vs yield()
Object.wait(),Thread.sleep(),Thread.yield()
wait(),wait(10),wait(10, 5); sleep(10),sleep(10, 5); yield()
wait()可通过notify()唤醒
wait()会释放对象锁,sleep(),yield()不会
wait()需要在同步块或同步方法中调用
yield()使当前线程停止时间是不定的
(2)start() vs run()
start()调用时会创建一个新线程,并且执行内部的run()方法
直接调用run()方法无法创建新线程,run()方法执行在当前线程里
start()方法不能调用多次,第二次会抛出IllegalStateException
(3)Thread vs Runnable interface
扩展继承Thread后就不能再继承其他类
Runnable标示该对象是一个Task可以被执行,执行还的通过Thread
(4)Callable vs Runnable
Callable会抛出checked异常,Runnable没有
Callable能在call()方法中返回操作结果,Runnable的run()方法不行
Callable可通过泛型传入返回类型
(5)Synchronized vs Concurrent Collections
都提供线程安全
Synchronized集合:Hashtable,Vector。Collections.synchronizedMap(),Collections.synchronizedList()
Concurrent集合:ConcurrentHashMap,CopyOnWriteArrayList
Synchronized集合比Concurrent集合性能慢
Synchronized集合锁整个对象,Concurrent集合会被分成多个segments锁其中一个segment
设计篇
(1)Abstraction vs Encapsulation
Abstraction抽象:interface, abstract class
Encapsulation封裝:private, package-private, protected
(2)Overloading vs Overriding
Overload重载在编译期,Override重写在运行期
同一个类中overload方法,子类中override父类方法
可以overload静态方法,但不能override静态方法
private和final方法不能override,但可以overload
overload时需要修改方法的定义(参数表),override不需要
(3)Dependency Injection vs Factory Pattern
DI依赖注入需要第三方框架支持(比如Spring),工厂模式自己封装代码
DI松耦合设计,工厂模式耦合factory和object
DI框架替你常见管理实例,工厂通过getInstance()生产一个实例
DI更易于单体测试,更弹性灵活,但DI需要配置注入关系
(4)Singleton Pattern vs Static Class
单例提供的是Object,静态类提供的是方法
静态类性能更好
静态类方法不可override
静态类不便于测试
单例可以保持对象的状态等信息,静态类不可以
单例只在使用时加载(lazy load),静态类启动时加载
很多DI框架更容易支持单例
其他
(1)trustStore vs keyStore
trustStore存储公钥和CA,keyStore存储私钥
trustStore验证证书,keyStore提供证书
创建SSLContext:trustStore-TrustManager(决定是否连接可信),keyStore-KeyManager(决定哪些连接在SSL握手时需要发到Server认证)
JRE默认trustStore保存在$JAVA_HOME/lib/security/cacerts
-Djavax.net.ssl.trustStore -Djavax.net.ssl.keyStore
-Djavax.net.ssl.trustStorePassword -Djavax.net.ssl.keyStorePassword
(2)Type 1, 2, 3, 4 JDBC Driver
Type 1:非Java实现,最早的驱动连接Access,需要把JDBC请求转化为ODBC后链接,又叫JDBC ODBC bridge driver(性能差)
Type 2:非Java实现,JDBC直接通过native API和DB链接,需要native library比如ocijdbc11.dll
Type 3:Java Net实现,通过代理服务和DB链接,client-server-database,又叫Net protocol JDBC driver
Type 4:纯Java实现,通过native protocol直接和DB链接,驱动JAR文件中包含所有数据库的调用,又叫thin JDBC driver