java集合面试题
String
字符串是多个字符的集合,
String:是内容不可变的字符串,底层是不可变的字符数组, final char[]
final修饰的字符数字,final修饰的类不能被继承,值不能能改,
stringBuilder和stringBuffer::可变,没有用final修饰,char[] value;
最经典的就是拼接字符串。
1,string c = "a"+"b";
2,stringBuild sb = new StringBuilder();
sb.append("a").append("b")
stringBuilder 线程不安全,效率较高
stringBuffer 线程安全,效率较低
集合
集合一般分为Collection接口和Map接口。Map接口一般会用HashMap即可。Collection接口中有两大类List和Set
集合分为值,key-value{conllection map}两种,
存储值分为list 和set
list是有序的,可以重复的。
set的无序的,不可以重复的。根据equals和hashcode判断,也就是如果一个对象要存储在set中,必须重写equals和hashcode方法。
存储key-value的为map
Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等
Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
list中常用的arraylist和linkedlist的区别
arraylist底层使用时数组;linkedlist 使用的是链表
数组具有索引,查询特定的元素很快,而插入,删除和修改比较慢,数组在内存中是一块连续的内存,如果插入或删除是需要移动内存,
链表不要求内存是连续的,在当前元素中存放或者下一个或上一个元素的地址,查询时需要从头部开始,一个一个的找,所以查询效率低,插入时不需要移动内存,只需要改变引用指向即可,所以插入或者删除的效率高。
java.util.ArrayList
集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList
是最常用的集合。
java.util.LinkedList
集合数据存储的结构是链表结构。方便元素添加、删除的集合。LinkedList是List的子类,List中的方法LinkedList都是可以使用
LinkedList的使用
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> link = new LinkedList<String>();
//添加元素
link.addFirst("abc1");
link.addFirst("abc2");
link.addFirst("abc3");
System.out.println(link);
// 获取元素
System.out.println(link.getFirst());
System.out.println(link.getLast());
// 删除元素
System.out.println(link.removeFirst());
System.out.println(link.removeLast());
while (!link.isEmpty()) { //判断集合是否为空
System.out.println(link.pop()); //弹出集合中的栈顶元素
}
System.out.println(link);
}
}
ArrayList的使用
public class ListDemo {
public static void main(String[] args) {
// 创建List集合对象
List<String> list = new ArrayList<String>();
// 往 尾部添加 指定元素
list.add("图图");
list.add("小美");
list.add("不高兴");
System.out.println(list);
// add(int index,String s) 往指定位置添加
list.add(1,"没头脑");
System.out.println(list);
// String remove(int index) 删除指定位置元素 返回被删除元素
// 删除索引位置为2的元素
System.out.println("删除索引位置为2的元素");
System.out.println(list.remove(2));
System.out.println(list);
// String set(int index,String s)
// 在指定位置 进行 元素替代(改)
// 修改指定位置元素
list.set(0, "三毛");
System.out.println(list);
// String get(int index) 获取指定位置元素
// 跟size() 方法一起用 来 遍历的
for(int i = 0;i<list.size();i++){
System.out.println(list.get(i));
}
//还可以使用增强for
for (String string : list) {
System.out.println(string);
}
}
}
hashset的使用
public class HashSetDemo {
public static void main(String[] args) {
//创建 Set集合
HashSet<String> set = new HashSet<String>();
//添加元素
set.add(new String("cba"));
set.add("abc");
set.add("bac");
set.add("cba");
//遍历
for (String name : set) {
System.out.println(name);
}
}
}
输出结果如下,说明集合中不能存储重复元素:
cba
abc
bac
tips:根据结果我们发现字符串"cba"只存储了一个,也就是说重复的元素set集合不存储。
HashSet是如何保证数据不可重复的?
答:HashSet的底层其实就是HashMap,只不过我们HashSet是实现了Set接口并且把数据作为K值,而V值一直使用一个相同的虚值来保存,我们可以看到源码:
public boolean add(E e) {
return map.put(e, PRESENT)==null;// 调用HashMap的put方法,PRESENT是一个至始至终都相同的虚值
}
由于HashMap的K值本身就不允许重复,并且在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V,那么在HashSet中执行这一句话始终会返回一个false,导致插入失败,这样就保证了数据的不可重复性;
hashmap和hashtable的区别
Java包含两个类,java.util.Hashtable 和java.util.HashMap,它们提供了一个多种用途的hashtable机制。
Hashtable和HashMap对象可以让你把一个key和一个value结合起来,并用put() 方法把这对key/value输入到表中。然后你可以通过调用get()方法,把key作为参数来得到这个value(值)。只要满足两个基本的要求,key和value可以是任何对象。注意,因为key和value必须是对象,所以原始类型(primitive types)必须通过运用诸如Integer(int)的方法转换成对象。
都可以用来存储key-value的数据
hashmap可以把null作为key或者value,hashtable
Hashtable底层是一个哈希表,它是一个线程安全的集合,单线程集合,速度慢,Hashtable集合不能存储null值,null键。
继承的父类不同
Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。
hashmap是线程不安全,效率较高,hashtable线程安全,效率较低。
(想要线程安全但是又想效率高,通过把整个map分为N个segment(类似hashtable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。)
Map m = Collections.synchronizedMap(new HashMap(...));
Hashtable 线程安全很好理解,因为它每个方法中都加入了Synchronize。这里我们分析一下HashMap为什么是线程不安全的:
HashMap底层是一个Entry数组,当发生hash冲突的时候,hashmap是采用链表的方式来解决的,在对应的数组位置存放链表的头结点。对链表而言,新加入的节点会从头结点加入。
//1,创建Hashmap集合对象。
Map<Student,String>map = new HashMap<Student,String>();
//2,添加元素。
map.put(newStudent("lisi",28), "上海");
map.put(newStudent("wangwu",22), "北京");
map.put(newStudent("zhaoliu",24), "成都");
map.put(newStudent("zhouqi",25), "广州");
map.put(newStudent("wangwu",22), "南京");
//3,取出元素。键找值方式
Set<Student>keySet = map.keySet();
for(Student key: keySet){
Stringvalue = map.get(key);
System.out.println(key.toString()+"....."+value);
}
\1. 先创建一个hashtable,保存了1, 2, 3三个对象。
Hashtable numbers = new Hashtable();
numbers.put("one", new Integer(1));
numbers.put("two", new Integer(2));
numbers.put("three", new Integer(3));
\2. 查找
Integer n = (Integer)numbers.get("two");
if (n != null) {
System.out.println("two = " + n);
}