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);
}
posted @ 2020-04-27 21:15  木子酱  阅读(121)  评论(0编辑  收藏  举报