全国咨询/投诉热线:400-618-9090

首页技术文章正文

集合的总结与常见问题解析

更新时间:2018-11-26 来源:黑马程序员 浏览量:

  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) 替换指定位置的元素,需要确定该元素的位置和新元素,返回就元素。

  ListsubList(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

  ----|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 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++){< p="">

  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

  Iteratoriterator():该类主要用于遍历集合对象,并描述了遍历集合的常见方法

  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

  ListIteratorlistIteraotr()

  ----| 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++){< p="">

  int y = Integer.parseInt(strs[x]);

  ts.add(y);

  }

  System.out.println(ts);

  }

  }

  23、遍历Map集合的方式有哪些?

  方式一:使用keySet

  将Map转成Set集合【keySet()】,通过Set的迭代器【Iterator】取出Set集合中的每一个元素,

  即Map集合中所有的键,再通过get()方法获取键对应的值

  Setks = map.keySet();

  Iteratorit = ks.iterator();

  while(it.hasNext()){

  Integer key = it.next();

  String value = map.get(key);

  }

  方式二:通过values获取所有值,但是不能获取到key对象

  Collectionvs = map.values();

  Iteratorit = vs.iterator();

  while(it.hasNext()){

  String value = it.next();

  }

  方式三:Map.Entry -->> public static interface Map.Entry

  通过Map中的entrySet()方法获取存放Map.Entry对象的Set集合 -->> Set<map.entry> entrySet()

  Set<map.entry> entrySet = map.entrySet();

  Iterator<map.entry> it = entrySet.iterator();

  while(it.hasNext()){

  Map.Entryen = it.next();

  }

  Integer key = en.getKey();

  String value = en.getValue();



作者:黑马程序员JavaEE培训学院

首发: http://java.itheima.com

javaee

python

web

ui

cloud

test

c

netmarket

pm

Linux

movies

robot

http://www.itcast.cn/subject/uizly/index.shtml?seozxuids

14天免费试学

基础班入门课程限时免费

申请试学名额

15天免费试学

基础班入门课程限时免费

申请试学名额

15天免费试学

基础班入门课程限时免费

申请试学名额

15天免费试学

基础班入门课程限时免费

申请试学名额

20天免费试学

基础班入门课程限时免费

申请试学名额

8天免费试学

基础班入门课程限时免费

申请试学名额

20天免费试学

基础班入门课程限时免费

申请试学名额

5天免费试学

基础班入门课程限时免费

申请试学名额

0天免费试学

基础班入门课程限时免费

申请试学名额

12天免费试学

基础班入门课程限时免费

申请试学名额

5天免费试学

基础班入门课程限时免费

申请试学名额

5天免费试学

基础班入门课程限时免费

申请试学名额

10天免费试学

基础班入门课程限时免费

申请试学名额
在线咨询 我要报名