目录
整个javase乃至于javaee很重要的知识点
集合的体系(java的后半段都是以前半段为基础的,面向对象继承多态要扎实)
集合的常用方法(API的使用)
List接口(重点 实际应用的时候用的多的)
ArrayList(最多)
Vector
LinkedList
数组回顾 int[] arr={1,8,9} int[] arr=new int[3] int[] arr=new int[]{1,2,5}
java数据类型 2 基本数据类型 引用数据类型
byte short int long float double boolean char
数组 类 接口
集合 一个容器 数组可以存储多个数值 一组数据 也可以存储对象
有数组为什么还要有集合呢?
一、常用API
添加相关的方法
add
(
E e)
确保此 collection 包含指定的元素(可选操作)。
addAll
(
Collection<? extends E> c)
将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
删除相关的方法
clear
()
移除此 collection 中的所有元素(可选操作)。
remove
(
Object o)
从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
removeAll
(
Collection<?> c)
移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
判断相关的方法
contains
(
Object o)
如果此 collection 包含指定的元素,则返回 true。
containsAll
(
Collection<?> c)
如果此 collection 包含指定 collection 中的所有元素,则返回 true。
isEmpty
()
如果此 collection 不包含元素,则返回 true。
数组的转换相关方法
toArray
()
返回包含此 collection 中所有元素的数组。
二、List集合
List是有序的集合,就像我们的数组一样。我们可以把list理解为是一个长度可变的数组,而且提供了丰富的api。List的集合底层就是数组。
0 | 1 | 2 | 3 | 4 |
劳斯莱斯 | 宾利 | 迈巴赫 | 奔驰 | 宝马 |
public static void main(String[] args) {
//创建一个list的集合
List list = new ArrayList();
//向末尾添加元素
list.add("吴用"); //0
list.add("刘唐"); //1
list.add("宋江"); //2
System.out.println(list);
//我们在1处的索引位置来插入元素,我们插入一个元素的话,改索引后面的元素都会向后移动一位
list.add(1, "晁盖");
System.out.println(list);
//创建一个集合
List list1 = new ArrayList();
list1.add("阮小五");
list1.add("阮小二");
list1.add("阮小⑦");
list.addAll(list1);
System.out.println(list);
}
public static void main(String[] args) {
//创建一个list的集合
List list = new ArrayList();
//向末尾添加元素
list.add("吴用"); //0
list.add("刘唐"); //1
list.add("宋江"); //2
System.out.println(list);
//我们在1处的索引位置来插入元素,我们插入一个元素的话,改索引后面的元素都会向后移动一位
list.add(1, "晁盖");
System.out.println(list);
//创建一个集合
List list1 = new ArrayList();
list1.add("阮小五");
list1.add("阮小二");
list1.add("阮小⑦");
list.addAll(list1);
System.out.println(list);
}
|
通过ListIterator的方式遍历
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()){
//获得迭代的元素
String str = (String) listIterator.next();
if("刘唐".equals(str)){
//我们不能在一边遍历的时候一边操作集合,这样有多线程的并发问题
//list.add("白胜");
//迭代器可以给我们提供了一个add方法让我们避免并发问题,但是添加的时候本次遍历不生效
listIterator.add("白胜");
}
System.out.println(str);
}
System.out.println(list);
我们可以使用for循环来动态的遍历List集合
System.out.println("---------------分割线 for循环遍历list-----------------------");
//int size = list.size();
//for循环对list的变量, 我们可以使用动态获得集合的长度的方式来遍历
for (int i = 0; i < list.size(); i++) {
//根据索引来获得对应的元素
String str = (String) list.get(i);
if("刘唐".equals(str)){
list.add("阮小五");
}
System.out.println(str);
}
0 | 1 | 2 | 3 | 4 |
劳斯莱斯 | 宾利 | 迈巴赫 | 宾利 | 宝马 |
List集合特点:
1.有序集合
2.元素可以重复 有索引
3.长度可变
4.底层实现为数组
三、ArrayList
ArrayList的底层是数组的原理。
ArrayList中的元素是可以重复
是有序的集合,长度不固定。
不是线程安全的。
效率高。
长度的变化。
ArrayList在添加数据的时候初始的长度是10,后续会以5个长度来扩充集合的长度。
ArrayList不是线程安全的集合,适合不要求线程安全的需求来实现。
好处是性能高。
缺点就是线程不安全,可能带来数据不准确。
如果线程要是同步的话,性能就会变低。
四、LinkedList
Linked也不是线程安全的。
1.底层结构是链表实现
2.适合做增删改的业务场景
3.线程不安全
4.有序集合但是更适合增删改
链表:储存了元素和前后的地址
LinkedList是链表为原理,添加修改删除的性能高。
栈:先进后出
队列:先进先出
五、Vector
Vector底层也是数组。
线程安全,支持多线程并发访问
可以存储任意类型对象,包括null
自定扩容,扩容机制是增量为当前容量的一半
public static void main(String[] args) {
Vector v = new Vector();
v.add("宋江");
v.add("晁盖");
v.add("刘唐");
System.out.println(v);
Object o = v.get(1);
//Object o1 = v.elementAt(1);
System.out.println(o);
System.out.println("--------------分割线-----------------");
for (int i = 0; i < v.size(); i++) {
Object o1 = v.get(i);
System.out.println(o1);
}
System.out.println("--------------分割线-----------------");
Enumeration elements = v.elements();
while(elements.hasMoreElements()){
Object o1 = elements.nextElement();
System.out.println(o1);
}
}
六、泛型
泛型就是在集合中指定存储的数据类型,而且只能存储这种类型,在List<类型>必须要指定, ArrayList<>可以指定也可以不指定。基本数据类不能作为泛型。
public static void main(String[] args) {
//定义一个集合里面指定只能存储一种数据类型
List<String> list = new ArrayList<>();
}
public static void main(String[] args) {
//定义一个集合里面指定只能存储一种数据类型
List<String> list = new ArrayList<>();
//调用集合
list.add("亮亮");
list.add("腻腻");
list.add("腻腻1");
list.add("腻腻2");
list.add("腻腻3");
//创建一个迭代器对象
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
//获得到String类型
String next = iterator.next();
System.out.println(next);
}
}
七、自定义的泛型
在自定义泛型时
语法:class/interface 类名/接口名 <T>{
}
T只是泛型的一个标准,使用什么字符都可以,但是都要大写,不要使用特殊字符,建议用T
自定义泛型类
public class GenericTest<T> {
//定义一个泛型的属性
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
测试
public static void main(String[] args) {
GenericTest<String> gt = new GenericTest<>();
gt.setT("哈哈");
//获得对应的泛型的结果
String t = gt.getT();
//指定泛型是Integer类型
GenericTest<Integer> gt1 = new GenericTest<>();
gt1.setT(1);
Integer t1 = gt1.getT();
//指定泛型是Integer类型的数组
GenericTest<Integer[]> gt2 = new GenericTest<>();
gt2.setT(new Integer[]{1, 2, 4});
Integer[] t2 = gt2.getT();
//测试2个泛型
GenericTest1<String, Integer> gtt1 = new GenericTest1<>("亮哥", 30);
GenericTest1<String, Date> gtt2 = new GenericTest1<>("亮哥", new Date());
}
八、增强的for
在Jdk1.5以后出现了增强的for
对数组,集合来做遍历
语法:
for(数据类型 变量:集合变量){
///
}
数据类型是集合或者数组中的数的类型
public static void main(String[] args) {
//定义一个数组
String [] strs = {"晁盖","宋江","刘唐","吴用"};
for(String str : strs){
System.out.println(str);
}
System.out.println("-----------------------------");
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
for (Integer i : list){
System.out.println(i);
}
System.out.println("-----------------------------");
//这个增强的for不能支持并发
/*for (Integer i : list){
if(i.equals(2)){
list.add(10);
}
System.out.println(i);
}*/
for (int i = 0; i < list.size(); i++) {
//根据索引获得集合的元素
Integer val = list.get(i);
//如果某个元素是2就在这个集合里加入一个10
if(val.equals(2)){
list.add(10);
}
System.out.println(val);
}
}
增强的for不支持并发,如果有并发的需求请使用普通的for循环。
九、Set(无序、唯一)的实现类HashSet
Set:
Set是Collection的子接口
无序性,无重复的元素
Set是个接口,不能直接创建对象,需要实现类来创建对象
Set的实现类是HashSet,linkedhashset,treeset
Hashset:特点:
1.元素唯一性
2.无序行
3.允许null存在一个
4.不是线程安全(效率高)
5,底层实现是数据结构是哈希表(哈希表依赖的两个方法:hashcode()和equals()方法)
(一般规则:对象的equals是true的话,hashcode需要相同,但是hashcode相同的对象不一定equals相同,这就是所谓的冲突现象,但是有不同的解决方法。你的hashCode()方法设计的好就会减少冲突。)
public static void main(String[] args) {
/**
* set是无序的
* set的元素是不可重复的,如果重复了就会自动的去掉
* set只能有一个null
*/
Set<String> set = new HashSet<>();
//给set添加元素
set.add("董卓");
set.add("张让");
set.add("何进");
set.add("李肃");
set.add(null);
System.out.println(set);
}
我们对set的唯一性深究一下
如果对象的hash值和equals都相等那么就是重复的对象。
public static void main(String[] args) {
//创建一个存储Person对象的集合
Set<Person> set = new HashSet<>();
set.add(new Person("孔明", 26));
set.add(new Person("刘备", 28));
set.add(new Person("关羽", 27));
set.add(new Person("张飞", 25));
set.add(new Person("张飞", 25));
System.out.println(set);
}
十、LinkedHashSet
特点:
1.元素唯一性
2.有序的
3.允许null存在一个
4.不是线程安全(效率高)
5,底层数据结构由链表和哈希表组成。
LinkedHashSet和HashSet来对比就是多了一个顺序。应用的不多。
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<>();
set.add("董卓");
set.add("张让");
set.add("何进");
set.add("李肃");
set.add(null);
System.out.println(set);
}
十一、TreeSet
排序比较
类如果要实现比较的规则都会实现Comparable接口。
String对CompareTo的实现
String str = "ab";
String str1 = "ab";
//字符串的比较规则是先按着第一个字符来比较,如果说一个字符串的第一个字符比另一个字符串的首字符大,那么前者就大
//如果是整数说明str大, 如果是负数str1大, 如果是0相等
int i = str.compareTo(str1);
System.out.println(i);
创建学生对象实现comparable接口
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
//做年龄的差
int flag = this.age - o.age;
if(flag == 0){
flag = this.name.compareTo(o.name);
}
return flag;
}
}
测试:
Student s = new Student("abc", 20);
Student s1 = new Student("abc", 20);
int i1 = s.compareTo(s1);
System.out.println(i1);
TreeSet的特点
特点:
1.元素唯一性
2.可自定义排序的(两种 Comparable接口 自己定义比较类实现Comparator比较器接口)
3.不允许null存在
4.不是线程安全
5,treeset集合中的包装类都必须实现Comparable接口。
6,底层数据结构是红黑树。(是一种自平衡的二叉树)
public static void main(String[] args) {
Set<Student> set = new TreeSet<>();
Student s = new Student("abc", 20);
Student s2 = new Student("abe", 20);
Student s1 = new Student("abd", 19);
set.add(s);
set.add(s1);
set.add(s2);
System.out.println(set);
}
十二、可变参数
可变参数的语法:
修饰符 返回值类型 方法名(数据类型…变量){
}
public class DynamicParamDemo {
public static void main(String[] args) {
//int result = add(10, 10);
int result = add(new int[]{10, 20, 30});
System.out.println(result);
}
//数据类型 ... 变量这是可变参数的定义方式
//可以代表数组, 还可以代表单个数的传递
//如果调用的时候我们发现了正好能匹配的方法就不会调用可变参数的方法,如果不存在这个一个正好调用的方法就会调用可变参数的方法
public static int add(int... a){
int total = 0;
for (int i = 0; i < a.length ; i++) {
total += a[i];
}
return total;
}
/*public static int add(int a, int b){
return a + b;
}*/
}
工具类Arrays
数组的工具类,这里的方法都是静态的
1.把数组转换成字符串
2.对任意数组排序
3.对任意的数组做二分法的查找
4.把数组转换成List
工具类Collections
面试题:
问:Collection和Collections的区别:
前者是集合的接口
后者操作集合的工具类