1-画出Collection接口下的子接口的结构
2-画出Map接口下的子接口的结构
3-Set和List的区别?
Set集合包括其他的所有集合只能存放对象,Set集合中元素是无序的,且不能存放重复元素
List集合是有序的,可以存放重复元素,效率高,但是线程不安全。
4-HashSet和Set用法有什么不同?
Set是接口,HashSet是Set的实现类。
5-Map和HashMap用法有什么不同?
Map是接口,HashMap是实现类。
6-eclipse导入包的快捷键是什么?
ctrl+shift+M
或者Ctrl+Shift+O
7-ArrayList的size和length区别是啥?
ArrayList的size是集合中包含元素的个数,length应该是ArrayList底层实现中的的数组的长度。
8-ArrayList、LinkedList、Vector区别?从底层实现、查询遍历、修改插入删除、安全性、效率等角度.
ArrayList
集合是List接口的实现类,底层是用数组实现,因此使用ArrayList集合查询快,但是修改、插入、删除慢。ArrayList集合可以使用Collection接口中的所有方法,在ArrayList集合内部封装了一个动态的、允许再分配的Object[]数组,它使用initialCapacity参数来设置该数组的长度,当向集合中田间的元素超出集合的长度时,它们的initialCapacity会自动增加。我们在创建一个新的集合对象时,可以指定它的初始长度,如果不指定初始长度,那么jdk会指定初始长度为10。
特别要注意的是:ArrayList是线程不安全的,当多个线程同时访问同一个ArrayList时,如果其中的某个或者某几个线程修改了这个集合,则程序必须手动保证该集合的同步性。
LinkedLis
t集合和ArrayList一样,都是List接口的实现类,可以根据索引来访问元素,除此之外,LinkedList集合还实现了Deque接口,可以被当作双端队列来使用,一次可以被当作“栈”来使用,也可以当作队列来使用。LinkedList集合和ArrayList集合的实现机制完全不同,它的内部是用链表来实现的,因此查询元素的性能较差,而插入、修改和删除性能较好(只需要修改元素中的指针的地址即可)。
Vector
在用法上和ArrayList几乎完全相同,最大的区别在于:Vector是线程安全的,但是效率较慢。另外,由于Vector是一个古老的集合(从JDK1.0开始就有了),当时Java还没有提供系统的集合框架,所以Vector里提供了一些方法名很长的方法,如:addElement(Object obj),实际上这和add(Object obj)没有任何区别,从JDK1.2以后,Java提供了系统的集合框架,就将Vector改为实现List接口,作为List的实现之一,从而导致Vector中有一些重复的方法。实际上,Vector有很多缺点,通常尽量少使用Vector。
9-自己实现一个ArrayList类,并对关键代码加注释,并本地调用方法。要求实现至少ArrayList的2个方法.
package com.bjsxt.MyCollection;
/**
* 自己动手实现一个ArrayList集合,理解集合的底层原理
* @author WL20180723
*
*/
public class MyArrayList<E> {
/** 存放元素 **/
private Object[] elementData;
/** 元素个数 **/
private int size;
/** 默认初始化容量 **/
public static final int DEFAULT_CAPACITY = 10;
public MyArrayList() {
this.elementData = new Object[DEFAULT_CAPACITY];
}
public MyArrayList(int initialCapacity) {
if(initialCapacity >= 0) {
this.elementData = new Object[initialCapacity];
}else{
throw new IllegalArgumentException("非法长度:" + initialCapacity);
}
}
/**
* 获取集合大小
* @return
*/
public int size() {
return size;
}
/**
* 判断集合是否是空集合
* @return
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 添加元素
* @param e 泛型
*/
public void add(E e) {
ensureCapacity();
elementData[size++] = e;
}
/**
* 添加元素
* @param index 索引
* @param e 元素值
* @return
*/
@SuppressWarnings("unchecked")
public E add(int index, E e) {
rangeCheck(index);
ensureCapacity();
E oldValue = (E) elementData[index];
elementData[index] = e;
return oldValue;
}
/**
* 获取元素
* @param index 元素位置索引
* @return 元素值
*/
@SuppressWarnings("unchecked")
public E get(int index) {
rangeCheck(index);
return (E) elementData[index];
}
/**
* 集合是否包含某元素
* @param obj
* @return
*/
public boolean contains(Object obj) {
boolean flag = false;
if(obj == null) {
for(int i = 0; i < size; i++) {
if(elementData[i] == null) {
flag = true;
}
}
}else {
for(int i = 0; i < size; i++) {
if(obj.equals(elementData[i])) {
flag = true;
}
}
}
return flag;
}
/**
* 确保集合容量
*/
private void ensureCapacity() {
//判断集合是否已经装满
if(size == elementData.length) {
//集合装满,将集合扩容
Object[] newElementData = new Object[elementData.length * 2 + 1];
System.arraycopy(elementData, 0, newElementData, 0, elementData.length);
elementData = newElementData;
}
}
private void rangeCheck(int index) {
if(index < 0 ||index >= size) {
throw new IndexOutOfBoundsException("非法索引:" + index);
}
}
}
10-System.arraycopy 函数的作用?请用代码说明.
Java提供的System.arraycopy
函数用来从一个数组中指定索引开始复制一定长度的数据到另一个数组中。
public class TestArrayCopy {
public static void main(String[] args) {
int[] src = new int[]{1, 2, 3, 4, 5, 6};
int[] dest = new int[10];
System.arraycopy(src, 0, dest, 0, src.length);
for(int i = 0; i < dest.length; i++) {
System.out.println(dest[i]);
}
}
}
输出结果如下:
1 2 3 4 5 6 0 0 0 0
11-自己实现一个LinkedList类,并对关键代码加注释,并本地调用方法。要求实现至少LinkedList的2个方法.
package com.bjsxt.MyCollection;
/**
* 手动封装一个LinkedList,进一步理解LinkedList底层原理
* @author WL20180723
*
*/
public class MyLinkedList<E> {
/** 集合元素个数 **/
private int size = 0;
/** 首元素 **/
transient Node<E> first;
/** 尾元素 **/
transient Node<E> last;
public MyLinkedList() {}
/**
* 获取集合中元素个数
* @return
*/
public int size() {
return size;
}
/**
* 添加元素:默认在最后一个元素节点后添加
* @param e
* @return
*/
public boolean add(E e) {
Node<E> l = last;//将最后一个元素节点赋值给一个新的元素节点l
Node<E> newNode = new Node<E>(l, e, null);//新建一个元素节点给刚加入的元素e
last = newNode;
if(l == null) {
first = newNode;
}else {
l.next = newNode;
}
size++;
return true;
}
/**
* 在指定索引处添加元素
* @param index
* @param e
* @return
*/
public boolean add(int index, E e) {
rangeCheck(index);
Node<E> current = first;
if(index < (size >>1)) {
for(int i = 0; i < index; i++) {
current = current.next;
}
}else {
for(int i = size - 1; i > index; i--) {
current = current.previous;
}
}
Node<E> forward = current.previous;
Node<E> element = new Node<E>(forward, e, current);
current.previous = element;
forward.next = element;
size++;
return true;
}
/**
* 通过索引获取元素
* @param index
* @return
*/
public E get(int index) {
rangeCheck(index);
Node<E> node = getNode(index);
return node.element;
}
/**
* 移除元素
* @param index 索引
*/
public void remove(int index) {
rangeCheck(index);
Node<E> current = getNode(index);
Node<E> forward = current.previous;
Node<E> later = current.next;
forward.next = later;
later.previous = forward;
size--;
}
private void rangeCheck(int index) {
if(index < 0 || index >= size) {
throw new IndexOutOfBoundsException("非法索引:" + index);
}
}
/**
* 通过索引获取元素节点
* @param index
* @return
*/
private Node<E> getNode(int index){
Node<E> current = null;
if(index < (size >> 1)) {
current = first;
for(int i = 0; i < index; i++) {
current = current.next;
}
}else {
current = last;
for(int i = size - 1; i > index; i--) {
current = current.previous;
}
}
return current;
}
}
由于LinkedList底层是用链表来实现的,因此自定义节点用来存放Linked List中的每个元素节点。代码如下(在LinkedList源码中,元素节点被定义成了LinkedList类中的一个静态内部类,而且结构比咱们自己写的要复杂):
package com.bjsxt.MyCollection;
/**
* 自定义节点,用来存放数据
* @author WL20180723
*
*/
public class Node<E> {
/** 元素 **/
E element;
/** 上一个节点 **/
Node<E> next;
/** 下一个节点 **/
Node<E> previous;
public Node() {}
public Node(Node<E> previous, E element, Node<E> next) {
this.previous = previous;
this.element = element;
this.next = next;
}
}
12-eclipse上下移动整行代码快捷键是什么?
整行向上移动:Alt + ↑
整行向下移动:Alt + ↓
13-Map接口类的方法,put,get,remove,containsKey,containsValue,size,isEmpty,putAll,clear 分别用代码加注释说明其用法.
package com.bjsxt.MyCollection;
import java.util.HashMap;
import java.util.Map;
/**
* Map的常用方法
* @author WL20180723
*
*/
public class TestMyMap {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
Map<Integer, String> newMap = new HashMap<Integer, String>();
map.put(1, "aaa");//往map中添加元素(key=1,value="aaa")
newMap.put(1, "ddd");
newMap.put(2, "bbb");
newMap.put(3, "ccc");
String value = map.get(1);//从map中取出key值为1的元素值
map.remove(1);//从map中移除key值为1的元素值
boolean containsKey = map.containsKey(1);//map中是否包含key=1的元素
int size = map.size();//获取map包含元素的个数
boolean empty = map.isEmpty();//判断map中是否为空(即map中是否有元素)
map.putAll(newMap);//将newMap的元素放到map中,key值相同的会被覆盖
map.clear();//清空map的元素
}
}
14-HashMap,Hashtable区别?
HashMap和Hashtable都是Map接口的典型实现类,它们之间的关系完全类似于ArrayList和Vector的关系:
1.Hashtable是一个古老的Map实现类,它从JDK1.0起就已经出现了;
2.Java8改进了HashMap的实现,使用Hash Map是即使存在key冲突时依然具有很好的性能;
3.Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的,所以HashMap比HashTable性能好一些:如果有多个线程访问同时访问同一个Map对象时,使用Hashtable实现类会更好;
4.Hashtable不允许使用null最为key和value,如果试图把null值放入Hashtable中,将会引发NullPointerException异常;但是HashMap可以使用null作为key或者value。
注意:从Hashtable的类名上就可以看出它是一个古老的类,它的命名甚至没有遵守Java的命名规范:每个单词的首字母都应该大写。