java知识点总结(基础篇)

写在前面:工作多年,很多细节都值得回味,汲取大神经验,总结如下与大家共勉~(持续更新)

1.字符串“==”与 equals问题
String str1 ="abcd";

首先解释创建过程:

(1)栈中开辟一块空间存放引用str1;

(2)在String池中寻找其指向的内容为"abcd"的常量,如果String池中没有,则开辟一块空间,存放String常量"abcd",然后str指向String池中的对象,如果有,则直接将str1指向"abcd";

  String str2 = new String("abcd");

(1)栈中开辟一块空间存放引用str2; 

(2)堆中开辟一块空间存放一个新建的String对象"abc"; 

(3) 引用str2指向堆中的新建的String对象"abc";

解答:==是比较地址,equals()比较对象内容。栈区是存储引用和基本类型,不能存对象,而堆区存对象。

String str1 = "abcd";

String str2 = "abcd";

String str3 = new String("abcd");

String str4 = new String("abcd");

System.out.println(str1==str2);//true地址一样

System.out.println(str3==str4);//false,但地址不一样

System.out.println(str3.equals(str3));//true,值一样

System.out.println(str2.equals(str3));//true,值一样
注意以下区别
String s1 = "a";  
String s2 = s1 + "b";  
String s3 = "a" + "b"; 
System.out.println(s2 == "ab");  //false
System.out.println(s3 == "ab");  //true

解答:第一条语句打印的结果为false,第二条语句打印的结果为true,这说明javac编译可以对字符串常量直接相加的表达式进行优化,不必要等到运行期去进行加法运算处理,而是在编译时去掉其中的加号,直接将其编译成一个这些常量相连的结果。

s2=s1+"b"相当于s2= new StringBuffer(s1).append("b").toString();所以String每次用“+”链接都相当于在堆内存中先实例化一个StringBuffer然后再调用其append方法,最后调用toString方法转换成字符串。

所以如果“+”两边都是字符串的话,javac编译就会对字符串常量直接相加的表达式进行优化,不必要等到运行期去进行加法运算处理,而是在编译时去掉其中的加号,直接将其编译成一个这些常量相连的结果。而如果两边其中有一个是表达式的话javac编译就可能不会对字符串常量直接相加的表达式进行优化,需要等到运行时才会去进行运算,所以在第一条语句打印的结果为false,第二条语句打印的结果为true。


2.解释java包装类、拆箱和装箱

首先,我们知道java的基本数据类型,那为什么要有包装类,因为了数据在不同类型间转化,包装类具有各种方法的调用。

 由基本类型向对应的包装类转换称为装箱,例如把 int 包装成 Integer 类的对象

包装类向对应的基本类型转换称为拆箱,例如把 Integer 类的对象重新简化为 int。

Integer i=5;会进行自动装箱,默认执行 Integer.valueOf(5)

Integer a=5; int b=a;会进行先装箱后拆箱操作,拆箱操作执行a.intValue();

注意:在循环中注意避免产生大量装箱拆箱操作,会创建很多无用对象,造成内存空间浪费。


3.数据缓存问题,==与equals时要特别注意

Class CachaClass Range
Character CharacterCache 0~127
Byte ByteCache -128~127
Short ShortCache -128~127
LongCache LongCache -128~127
Integer IntegerCache -128~127

进行数值比较时,使用equals可能会出现问题。用BigDecimal类型compareTo方法进行比较靠谱

4.集合类

List相关:

ArrayList:底层数据结构使数组结构,查询速度快,增删改慢,

LinkList:底层使用链表结构,增删速度快,查询稍慢;

Vector:底层是数组结构,线程同步ArrayList是线程不同步;

ArrayList概述:ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。

ArrayList也采用了快速失败的机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。

   每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。

Vector:相对于ArrayList来说,Vector线程是安全的,也就是说是同步的

Set相关:

  HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用null元素。

  对于HashSet而言,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成


TreeSet实现了SortedSet接口,使用一个红黑树来存储元素,提供了元素的有序存储和访问.


HashMap底层是用数组链表存储的,元素是Entry。向HashMap添加时,由key的hashcode决定Entry存储位置,当两个Entry对象的key的hashcode相同时,由key的equals()方法返回值决定采用覆盖行为(返回true),还是在链表头添加新的Entry(返回false)。Collection values(),返回集合对象,但不能添加元素,主要是用来遍历。自定义类如果放入HashMap或HashSet中,需要重写equals和hashcode方法。


TreeMap底层是用红黑树来存储,每个Entry对应树的一个节点,TreeMap元素默认从小到大排序。V put(Key k, Value v)实质是二叉排序树的插入算法



3.&和&&的区别

&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式,例如,对于if(str != null&& !str.equals(“”))表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException如果将&&改为&,则会抛出NullPointerException异常。If(x==33 &++y>0) y会增长,If(x==33 && ++y>0)不会增长
&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。

5、switch语句能否作用在byte上,能否作用在long上,能否作用在String上?
在switch(expr1)中,expr1只能是一个整数表达式或者枚举常量,整数表达式可以是int基本类型或Integer包装类型,由于,byte,short,char都可以隐含转换为int,所以,这些类型以及这些类型的包装类型也是可以的。显然,long和String类型都不符合switch的语法规定,并且不能被隐式转换成int类型,所以,它们不能作用于swtich语句中。

 



你可能感兴趣的:(java基础)