java经典八股(持续更新)
1、String StringBuilder和StringBuffer
String的所有方法和参数都是用final修饰的,是不可变的。java中双引号括起来的字符串,例如"abc","qwe"都是存储在方法区中的字符串常量池的。
此时字符串常量池中会创建"abc"这个字符串常量,new创建的所有对象都在堆内存中,此时堆中存放的是指向“字符串常量池”的内存地址,所以s1==s2为false,他们两个在堆中的地址不同。 栈中存放的是指向堆的引用地址 String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1==s2); false 比较地址 System.out.println(s1.equals(s2)); true 比较内容
StringBuilder 和 Stringbuffer 都是在原对象上操作,StringBuffer是线程安全的,StringBuilder是线程不安全的,因为StringBuffer的方法都是synchronized修饰的。 性能:StringBuilder > StringBuffer > String 使用场景:经常需要改变字符串内容时,不用String,优先使用StringBuilder,多线程共享变量时使用StringBuffer 注意: 千万不能说不考虑性能时用StringBuffer 不考虑线程安全时使用StringBuilder,因为没有程序是不考虑这两个的
2、重载和重写的区别
重载:发生在同一个类中,方法名相同,参数类型不同、个数不同、顺序不同。
注意:方法名和参数都相同,只有返回值或访问修饰符不同时,不是重载!编译会报错 public String add(int i); public int add(int i); 编译报错,不是重载,重载和返回值修饰符没关系
重写:发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法用private修饰,则子类无法重写也无法继承
3、接口和抽象类的区别
4、hashCode和equals
equals如果不重写,那么就使用Object中的equals,即 == 比较引用地址 hashCode是为了计算哈希值返回int型,计算hashCode()是为了放入哈希表中,两个对象hashCode()相同,值不一定相同。两个对象相等,那么hashCode()一定相同。 hashCode()默认行为时对堆上的对象产生独特值。如果没有重新hashCode(),那么同一个类的两个对象无论如何也不会相等(即使两个对象指向相同的数据)。
5、ArrayList扩容机制
本质就是计算出新的扩容数组的size后实例化,并将原有的数组内容复制到新的数组中,默认新的容量是原来容量的1.5倍。
6、如何在遍历ArrayList时移除一个元素?
在foreach遍历时,删除元素会导致快速失败机制。使用迭代器的remove()方法
Iterator it = list.iterator(); while(it.hasNext()){ if(it.next().equals("123")) it.remove(); }
7、ArrayList和LinkedList
ArrayList底层使用数组实现,默认值为10。查找快,增删慢 LinkedList底层使用双向链表,查找慢,增删快。
8、HashMap
jdk1.8使用数组+链表+红黑树实现,1.8以前没有红黑树。链表长度大于8时会把链表转为红黑树,小于6时把红黑树转为链表。
9、解决hash冲突有哪些方法,HashMap使用哪种
有开放定址法、再哈希、链地址法。hashMap使用链地址法 HashMap使用的hash算法为:取key的hashCode值、高位运算、取模运算
h = key.hashCode(); 取hashcode值 h ^(h>>>16) 高位参与运算,减少冲突 return h&(length-1) 取模运算
jdk1.8优化了高位运算算法,通过hashCode()的高16位异或低16位实现的:这么做可以在数组比较小的时候,也能保证考虑到高低位都参与到hash计算,减少冲突。