写在前面:工作多年,很多细节都值得回味,汲取大神经验,总结如下与大家共勉~(持续更新)
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。
首先,我们知道java的基本数据类型,那为什么要有包装类,因为了数据在不同类型间转化,包装类具有各种方法的调用。
由基本类型向对应的包装类转换称为装箱,例如把 int 包装成 Integer 类的对象
包装类向对应的基本类型转换称为拆箱,例如把 Integer 类的对象重新简化为 int。
Integer i=5;会进行自动装箱,默认执行 Integer.valueOf(5)
Integer a=5; int b=a;会进行先装箱后拆箱操作,拆箱操作执行a.intValue();
注意:在循环中注意避免产生大量装箱拆箱操作,会创建很多无用对象,造成内存空间浪费。
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方法进行比较靠谱。
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添加
TreeMap底层是用红黑树来存储,每个Entry对应树的一个节点,TreeMap元素默认从小到大排序。V put(Key k, Value v)实质是二叉排序树的插入算法
5、switch语句能否作用在byte上,能否作用在long上,能否作用在String上?
在switch(expr1)中,expr1只能是一个整数表达式或者枚举常量,整数表达式可以是int基本类型或Integer包装类型,由于,byte,short,char都可以隐含转换为int,所以,这些类型以及这些类型的包装类型也是可以的。显然,long和String类型都不符合switch的语法规定,并且不能被隐式转换成int类型,所以,它们不能作用于swtich语句中。