基本数据类型有四类八种:
整型:byte(1字节)、short(2字节)、int(4字节)、long(8字节)
浮点型:float(4字节)、double(8字节)
字符型:char(2字节)
布尔型:boolean(1位)
引用类型:类class、接口interface、数组[]
Float存放的更大,因为虽然float占用4个字节,long占用8个字节,但是float存储结构不同, 是把32位分成了两部分,一部分存放阶码(左移位数的2进制表示,等价于10进制指数),一部分存放尾数(移动后小数点后面的数字,等价于10进制底数)。
可以,因为char是2个字节,汉字也是2个字节
不一定,如byte i = 127,加完之后结果为-128
结果不是0.1,会丢失精度,用BigDecimal,注意使用字符串进行构造,如new BigDecimal(“0.09”);同样大整形的时候可以使用BigInteger。
浮点数转二进制,是把小数点后面的值一直*2,一直到小数点后面为0结束,如果到了小数的底数表示的位数的时候还没有结束,就会直接丢失。
第一个有问题,第二个没问题,因为+=做了特殊处理,相当于+完之后强转了
int a = 128;
int b = 128;
System.out.println(a == b); //①
Integer a1 = 128;
Integer b1 = 128;
System.out.println(a1 == b1); //②
Integer a2 = 127;
Integer b2 = 127;
System.out.println(a2 == b2); //③
解析:对于①,由于a和b都是基本数据类型,==对比的时候采用的是值对比,所以相同,打印true
对于②和③,由于是对包装类型进行对于,所以比较的是引用,然后,对于整数,127到-128之间的数据存在了常量缓冲区,所以a2和b2并没有重新创建对象,而是指定了同一个地址,所以③为true,而a1和b1超出了范围,会创建出新的对象,所以不同,②打印false
回到目录
JAVA里面引用有四种类型:强引用、软引用、弱引用、虚引用
回到目录
a << 3
if(b() && a()){
}
boolean a{
打印一句话
return true;
}
boolean b {
打印一句话
return false;
}
int tmp = a ;
a = b;
b =tmp;
a = a+b;
b = a-b;
a = a-b;
a=a^b;
b=a^b;
a=a^b;
a = (a+b) - (b=a)
有时候,笔试题目可能会遇到取模运算,有正数也有负数,我们只需要按照下面规则处理即可:
回到目录
相同点
这三个类都是用来处理字符串的。
是否可变
String是不可变字符串,StringBuffer和StringBuilder是可变字符串。
安全性
StringBuffer是线程安全的,效率较低;StringBuilder是线程不安全的,效率高一些。
String有length()方法,数组没有,有lenth属性。
1个或者2个,因为new,一定会在堆中开辟空间,如果”123”在字符串常量池已经存在,就不会再字符串常量池中创建对象了,这样就只会有1个;如果串池(字符串常量池)中没有,那么就会在串池中创建一个对象,这样,就有两个对象。
回到目录
相同点
底层结构
线程安全性
Collections.synchronizedList(List)
大小和增长方式
CopyOnWriteArrayList 类的所有可变操作(add,set等等)都是通过创建底层数组的新副本来实现的。当 List 需要被修改的时候,我并不修改原有内容,而是对原有数据进行一次复制,将修改的内容写入副本。写完之后,再将修改完的副本替换原来的数据,这样就可以保证写操作不会影响读操作了。
从 CopyOnWriteArrayList 的名字就能看出CopyOnWriteArrayList 是满足CopyOnWrite 的ArrayList,所谓CopyOnWrite 也就是说:在计算机,如果你想要对一块内存进行修改时,我们不在原有内存块中进行写操作,而是将内存拷贝一份,在新的内存中进行写操作,写完之后呢,就将指向原来内存指针指向新的内存,原来的内存就可以被回收掉了。
相同点
底层结构
null值要求
容量和增长方式
安全性和性能
jdk8以前
ConcurrentHashMap使用一个Segment 数组Segment< K,V >[] segments,Segment继承自ReenTrantLock,所以每个Segment就是个可重入锁,每个Segment 有一个HashEntry< K,V >数组用来存放数据,put操作时,先确定往哪个Segment放数据,只需要锁定这个Segment,执行put,其它的Segment不会被锁定;所以数组中有多少个Segment就允许同一时刻多少个线程存放数据,这样增加了并发能力。
jdk8之后
去掉了分段锁,采用CAS + synchronized 控制并发操作,在某些方面提升了性能。对于节点Node中的value和next都用volatile修饰,保证并发的可见性。
会在某个key不再被引用的时候,remove掉这个key
Map wmap = new WeakHashMap<>();
// 添加键值对
wmap.put(w1, "w1");
wmap.put(w2, "w2");
wmap.put(w3, "w3");
// 打印出wmap
System.out.println("原始Map" + wmap);
// ---- 测试 WeakHashMap 的自动回收特性 ----
// 将w1设置null。
// 这意味着“弱键”w1再没有被其它对象引用,调用gc时会回收WeakHashMap中与“w1”对应的键值对
w1 = null;
// 内存回收。这里,会回收WeakHashMap中与“w1”对应的键值对
System.gc();
其实我觉得这个问题没有啥意义, 人家jdk底层要这么定义,关我毛事啊,但是如果面试官非得问,你可以如下回答:
HashMap为了存取高效,要尽量较少碰撞,就是要尽量把数据分配均匀。每个链表长度大致相同,这个实现就在把数据存到哪个链表中的算法;这个算法实际就是取模,hash%length,计算机中直接求余效率远远不如位移运算,源码中做了优化hash&(length-1),hash%length==hash&(length-1)的前提是length是2的n次方;
这个算法在putVal里面获取下标的地方是能看到的
hashtable计算下标的算法为:int index = (hash & 0x7FFFFFFF) % tab.length;
因为get操作可以无锁是由于Node的元素val和指针next是用volatile修饰的,在多线程环境下线程A修改结点的val或者新增节点的时候是对线程B可见的。
HashSet底层其实存放了一个HashMap,往set里面添加的元素放在了HashMap的key里面,这也是HashSet元素无顺以及不能重复的原因,因为hashmap结构,就注定了key不能重复,同时也不会有顺序。
static List arrayToList(final T[] array) {
final List l = new ArrayList(array.length);
for (final T s : array) {
l.add(s);
}
return (l);
List list = new ArrayList();
CollectionUtils.addAll(list, str);
对于不可变集合,你可以使用ImmutableList类及其of()与copyOf()工厂方法:(参数不能为空)
List il = ImmutableList.of("string", "elements"); // from varargs
List il = ImmutableList.copyOf(aStringArray); // from array
对于可变集合,你可以使用Lists类及其newArrayList()工厂方法:
List l1 = Lists.newArrayList(anotherListOrCollection); // from collection
List l2 = Lists.newArrayList(aStringArray); // from array
List l3 = Lists.newArrayList("or", "string", "elements"); // from varargs
什么是Hash碰撞
在HashMap中插入数据的时候,当我们对某一个元素进行hash函数计算以及干扰函数得到一个位置之后,发现这个位置已经被其他元素占用了,这种情况就是我们说的哈希碰撞,也叫哈希冲突。
解决办法
HashMap产生冲突的时候元素是插在链表的头部还是尾部?为什么?
Java7以前会插在链的头部,因为这样的话,不需要把指针移动到最后面一个元素进行插入操作,效率更高。Java8以后链表长度超过8的时候就会转变成红黑树,插入的位置是根据大小调整的。
要求重写hashcode和equals方法。
static class MyComparator implements Comparator{
@Override
public int compare(User o1, User o2) {
return o1.getId() - o2.getId();
}
}
然后调用
Collections.sort(List,Comparator),如:
public static void main(String[] args) {
List uList = new ArrayList<>();
Collections.sort(uList, new MyComparator());
}
当然,在jdk8以后,我们可以通过传入Lamda表达式来简化代码,我这里就不多赘述了
3. 使用jdk8提供的排序功能
List asks = .....
asks.sort(Comparator.comparing(DepthItem::getPrice)); //按照价格升序
asks.sort(Comparator.comparing(DepthItem::getPrice).reversed()); //按照价格降序
对于Integer类型的,可以在comparing里面传入:Integer::intValue
回到目录
回到目录
如有错误,欢迎大家多多批评,持续待续中…