学习Java容易混淆的一概念

[size=medium][b]基础篇[/b][/size]
[color=blue](1)== vs equals()[/color]
==是操作符(可比较primitive),equals()是方法(继承自java.lang.Object,比较对象)
==比较对象在heap中的引用或内存中的位置(new一个对象会产生一个新的对象),equals()比较对象的状态和内容
==行为不可复写(Java不支持操作符重载),equals()可以覆写改变其比较行为
集合类一般使用compareTo()来比较对象
包装类用==比较时会先转成primitive后比较,所以要避免NPE;而且比较的是引用
Integer包装类对于-128到127有cache,所以结果会是true

[color=blue](2)String literal vs new String()[/color]
new String("Java")会在heap中创建两个对象,一个String对象一个String常量。
literal会从String常量池中返回一个存在的对象(如果池中没有会默认创建一个自动调用intern()方法放入池中)
也可以自己调用intern()方法把任意对象放入池中:
String s1 = "Java";
String s2 = new String("Java");
s2 = s2.intern(); // 这里s1==s2为true

[color=blue](3)String vs StringBuffer vs StringBuilder[/color]
String是immutable/final,StringBuffer是mutable
String通过+操作符连接,StringBuffer使用append()
String和StringBuffer不能强制转换,需要StringBuffer的toString()
StringBuffer同步且线程安全,StringBuilder不同步不线程安全
StringBuffer和StringBuilder都继承自AbstractStringBuilder
String/StringBuffer/StringBuilder内部都是用字符数组实现
StringBuffer/StringBuilder有初始容量capacity

[color=blue](4)Interface vs Abstract Class[/color]
抽象类只能extend一个,接口可以implement多个
抽象类中可以定义非抽象方法,接口中不能定义非抽象方法(JDK8默认方法除外)
抽象类中即使没有抽象方法也可以标记为abstract
抽象类可以添加方法不影响子类,接口中添加方法需要修改所以它的实现类
抽象类适合代码重用,接口适合类型同一
接口没有方法实现更易于解耦
接口可以实现依赖注入
接口里的变量默认是public final
接口不可实例化,抽象类不可实例化但可以invoked

[color=blue](5)Static vs Non Static class[/color]
类分为顶级类和嵌套内部类(还有特殊的匿名类)
顶级类不能被定义为static,嵌套内部类可以选择是否为static
嵌套内部类如果是static的话一般叫嵌套类,非static的叫内部类
嵌套类和内部类的创建方法不同:
Outer.Nested nested = new Outer.Nested();
Outer.Inner inner = new Outer().new Inner();
嵌套类可以被看做外部类的一个静态成员,可以在static方法中被使用
嵌套类不可以访问外部类的非static成员,内部类可以

[color=blue](6)Primitive vs Reference variable[/color]
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

[color=blue](7)Static vs Non Static method [/color]
static方法隶属于class,通过Class名直接调用(多用于工厂和单例),非static方法需要通过创建的对象来调用
static方法中不能访问非static变量
static方法不能被override
static方法多用于utility类

[color=blue](8)transient vs volatile [/color]
transient变量不会被序列化(值是默认值)
volatile变量用于并发编程,被保存在单线程中,取值时也是从主线程中获取和当前线程栈无关(线程共享)
volatile经常用于实现单例来代替static final
transient和volatile只能用于变量不能用于方法或类

[color=blue](9)volatile vs static[/color]
线程会缓存static变量
线程在操作static变量时是操作它们内部cache的local copy,不会影响其他线程
volatile变量只有一个main copy,各线程之间的更新会反映到其他线程

[color=blue](10)throw vs throws[/color]
throw是在方法内部抛出异常,throws是在方法定义上标示该方法会抛出什么样的异常
throw一次只能抛出一个异常,throws可以通过逗号分隔标示多个异常
throw可以用于switch语句,throws只能用于方法定义处
throws只是标示给编译器用,并不会处理异常
方法内部抛出的需要checked的异常都要在方法定义处通过throws标示
不管是需要checked的或运行时异常都可以在throws标示,但运行时异常可以不标示
throws也可以只标示方法内部所有异常的父类
throw异常需要注意方法override引起的异常继承关系

[color=blue](11)final vs finally vs finalize()[/color]
final用于变量/方法/类,finally用于try-catch,finalize()方法给GC调用
final变量不可修改,final方法不可override,final类不可继承

[color=blue](12)Error vs Exception[/color]
常见Error:OutOfMemoryError
Error不需要try-catch即使catch了也无法解决,Exception异常catch后可做后续处理
RuntimeException表示的是程序代码的错误,Erro多为系统环境上致命错误

[color=blue](13)Runtime Exception vs Checked Exception[/color]
常见Runtime异常:NullPointerException、ArrayIndexOutOfBoundException
常见Checked异常:ClassNotFoundException、IOException
Checked异常需要在调用处try-catch,Runtime异常不需要
Checked异常继承自Exception, Runtime异常继承自RuntimeException
自定义异常时需要注意标示异常是否为RuntimeException

[color=blue](14)NoClassDefFoundError vs ClassNotFoundExcepiton[/color]
NoClassDefFoundError是Error不需要try-catch,ClassNotFoundException是Checked异常
NoClassDefFoundError出现在JVM或ClassLoader无法找到类(静态块初始化),ClassNotFoundException出现在程序动态加载类时
ClassNotFoundException多来自于Class.forName(),ClassLoader.findSystemClass(),ClassLoader.loadClass()

[color=blue](15)Serializable vs Externalizable [/color]
Serializable是标记接口没有任何需要实现的方法,Externalizable继承自Serializable有两个需要实现的方法writeExternal()、readExternal()
Externalizable的子类JVM在序列化和反序列化对象时会调用writeExternal()、readExternal()
Serializable默认序列化所有类信息,Externalizable可以自定义序列化过程
Serializable序列化性能慢,可以通过使用transient或static
减少序列化字段来提高性能
Serializable由于字段的改变会变得不可维护
Externalizable可以处理transient变量或static变量

[color=blue](16)Stack and Heap[/color]
stack存储本地变量和函数调用,heap存储对象
JVM启动可指定栈和堆得大小:stack(-Xss) heap(-Xms-Xmx)
stack空间不足时java.lang.StackOverFlowError
heap空间不足时java.lang.OutOfMemoryError: Java Heap Space
使用递归调用会让stack急剧变小
stack中的变量只能自己线程访问,stack中的对象所有线程都能访问
stack所需大小远小于heap

[color=blue](17)Shallow Copy vs Deep Copy[/color]
浅拷贝:使用已知实例对新创建的实例的成员变量逐个赋值
深拷贝:不仅复制primitive变量值,还要为引用类型reference的成员变量创建新的实例
浅拷贝时,拷贝的对象和元对象不是100%隔离
浅拷贝时,任何修改元对象中引用类型变量的操作会反映到拷贝对象中,反之也是
默认clone()方法提供的是浅拷贝shallow copy,深拷贝需要override默认clone()方法
如果对象只有primitive变量,浅拷贝足够

[color=blue](18)<? super T> vs <? extends T> [/color]
PECS: "Producer Extends, Consumer Super".
<? extends T> 表示类型的上界,可用于的返回类型限定,不能用于参数类型限定。
<? super T> 表示类型下界,表示参数化类型是此类型的父类型。可用于参数类型限定,不能用于返回类型限定。
List<? extends Number> foo1 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo2 = new ArrayList<Double>(); // Double extends Number
Number a1 = foo1.get(0);
Number a2 = foo2.get(0);
foo1.add(1); // error
foo2.add(1.5); // error

List<? super Integer> bar1 = new ArrayList<Number>();   // Number is a superclass of Integer
List<? super Integer> bar2 = new ArrayList<Object>(); // Object is a superclass of Integer
bar1.add(2);
bar2.add(3);
Object b1 = bar1.get(0);
Object b2 = bar2.get(0);


[size=medium][b]集合篇[/b][/size]
[color=blue](1)Enumeration vs Iterator vs ListIterator[/color]
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()

[color=blue](2)Collection vs Collections[/color]
Collection是集合类的顶级接口,除过Map其他大部分实现在该接口
Collections是一个utility类,提供一些静态方法来处理集合类

[color=blue](3)Comparator vs Comparable[/color]
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可以写多个比较方法多次排序

[color=blue](4)List vs Set vs Map[/color]
List有序可重复,可存多个null元素,主要实现:ArrayList, Vector, LinkedList
Set无序不可重复,只能存一个null元素,主要实现:HashSet, TreeSet, LinkedHashSet
Map键值对,键不可重复,键只有一个null,主要实现:HashMap, LinkedHashMap, Hashtable and TreeMap

[color=blue](5)Array vs ArrayList[/color]
Array固定长度,ArrayList不固定长度(后台通过数组实现)
Array创建时需要指定长度,ArrayList不需要(JDK有默认初始容量并会自动扩容)
Array不支持泛型,ArrayList支持泛型
Array长度:arr.length; ArrayList大小:list.size();
ArrayList只能存对象不能存primitive变量(自动装箱除外)

[color=blue](6)ArrayList vs LinkedList[/color]
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)

[color=blue](7)HashSet vs TreeSet[/color]
HashSet比TreeSet性能好
HashSet后台用Hashtable实现,TreeSet后台用红黑树实现
HashSet允许null,TreeSet不允许null
HashSet使用equals()比较对象,TreeSet使用compareTo()比较对象

[color=blue](8)Fail-Safe vs Fail-Fast Iterator[/color]
安全失败(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

[size=medium][b]线程篇[/b][/size]
[color=blue](1)wait() vs sleep() vs yield()[/color]
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()使当前线程停止时间是不定的

[color=blue](2)start() vs run()[/color]
start()调用时会创建一个新线程,并且执行内部的run()方法
直接调用run()方法无法创建新线程,run()方法执行在当前线程里
start()方法不能调用多次,第二次会抛出IllegalStateException

[color=blue](3)Thread vs Runnable interface[/color]
扩展继承Thread后就不能再继承其他类
Runnable标示该对象是一个Task可以被执行,执行还的通过Thread

[color=blue](4)Callable vs Runnable[/color]
Callable会抛出checked异常,Runnable没有
Callable能在call()方法中返回操作结果,Runnable的run()方法不行
Callable可通过泛型传入返回类型

[color=blue](5)Synchronized vs Concurrent Collections[/color]
都提供线程安全
Synchronized集合:Hashtable,Vector。Collections.synchronizedMap(),Collections.synchronizedList()
Concurrent集合:ConcurrentHashMap,CopyOnWriteArrayList
Synchronized集合比Concurrent集合性能慢
Synchronized集合锁整个对象,Concurrent集合会被分成多个segments锁其中一个segment

[color=blue](6)Multi-Threading vs Multi-Tasking[/color]
multi-threading多个线程同时执行同一个程序或程序不同部分,multitasking并行执行不同的程序
multitasking有两种:基于进程process、基于线程thread。进程比线程开销跟大

[color=blue](7)User thread vs Daemon thread[/color]
main thread里创建的线程默认都是user thread,通过setDaemon(true)能够是它变为daemon thread
daemon thread里边创建的线程也是daemon thread的
JVM在结束时需要等待user thread,但是不会等待daemon thread
JVM自身会创建一些daemon thread,比如GC
daemon thread的优先级更低
user thread可以被应用或线程自己关闭,JVM来终止daemon thread
不要再daemon thread里编写业务代码

[size=medium][b]设计篇[/b][/size]
[color=blue](1)Abstraction vs Encapsulation[/color]
Abstraction抽象:interface, abstract class
Encapsulation封裝:private, package-private, protected

[color=blue](2)Overloading vs Overriding[/color]
Overload重载在编译期,Override重写在运行期
同一个类中overload方法,子类中override父类方法
可以overload静态方法,但不能override静态方法
private和final方法不能override,但可以overload
overload时需要修改方法的定义(参数表),override不需要

[color=blue](3)Dependency Injection vs Factory Pattern[/color]
DI依赖注入需要第三方框架支持(比如Spring),工厂模式自己封装代码
DI松耦合设计,工厂模式耦合factory和object
DI框架替你常见管理实例,工厂通过getInstance()生产一个实例
DI更易于单体测试,更弹性灵活,但DI需要配置注入关系

[color=blue](4)Singleton Pattern vs Static Class[/color]
单例提供的是Object,静态类提供的是方法
静态类性能更好
静态类方法不可override
静态类不便于测试
单例可以保持对象的状态等信息,静态类不可以
单例只在使用时加载(lazy load),静态类启动时加载
很多DI框架更容易支持单例

[color=blue](5)Class vs Instance vs Object[/color]
Class的实例是对象。(An object is an instance of a class)
Class是用于创建对象的模板蓝图
Instance是类的一个唯一拷贝用于表现对象
Object拥有状态 state 和行为 behavior
JVM实际是先创建Instance后创建Object
具体参考[url=https://alfredjava.wordpress.com/2008/07/08/class-vs-object-vs-instance/]这里[/url]

[color=blue](6)Stack vs Heap[/color]
Heap存贮对象(JDK 7前String存在String Pool,之后也版本也存入Heap)
Stack存贮本地变量、方法定义、调用栈
所有线程共享Heap,各线程之间是不共享Stack的(本地变量是被线程隔离的)
创建thread后JVM会为其分配Stack
Heap的空间比Stack更大
可以指定Heap(-Xms-Xmx)和Stack(-Xss)的大小
Heap和Stack存储的数据结构是不一样的

[size=medium][b]其他[/b][/size]
[color=blue](1)trustStore vs keyStore[/color]
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
[quote]
证书标准 :X.509
编码格式 :
PEM-encoded certificate (domain.pem) Apache和*NIX服务器
DER-encoded certificate (domain.der) Java和Windows服务器
文件扩展名 :
keystore.jks - Java的Keytool工具生成的密钥库,存储非对称密钥对(私钥+x509公钥证书),有时也叫xxxx.keystore
keytool -genkey -alias localhostkey -keystore localhost.keystore -storepass password -keypass password
domain.key - 存放一个公钥或者私钥,并非X.509证书
openssl genrsa -des3 -out domain.key 2048
domain.csr - 证书签名请求,存放一个公钥,并非X.509证书,生成证书时要提交给证书颁发机构
openssl req -newkey rsa:2048 -nodes -keyout domain.key -out domain.csr
domain.crt - Self-Signed Certificate *NIX系统
openssl req -newkey rsa:2048 -nodes -keyout domain.key -x509 -days 365 -out domain.crt
domain.cer - 证书文件,只有公钥
domain.p12 - 证书文件,包含公钥及私钥,PKCS12(domain.pfx)
[/quote]

[color=blue](2)Type 1, 2, 3, 4 JDBC Driver[/color]
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

[color=blue](3)32-bit vs 64-bit[/color]
32位CPU寻址范围是2的32次方,大概4GB的RAM(留给应用的大概Linux:2GB,Windows:1.5GB)
64位系统各OS寻址范围不同Windows可达8TB
32位OS只能按照32位Java,64位OS可以安装32位Java或64位Java
64位需要heap的大小多于32位的30-50%(object headers、object references)
64位GC中断时间更长
.class不依赖于多少位的Java编译器(互通编译,互通使用)
整型值的上限和多少位没关系Integer.MAX_VAlUE = 2^31 - 1

[color=blue](4)PATH vs CLASSPATH[/color]
- JAVA_HOME:
指向JDK安装目录,比如C:\Program Files\Java\jdk1.8.0_65
Java本身不使用,第三方应用比如Tomcat使用,因为运行需要JDK支持
- JRE_HOME:
指向JRE安装目录,比如C:\Program Files\Java\jdk1.8.0_65\jre
Java本身不使用,第三方应用比如Tomcat使用,因为运行需要JDK支持,Tomcat优先使用JRE_HOME
JDK安装后有两套相同的JRE:C:\Program Files\Java\jdk1.8.0_65\jre(供JDK附属工具用的)、C:\Program Files\Java\jre1.8.0_65
***javac XXX.java 等价于 java -cp "%JAVA_HOME%\lib\tools.jar" com.sun.tools.javac.Main XXX.java
***Tomcat早期版本需要JDK把jsp编译成servlet,现在已经内置Eclipse的ECJ来支持JSP。
- CLASSPATH:
JVM类加载器查找class的路径
Java6后支持通配符不用挨个指定jar,CLASSPATH="C:\Program Files\Java\jdk1.8.0_65\lib"
也可以通过-cp 或 -classpath参数指定后供javac和java命令使用
目前来说基本无需设置:JDK工具能自己查找到这些jar;IDE会为project设置不同classpath
***Eclipse有自己的编译器ECJ来编译代码不需要javac。
- PATH:
操作系统的默认环境变量,去查找javac和java等工具的位置
-rt.jar、dt.jar、tools.jar
rt.jar: JRE提供的所有类java.lang.String、java.util.ArrayList等,在$JAVA_HOME/jre/lib下。源代码:$JAVA_HOME/src.zip
dt.jar: 不要包含Swing的BeanInfo文件,在$JAVA_HOME/lib下。
tools.jar: JDK需要的工具集,javac、javadoc等需要调用这个jar,在$JAVA_HOME/lib下。
***这些文件都是提供给JVM使用的,一般不需要特别设置。而且这三个文件在JDK9会被删掉分到不同的文件!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值