********集合********
Collection:单列集合顶层接口 add() remove() clear() 集合-->数组 迭代器 iterator() Iterator hasNext() next() |--List:有序,有索引,可以存入重复的元素 list.size() list.get() |--ArrayList:底层数组结构,增删较慢,查找相对较大 |--LinkedList:底层是链表,使用物理的不相邻表示逻辑的相邻,节点:本身元素,下一个元素的地址。 增删较快,查找较慢 特点方法:操作头和尾的节点的操作 addFirst() addLast() removeFirst() removeLast() getFirst() getLast() |--Vector:被ArrayList取代了,addElement() removeElement() elements 枚举器 hasMoreElement nextElement |--Set:无序,不能存储相同的元素 |--HashSet:哈希表,如何元素唯一呢, hasCode() equals() 存储的顺序和取出的顺序可能不一致。 |--LinkedHashSet:既想保证元素唯一,又想有序。 |--TreeSet:二叉树,既可以保证元素唯一,同时还可以进行排序。 第一种方式:让元素本身具有比较性 自定义类实现Comparable 重写compareTo()方法 正整数、零、负整数 第二种方式:使集合在创建 的时候就有比较性。比较器:自定义类实现Comparator,重写compare()方法 正整数、零、负整数 当两种方式同时存在,使用集合本身的比较性,元素的比较性就会失效。 Map:双列集合的顶层接口 put(K,V) get(k) 两种遍历方式: keySet()--->Set<Key> 遍历Set集合,过程中通过get() 获取相应的值 entrySet()-->Set<Map.Entry> 遍历set集合,过程中通getKey() getValue()获取相应的键和值 |--HashMap |--LinkedHashMap:既保证唯一,又有序。 |--TreeMap |--Hashtable:被HashMap替代。区别。 泛型:不确定的类型。 |--泛型类 |
①单列集合:每个元素都是一个单独的个体,只有value值 ②双列集合:每次操作都是针对一对数据,一个数据作为一个单位,key-value 单列集合体系 Collection:所有单列集合的顶层接口 |-------List:有序的子接口 |-------ArrayList:数组,顺序存储 |-------LinkedList:链表,链式存储 |-------Vector:被ArrayList取代 |-------Set:无序的子接口 |-------HashSet:哈希存储 |-------TreeSet:二叉树存储(会排序) 双列集合体系 Map:所有单列集合的顶层接口 |-------HashMap:哈希存储 |-------TreeMap:二叉树存储 |
1、集合和数组的区别 数组和集合类都是容器。 数组长度是固定的,集合长度是可变的。(存储数量不同) 数组中可以存储基本数据类型,集合只能存储对象。数组中存储数据类型是单一的,集合中可以存储任意类型的对象。(存储内容不同) 数组中只有Object中的方法和Length属性。集合中有很多很多方法。(方法不同) 集合类的特点,用于存储对象,长度是可变的,可以存储不同类型的对象。 |
********Collection********
Collection是单列集合的顶层接口,接口不能创建对象,可以创建一个具体的实现类,例如:Collection c = new ArrayList(); 1、Collection接口所定义的方法:
2、Collection遍历 ①把集合转换为数组,对数组进行遍历 Object[] toArray(); 单列集合通用的第一种遍历方式(调用toArray()方法,转为数组,然后遍历) 注意单列集合的这个toArray()方法返回值是一个Object类型的数组 多态(父类的引用指向子类的对象)中的成员方法的访问特点 1.编译看左边,运行看右边 2.编译的时候,要看父类中是否存在该方法,如果存在,编译通过,否则编译报错。 3.运行的时候,要运行子类的重写的方法,如果没有重写的方法,执行父类的方法。*/ Student stu = (Student)obj; /*不强转为子类对象的引用stu时,obj只能调用两者共有的方法中的子类对象的方法而不能调用Student类中特有的方法. ②获取集合的迭代器 Itreator 该接口是集合的迭代器接口类,定义了常见的迭代方法 Iterator迭代器是个接口,不能直接创建对象,但可以通过集合调用iterator()方法创建对象 1:boolean hasNext() 判断集合中是否有元素,如果有元素可以迭代,就返回true。 2: E next() 返回迭代的下一个元素,注意: 如果没有下一个元素时,调用next元素会抛出NoSuchElementException 3: void remove() 从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)。
1、迭代器对象虽然多次调用next方法,都是同样的方法名称,但是每次调用返回的结果是不同的,会因为next方法既可以获取下一个元素,也会让迭代器对象,向前移动一步。 2、如果没有下一个元素,仍然调用next方法,出现NoSuchElementException(没有当前元素异常),可以使用hasNext方法判断是否有下一个元素,决定是否调用next方法 3、hasNext方法,判断是否有下一个元素,不会移动迭代器的位置 4、next方法,不仅可以获取下一个元素,还会移动迭代器位置 5、不要只判断一次hasNext,就调用多次next方法 ③高级for循环底层实现的就是迭代器 只要实现了Iterable接口的集合,就可以使用增强型for循环进行遍历。 |
********List********
List接口是Collection的子接口,实现List接口的容器类中的元素是有顺序的,而且可以重复。 List容器中的元素都对应一个整数型的序号记录其在容器中的位置,可以根据此序号存取元素。 1、List中特有的方法(带索引)
2、List集合中的特有的遍历 size():获取元素的个数 get():获取指定位置的元素
|
********并发修改异常********
java.util.ConcurrentModificationException 原因:在迭代器(或者是在增强for循环中)操作数据时,集合本身也在操作(add,remove,clear等修改)数据,导致并发修改异常。 解决方法:要么集合本身在操作集合,要么迭代器在操作集合。 迭代器在操作集合时功能只有remove(),功能非常有限。所以引入ListInterator ListIterator:
|
********List-->Vector********
List的实现类,不常用,在jdk1.0出现,在jdk1.2被ArrayList替代 特点:效率较低,线程安全(多线程),顺序存储,增删较慢
|
********List-->ArrayList********
底层采用数组实现,默认10。每次增长60%,((oldCapacity * 3)/2 + 1) 查询快,增删慢。 实现原理:数组实现,顺序存储,通过物理内存的位置关系,来表达描述逻辑的顺序相邻。 查找快, 增删慢。
|
因为数组的内存空间地址是连续的. ArrayList底层维护了一个Object[] 用于存储对象,默认数组的长度是10。可以通过 new ArrayList(20)显式的指定用于存储对象的数组的长度。 当默认的或者指定的容量不够存储对象的时候,容量自动增长为原来的容量的1.5倍。 由于ArrayList是数组实现, 在增和删的时候会牵扯到数组增容, 以及拷贝元素,所以慢。数组是可以直接按索引查找, 所以查找时较快。 可以考虑,假设向数组的0角标位置添加元素,那么原来的角标位置的元素需要整体往后移,并且数组可能还要增容,一旦增容,就需要将老数组的内容拷贝到新数组中。所以数组的增删的效率是很低的。
|
********List-->LinkedList********
链表(节点)实现,链式存储,不通过连续的物理内存位置的相邻,来表示逻辑顺序的相邻 增删快, 查找慢 特有方法:
| |
1、为什么链表的增删快,而查询慢? 由于LinkedList:在内存中的地址不连续,需要让上一个元素记住下一个元素。所以每个元素中保存的有下一个元素的位置。虽然也有角标,但是查找的时候,需要从头往下找,显然是没有数组查找快的。但是,链表在插入新元素的时候,只需要让前一个元素记住新元素,让新元素记住下一个元素就可以了,所以插入很快。 由于链表实现, 增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记住后一个元素, 后一个元素记住前一个元素。这样的增删效率较高。 但查询时需要一个一个的遍历, 所以效率较低。
他们都是线性表,但是ArrayList基于数组(顺序存储),LinkedList基于链表(链式存储) 由于实现的不同,ArrayList在随机访问元素时性能较高,插入和删除元素时效率较低,LinkedList则反之。 |
********Set********
Set:注重独一无二的性质,该体系集合可以知道某物是否已经存在于集合中,不会存储重复的元素。用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。 该集合中没有特有的方法,直接继承自Collection。 Set集合的特点:无序、数据不重复。 主要包含的实现类有:HashSet、TreeSet、LinkedHashSet ... |
********Set-->HashSet********
HashSet的底层结构是HashMap
元素的哈希值是通过元素的hashcode方法来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法。如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不是同一个元素。
就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。 |
******HashSet-->LinkedHashSet******
是HashSet的一个子类。 和HashSet的不同之处在于,具有可预知的迭代顺序,存储的顺序和遍历集合时取出的顺序一致。 |
********Set-->TreeSet********
TreeSet是一个可排序集合,基于红黑树(自平衡二叉树),默认按元素的自然顺序升序排列。 1、也是一个Set子类,也可以保证元素的唯一,底层结构是二叉树。 2、既可以保证元素唯一,也可能进行自动排序 当存入的是基本数据类型和字符串时,TreeSet有自动升序排列的能力。而当存入的是自定义引用类型,遍历时会抛出异常。因为TreeSet并不知道如何排序。 两种比较器: (1)Comparable接口 TreeSet集合排序的两种方式: 第一种方式让元素自身具备比较性。也就是元素需要实现Comparable接口,重写compareTo 方法。
这种方式也作为元素的自然排序,也可称为默认排序。 compareTo 方法:this和参数的比较。
(2)Comparator接口 当元素自身不具备比较性,或者元素自身具备的比较性不是所需的。 那么这时只能让容器自身具备。
定义一个类实现Comparator 接口,重写compare方法。并将该接口的子类对象作为参数传递给TreeSet集合的构造方法。 当Comparable比较方式,及Comparator比较方式同时存在,以Comparator 比较方式为主。
compare方法比较规则:
TreeSet去重: 情况1: 当存入的数据是根据类型本身实现 Comparable接口方式比较大小,判断重复就是根据重写的compareTo方法。如果返回的是0 则认为是重复数据。 情况2: 当存入对象本身没有比较大小能力,而是根据比较器比较大小时,根据比较器中的compare方法的返回值来决定是否重复。返回0则认为是重复数据。 |
操作集合的工具类 Collections了解
Collections常用功能:大部分功能都是list的 List排序:sort方法 Collection元素搜索:binarySearch方法 改变Collection中的元素:addAll方法
|
********泛型********了解
格式
说明 1、类名后面跟着的泛型类型,是泛型的声明,一旦泛型声明出来,就相当于这个类型成为了已知类型,这个类型就可以在整个类中使用。 2、泛型的声明名称,只需要是一个合法的标识符即可,但是通常我们使用单个大写字母来表示,常用字母:T、W、Q、K、V、E。 3、泛型确定的时机:将来在使用这个类和创建对象的时候。 2、泛型方法 格式
说明 1、在方法上声明的泛型,可以在整个方法中,当做已知类型来使用。 2、如果【非静态】方法上没有任何泛型的声明,那么可以使用类中定义的泛型 3、如果【静态】方法上没有任何的泛型声明,那么就不能使用类的泛型,连类中定义的泛型,也不能使用,因为类中的泛型需要在创建对象的时候才能确定。所以【静态】方法想使用泛型,就必须在自己的方法上单独声明。 3、泛型接口 格式
说明 1、在接口声明上,定义好的泛型,可以在整个接口中当做已知类型来使用。 2、泛型接口被其他类实现的时候,有两种实现方式: (1)声明的类不再是一个泛型类,而是一个确定了泛型的类,格式如下: class 实现类类名 implements 接口名<具体类型> { 所有的泛型类型都已经被确定 } (2)声明的类还是一个泛型类,泛型的类型和接口的泛型一致,格式如下: class 实现类类名<泛型标识符1> implements 接口名<泛型标识符1> { 所有的方法还都是可以使用泛型标识符的方法 }
泛型通配符 ? extends E: 接收E类型或者E的子类型。 ? super E: 接收E类型或者E的父类型。 | |||
泛型的好处 1、提高了数据的安全性,将运行时的问题,提前暴露在编译时期 2、避免了强转的麻烦 注意事项 1、前后一致:在创建对象时,赋值符号前面和后面的类型的泛型,必须一致。 2、泛型推断:如果前面的引用所属的类型已经写好了泛型,后面创建对象的类型就可以只写一个尖括号,尖括号中可以不写任何内容。<>特别像菱形,称为“菱形泛型”,jdk1.7特性。 如何写一个方法,调用者传递什么类型的变量,该方法就返回什么类型的变量? 实现一: 由于无法确定具体传递什么类型的数据,那么方法的形参就定义为Object类型,返回值也就是Object类型。但是使用该方法时需要强制类型转换。 当不进行强制类型转换能否写出该功能?
目前所学的知识无法解决该问题。 就需要使用泛型类解决。 使用的泛型的自定义来解决以上问题。
|
********栈(Stack)********了解
常用方法:
|
********Map(映射)********
Map:双列集合的顶层接口。 Map是一个以键(key)值(value)对形式存储数据的容器。 特点 Map 是一个接口,但不是Collection的子接口。 Map以键值对的形式存储数据,每个键(key)对应一个值(value)。 Map 中的键不能重复(唯一)。(如果键重复的话,就以最后一个为准,前面的相同键的键值对都被覆盖) Map 中的值可以重复。 主要实现类 HashMap Hashtable TreeMap . 常用方法
|
********Map-->HashMap********
HashMap是Map接口的最常用实现类,底层是哈希表形式存储的,非线程安全的,允许有null键值对。 Map遍历 方式一:使用keySet()方法
Set<K> keySet() 方式二:使用entrySet()方法 获取Map集合中的所有键值对对象(Entry),到Set集合中,遍历Set集合,拿到的是每个键值对对象(Entry),从这个对象中分别获取键和值。【根据键值对对象获取键和值】 根据Map集合获取所有的键值对对象,到一个Set集合中 Set<Map.Entry<K, V>> entrySet()
Entry是Map接口中的内部接口,访问的方式:Map.Entry
Entry的常用方法: getKey()获取当前键值对对象的键 getValue()获取当前键值对对象的值 |
********Map-->HashTable********
Hashtable是一个比较古老的类(从JDK1.0开始),特点是线程安全的,不允许有null键. 用法和HashMap相同,基本被HashMap替代 |
面试常见问题HashMap和Hashtable的区别? HashMap: 线程不安全,允许null键值对,出现版本不同(1.2)),命名规范 Hashtable: 线程安全,不允许null键值对,1.0,命名不规范
|
********Map-->TreeMap********
特点:会根据key值进行升序排列。 |
******HashMap-->LinkedHashMap******
是HashMap的一个子类。 和HashMap的不同之处在于,具有可预知的迭代顺序,存储键值对的顺序和遍历集合时取出键值对的顺序一致。 |