1、如何定义Collection?
Collection是一个集合体系的顶层接口,此接口中的方法都是:public abstract。
可以进行增删改查的操作:
增加: -->> boolean add(Object o) 一次添加一个元素,元素可以是Object 的子类,返回true
boolean addAll(Collection c) 一次添加一批元素,参数是Collection类型的
删除: -->> void clear() 清空集合
boolean remove(Object o) 一次删除一个元素,成功删除,返回true
boolean removeAll(Collection c) 一次删除一批,成功,返回true
查找: -->> boolean contains(Obejct o) 判断集合中是否包含指定元素
boolean containsAll(Collection c) 是否包含一批
boolean isEmpty() 判断集合是否为空
int size() 获取集合中的个数
修改: -->> clear() 清空集合中的所有元素
获取: -->> int size() 返回集合容器的大小
集合转换为数组:
Object[] toArray(); 该方法将集合转为数组,集合中的每一个元素,作为了数组一个的元素
【注意:集合中存储的是对象的引用,而不是对象本身】
【注意:接口与接口之间属于:继承关系】
2、录入用户在控制台输入的信息,可以使用Scanner类
Scanner sc = new Scanner();
3、List接口: ---->> public interface List extends Collection
List是一个继承了Collection接口的接口,具备了比Collection多的功能。
特点: ---->> 有序、有角标、可重复。
此接口的用户可以对List接口中每个元素的插入位置进行精确地控制。(通过角标获取集合中的元素)
增:
void add(int index,Object element) 指定元素添加的角标,增加一个元素
boolean addAll(int index,Collection c) 指定位置,增加一批
删:
Element remove(int index) 删除指定位置的元素,并且返回该元素
改:
Element set(int index,Object element) 替换指定位置的元素,需要确定该元素的位置和新元素,返回就元素。
List<E> subList(int fromIndex,int toIndex) 截取子结合,返回一个List,包含头,不包含尾。
查:
Object get(int index) 获取List结合指定位置的元素
int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引
int lastIndexOf(Object o) 倒序查找指定元素的位置
【注意角标越界:IndexOutOfBoundException // 找不到返回:-1】
【Object set = new list.get(list.size()-1);】
【List集合特有的增删改查方法都跟角标有关系!!!!】
【问:如何取出List集合中的元素?】
通过for循环,并使用size()和set()方法可取出List集合中的每一个元素。
4、ArrayList -->> 是一个List接口的实现类
具备List集合的特点:有序、有角标、可重复。
该类内部,维护了一个数组, 数组的元素是Object 类.
在ArrayList 类的构造函数中初始化的该数组, 如果没有显示的指定数组的长度,【默认长度是10】
也就是说: 使用无参数构造,new ArraList(), 自动创建的数组长度是60%.
ArrayList 在添加元素时,都会检测数组是否已满,如果满了,自动扩容(创建一个新数组),
【新数组长度的是老数组的1.6倍】
并且将老数组中的元素拷贝到了新数组,使用新数组继续增加元素.
5、ArrayList使用什么实现的?其优缺点是什么?
ArrayList是使用数组实现的。
优点:内存地址连续,查找快;
缺点:增加和删除元素,需要设计数组的扩容或者拷贝,效率很低。
---->> 总结: 数组实现,查找快,增删慢。
ArrayList中的方法:
boolean contains(Object o) 判断集合是否包含指定的元素,涉及了元素的比较(对象的比较)
内部使用了元素的equals()方法。
String类 重写了equals()方法
6、LinkedList ---->> List接口的实现类,具备:有序、有角标、元素可重复的特点。【和ArrayList类似】
LinkedList是一个双向链表,该集合提供了方便操作集合头和集合尾的方法。
【如果集合中没有元素可以获取或者删除,则抛:NoSuchElementException】
LinkedList特有的方法:
增加:
void addFirst(Element e)
void addLast(Element e)
删除:
Object getFirst()
Object getLast()
查找:
Object removeFirst() 移除并返回此列表的第一个元素
Object removeLast() 移除并返回此列表的最后一个元素
数据结构:
堆栈:
void push(Element e) 将元素推入此列表所表示的堆栈
Element pop() 从此列表所表示的堆栈处弹出一个元素
【压栈和弹栈:先进后出,后进先出】
队列:
boolean offer(Element e) 将指定元素添加到此列表的末尾(最后一个元素)
Element poll() 获取并移除此列表的头(第一个元素)
Element peek() 获取但不移除列表的头(第一个元素)
【队列的数据结构:先进先出】
返回逆序的迭代器对象:
descendingIterator() 返回逆序的迭代器对象
7、LinkedList的实现原理是什么?其优缺点?
LinkedList的实现原理是:链表实现,其内存地址是不连续的。
优点:相对于数组,增加元素快;
缺点;由于内存地址不连续,查找性能低。
8、集合与数组有什么区别?
相同点:数组和集合都是容器
数组和集合中存放的都是【对象的引用】而非对象本身
不同点:数组存储【基本数据类型】,是单一的。而且一旦声明好长度后,长度不可变;
集合【只能】储存【对象】,但是可以是任意类型的对象,其长度可变。
【集合的分类】
----|Iterable:接口
Iterator iterator()
----|Collection:单列集合
----|List: 有序存储顺序,可重复
----|ArrayList: 数组实现,查找快、增删慢
由于是数组实现,在增和删的时候会牵扯到数组增容,以及拷贝元素,所以慢;
数组是可以直接按索引查找的,所以查找时比较快。
----|LinkedList: 链表实现,增删快、查找慢
由于链表实现,增加时只要让前一个元素记住自己就可以了,删除时让前一个元
素记住后一个元素,后一个元素记住前一个元素,这样的增删效率高;
但查询时需要一个一个的遍历,所以效率比较低。
----|Vector: 多线程安全、效率略低 【ArrayList单线程效率高,但是多线程要使用Vector】
----|set: 无序存储,不可重复
----|HashSet 线程不安全,存取速度快
底层是以hash表实现的
----|TreeSet 红-黑树的数据结构,默认对元素进行自然排序(String)
【TreeSet自身具备排序功能】
----|Comparable
----|compareTo(Object o) 元素自身具备比较性
----|Comparator
----|compare(Object o1,Object o2) 给容器传入比较器
如果在比较的时候两个对象返回值是【0】,那么这两个元素【重复】
【当Comparable和Comparator比较方式同时存在时,以Comparator比较方式为主】
----|LinkedHashSet 会保存插入的顺序
----|Map: 将键映射到值的对象。一个映射不能包含重复的键,每个键最多只能映射一个值。
interface Map<K,V>
----|TreeMap 底层是二叉树数据结构,可以对map集合中的键进行排序
需要使用Comparable或者Comparator进行比较排序。
【return 0 判断键的唯一性】
----|HashTable 底层是哈希表数据结构,线程是【同步】的 -->> 不可以存入null键、null值
效率较低,故被【HashMap】替代
----|HashMap 采用哈希表实现 -->> 【无序】
底层是哈希表数据结构,线程是【不同步】的 -->> 可以存入null键、null值
【要保证键的唯一性,需要覆盖hashCode()方法和equals()方法】
----|LinkedHashMap
【常用方法:】
添加: V put(K key,V value) 可以是相同的key值,但是添加的value值会覆盖前面的
putAll(Map<? extends K , ? extends V> m)
从指定映射中将所有映射关系复制到此映射中(可选操作)
删除: remove(Object key) 删除关联对象,指定key对象
clear() 清空集合对象
获取: value get(Object key) 可以用于判断键是否存在的情况。
判断: boolean isEmpty() 如果此映射不包含键-值映射关系【即长度为0】,则返回true,否则返回false
boolean containsKey(Object key)
判断集合中是否包含指定的key
boolean containsValue(Object value)
判断集合中是否包含指定的value
当指定的键不存在的时候,返回的是null
长度: int size() 返回此映射中的键-值映射关系数
9、在什么时候该使用什么样的集合?
Collection 当我们需要保存若干个对象的时候使用集合
-->> List 如果需要保留存储顺序、并且重复元素时,使用List
-->> 如果查询较多,使用ArrayList;
如果存取较多,使用LinkedList;
如果需要线程安全,使用Vector。
-->> Set 如果不需要保留存储顺序,并且要去掉重复元素时,使用Set
-->> 如果需要将元素排序,使用TreeSet;
如果不需要排序,使用HashSet 【HashSet比TreeSet效率高】
如果需要保留存储顺序,同时要过滤重复元素,使用LinkedHashSet。
10、自定义对象时为什么要重写toString()和equals()方法?
因为Object是自定义类的父类,Object类中的toString()方法返回的是哈希值;
Object类中的equals()方法比较的是对象的地址值。
【去除集合中重复的元素】
代码如下:
public class Demo{
public static void main(String[] args){
ArrayList arr = new ArrayList();
Person p1 = new Person("jack",20);
Person p2 = new Person("rose",18);
Person p3 = new Person("rose",18);
arr.add(p1);
arr.add(p2);
arr.add(p3);
System.out.println(arr);
ArrayList arr2 = new ArrayList();
for(int i=0;i<arr.size();i++){
Object obj = arr.get(i);
Person p = (Person)obj;
if(!arr2.contains(p)){
arr2.add(p);
}
}
System.out.println(arr2);
}
}
class Person{
private String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
public int hashcode(){
return this.name.hashCode() + age*37;
}
public boolean equals(Object obj){
if(!(obj instanceof Person)){
return false;
}
Person p = (Person)obj;
return this.name.equals(p.name) && this.age = p.age;
}
public String toString(){
return "name:" + this.name + "age:" + this.age;
}
}
11、Vector: 多线程安全、但是效率低 ---->> 描述的是一个线程安全的ArrayList。
特有的方法:
void addElement(E obj) 在集合末尾添加元素
E elementAt(int index) 返回指定角标的元素
Enumeration element() 返回集合中的所有元素,封装到Enumeration对象中
Enumeration接口:
boolean hasMoreElements() 测试此枚举是否包含更多的元素
E nextElement() 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素
【代码如下:】
public static void main(String[] args){
Vector v = new Vector();
v.addElement("aaa");
v.addElement("bbb");
v.addElement("ccc");
// System.out.println(v.elementAt(2));
Enumeration ens = v.elements();
while(ens.hasMorreElements()){
System.out.println(ens.nextElement());
}
}
12、Iterable: 是Collection的父接口,实现Iterable的类可以进行迭代,并且支持增强for循环
该接口只有一个方法,用于返回集合迭代器对象! 【获取迭代器的方法iterator()】
piblic interface Iterable<T>
Iterator<T> iterator():该类主要用于遍历集合对象,并描述了遍历集合的常见方法
boolean hasNext() 判断集合中是否有元素,如果有元素可以迭代,就返回true。
E next() 返回迭代的下一个元素。
如果没有下一个元素,调用next()会抛出 -->> NoSuchElementException
void remove() 从迭代器指向的集合中移除迭代器返回的最后一个元素
【Iterator的for循环、清空】
public class Demo{
ArrayList list = new ArrayList();
// 增加:add() 将指定对象存储到容器中
list.add("计算机网络");
list.add("现代操作系统");
list.add("java编程思想");
list.add("java核心技术");
list.add("java语言程序设计");
System.out.println(list);
for(Iterator it = list.iterator();it.hasNext();){
// 迭代器的next()方法返回值类型是Object,所有要记得【类型强转】
String next = (String)it.next();
System.out.println(next);
it.remove();
}
}
【细节一:如果迭代器的指针已经指向了集合的末尾,那么如果再调用next()会返回NoSuchElementException异常】
【细节二:如果调用remove()之前没有调用next()方法是不合法的,会抛出IllegalStateException异常】
【细节三:当一个集合在循环中即使用引用变量操作集合,又使用迭代器操作集合对象,会抛出ConcurrentModificationException异常】
13、为什么next()方法的返回值类型是Object呢?
为了可以接收任意类型的对象
如果返回的时候不知道是什么类型的,就定义为object
14、Iterator和ListIterator有什么关系?
ListIterator是Iterator的子接口,是List集合特有的迭代器。
Iterator在迭代时,只能对元素进行获取【next()】和删除【remove()】的操作;
ListIterator在迭代list集合时,还可以对元素进行添加【add(obj)】和修改【set(obj)】的操作。
15、List集合特有的迭代器ListIterator
---->> public interface ListIterator extends Iterator
ListIterator<E> listIteraotr()
----| Iterator
hasNext()
next()
remove()
----| ListIterator
add(E e) 将指定的元素插入列表(可选操作)。
该元素直接插入到next()返回的下一个元素的前面(如果有)
void set(E o) 用指定的元素替换next()或previous()返回的 【最后】 一个元素
hasPrevious() 逆向遍历列表,列表迭代器有多个元素,则返回true
previous() 返回列表中的前一个元素
16、HashSet是如何判断两个元素重复的?
通过hashCode()方法和equals()方法来保证元素的唯一性,add()方法返回的是boolean类型
【调用原理:HashSet集合在判断元素是否相同,先判断hashCode()方法,相同才会判断equals()方法;不相同不会调用equals()】
17、HashSet和ArrayList集合在判断元素时是否有相同的方法?
有:boolean contains(Object o)
HashSet使用hashCode()和equals()方法,ArrayList使用eqauls()方法。
18、给TreeSet指定排序规则:
方式一:【元素自身】具备比较性
元素自身具备比较性,需要元素实现【Comparable接口】,重写【compareTo方法】,
也就是让元素自身具备比较性,这种方式叫做元素的【自然排序】也叫做【默认排序】。
方式二:【容器】具备比较性
当元素自身不具备比较性,或者自身具备的比较性不是所需要的。
那么此时可以让容器自身具备。需要定义一个类实现【Comparator接口】,重写【compare方法】,
并将该接口的子类实例对象作为参数传递给【TreeSet集合】的【构造方法】。
注意:当Comparable比较方式和Comparator比较方式同时存在时,以【Comparator】的比较方式为主;
注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。
通过return 0 来判断唯一性。
19、为什么使用TreeSet存入字符串,字符串默认输出是按升序排列的?
因为字符串实现了一个接口,叫做【Comparable接口】,字符串重写了该接口的【compareTo()方法】,
所以String对象具备了比较性。
【自定义的元素(比如Person类、Book类)想要存入TreeSet集合,就必须实现Comparable接口,也就是要让自定义对象具备比较性】
【存入TreeSet集合的元素都要具备比较性:要实现Comparable接口、并重写该接口的compareTo()方法】
20、总结:
看到array,就要想到角标。
看到link, 就要想到first,last。
看到hash, 就要想到hashCode,equals.
看到tree, 就要想到两个接口。Comparable,Comparator。
21、TreeSet是如何保证元素的唯一性的?
通过【compareTo】或者【compare】方法来保证元素的唯一性。
当Comparable接口中的compareTo()函数返回值为【0】时,说明两个对象相等,此时该对象不会被添加进来。
22、使用TreeSet集合将字符串 String str = "8 10 15 5 2 7"; 的数值进行排序。
public class Demo{
public static void main(String[] args){
String str = "8 10 15 5 2 7";
String strs = str.split(" ");
TreeSet ts = new TreeSet();
for(int x= 0;x<strs.length();x++){
int y = Integer.parseInt(strs[x]);
ts.add(y);
}
System.out.println(ts);
}
}
23、遍历Map集合的方式有哪些?
方式一:使用keySet
将Map转成Set集合【keySet()】,通过Set的迭代器【Iterator】取出Set集合中的每一个元素,
即Map集合中所有的键,再通过get()方法获取键对应的值
Set<Integer> ks = map.keySet();
Iterator<Integer> it = ks.iterator();
while(it.hasNext()){
Integer key = it.next();
String value = map.get(key);
}
方式二:通过values获取所有值,但是不能获取到key对象
Collection<String> vs = map.values();
Iterator<String> it = vs.iterator();
while(it.hasNext()){
String value = it.next();
}
方式三:Map.Entry -->> public static interface Map.Entry<K,V>
通过Map中的entrySet()方法获取存放Map.Entry<K,V>对象的Set集合 -->> Set<Map.Entry<K,V>> entrySet()
Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
Iterator<Map.Entry<Integer,String>> it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<Integer,String> en = it.next();
}
Integer key = en.getKey();
String value = en.getValue();
|
|