1、集合
介绍:集合,集合是java中提供的一种容器,可以用来存储多个数据。出现意义:面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。Java中的集合: JDK为我们提供了一套完整的容器类库,这些容器可以用于存储各种类型的对象,并且长度都是可变的,我们把这些类统称为集合类,它们都位于java.util包中。
☆集合和数组区别:数组的长度是固定的。集合的长度是可变的。集合中存储的元素必须是引用类型数据。
Collection概念:Collection是所有单列集合的直接或间接接口,其指定了所有集合应该具备的功能。集合体系如图:
☆List总结
- 所有的List中只能容纳单个不同类型的对象组成的表,而不是Key-Value键值对。例如:[ tom,1,c ];
- 所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ];
- 所有的List中可以有null元素,例如[ tom,null,1 ];
- 基于Array的List(Vector,ArrayList)适合查询,而LinkedList(链表)适合添加,删除操作。
☆Set总结
6. Set实现的基础是Map(HashMap);
7. Set中的元素是不能重复的,如果使用add(Object obj)方法添加已经存在的对象,则会覆盖前面的对象
Collection通用方法:
boolean add(E e) //添加元素
boolean remove(Object o) //删除元素
void clear() //清空集合
boolean contains(Object o) //判断是否包含某元素
boolean isEmpty() //判断是否为空
int size() //获取集合长度
增强for循环:增强for循环是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。增强for循环用来迭代集合或数组。
☆格式:for(元素的数据类型 变量 : Collection集合or数组){}
☆注意:新for循环必须有被遍历的目标。目标只能是Collection或者是数组。遍历数组时,如果仅为遍历,可以使用增强for如果要对数组的元素进行 操作,使用老式for循环可以通过角标操作。
迭代器:集合用来持有数据,一定会设计出对数据的增、删、改、查四个常用方法,而查是集合中最常用的功能。Collection接口继承了Iterable接口,具备了可迭代功能iterator方法,该方法用于迭代集合。所以,所有单列集合由于是Collection的直接或间接实现类,均具有该方法。而增强for循环让迭代器循环访问的方式更加简便。
☆区别for循环:1、如果在for循环的过程中调用集合的remove()方法,就会导致并发修改异常 。因为循环过程中list.size()长度变小导致了错误。如果想在循环语句中删除集合中的某个元素,就要用迭代器iterator的remove()方法。2、在ArrayList里,for循环较快;在LinkedList里,使用iterator较快。
迭代常规步骤:1、通过集合获取这个集合的迭代器。 2、结合使用迭代器的hashNext与next完成集合迭代。
ArryList<String> list = new ArryList <String>();
list.add("i love java");
list.add("i like java");
Iterator<String> iterator = list.iterator();//返回迭代器
while (iterator.hasNext()) {
String string = iterator.next();
System.out.println(string);}
迭代集合元素图解:
public class Demo {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("111");
c.add("追");
c.add(111);
Iterator iterator = c.iterator(); // Iterator 接口 指向 子类对象.
while(iterator.hasNext()){// 2.调用迭代器的方法,获取集合中的元素.
Object next = iterator.next();
System.out.println(next);}
}
}
说明:遍历之前,有一个指针指向初始位置,第一个元素的前面, hasNext,判断是否在指针后面有元素,有返回true ,没有返回false 。如果有 , 就可以通过 next() 获取下一个元素了。
public class Demo {
public static void main(String[] args) {
Person s1 = new Person("顾慎为" , 20);
Person s2 = new Person("独步王" , 59);
Collection<Person> c = new ArrayList<>();
c.add(s1);
c.add(s2);
System.out.println(c);
Iterator<Person> it = c.iterator();//获取迭代器
while (it.hasNext()) {
Person p = it.next();
if(p.getAge() <59){
//c.remove(p);ConcurrentModificationException 并发修改异常 .
it.remove(); // 移除当前迭代的元素. (迭代器移除方法可以避免并发修改异常)
System.out.println(p.getName() +" --- "+ p.getAge());
}
}
}
class Person {
String name;
int age;
public Person(String n,int a){
this.name=n;
this.age=a;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
并发修改异常:迭代过程中并发修改异常的原因为迭代器中”记忆”的集合长度与集合中实际长度不同,而导致出现索引与实际元素不符甚至无限循环的情况发生。所以在使用Iterator时,避免类似操作,for循环底层为迭代器实现,所以也需要避免类似操作。有些迭代器避免了这样的问题,如ListIterator,但该类并不通用也不常用,实际开发中很少使用,只需要简单了解。
2、泛型
概述:泛型用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数传递。泛型是数据类型的一部分,我们将类名与泛型合并一起看做数据类型。泛型的定义:定义泛型可以在类中预支地使用未知的类型。泛型的使用:一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。常见应用:泛型类、泛型方法、泛型接口
含有泛型的类:
定义格式:修饰符 class 类名<代表泛型的变量> { }
//例如,API中的ArrayList集合
class ArrayList<E>{public boolean add(E e){ };public E get(int index){ }}
使用格式:创建对象时,确定泛型的类型。
ArrayList list = new ArrayList<>();
含有泛型的方法:
定义格式:修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
//例如,API中的ArrayList集合中的方法:
public <T> T[] toArray(T[] a){ }//该方法,用来把集合元素存储到指定数据类型的数组中,返回已存储集合元素的数组
使用格式:调用方法时,确定泛型的类型。
ArrayList list = new ArrayList<>();
String[] arr = new String[100];
String[] result = list.toArray(arr);
含有泛型的接口:
定义格式:修饰符 interface接口名<代表泛型的变量> { }
//例如,API中的Iterator迭代器接口
public interface Iterator<E> {public abstract E next();}
使用格式:
1、定义类时确定泛型的类型
public final class Scanner implements Iterator { public String next(){ }}
2、始终不确定泛型的类型,直到创建对象时,确定泛型的类型
Collection list = new ArrayList<>();
Iterator it = list.iterator();//此时,变量E的值就是String类型。
泛型通配符:在JDK1.5出现前,使用Object代表任意类型,但在使用时,涉及到了强转的麻烦。泛型替代了Object来代表任意类型。泛型在编译时会擦除:泛型仅用来在编译期限制、方便程序员的操作,实际上真正编译后的.class中是没有泛型的,其中仍然使用的为Obejct类,通过类似多态的方式完成任意某个类型的指定。当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
☆泛型优点:提高了程序的安全性;将运行期遇到的问题转移到了编译期;省去了类型强转的麻烦。
/*
泛型通配符?,代表任意的数据类型
使用:调用方法时可以给予任意类型。参照Arraylist的构造方法
public ArrayList(Collection<? extends E> c)
? extends E代表只要是E类型的子类即可
? super E代表只要是E类型的父类即可
*/
public class Demo {
public static void main(String[] args) {
ArrayList<String> listB = new ArrayList<>();
listB.add("Trump");
//创建集合对象A时,给于另外一个集合对象B作为参数,则创建好的集合A中包含了集合B中的元素
ArrayList<Object> listA = new ArrayList<Object>(listB);
listA.add("Obama");
System.out.println(listA);
}
}