为什么使用集合框架?
java集合框架提供了一套性能优良、使用方便的接口和类,它们位于java.util包中。
接口(增删改查)
Collection接口
存储一组不唯一、无序的对象。
特点:
1.可以存放不同类型的数据,
2.当使用arraylist子类实现的时候,初始化长度是10,长度不够时进行扩容操作。
api方法:
add: 要求必须传入的参数是Object对象,因此当写入基本数据类型的时候,包含了自动拆箱和自动装箱的过程。
-
Collection collection=new ArrayList(); collection.add(1);
addAll: 添加另一个集合到此集合中。
-
Collection collection1=new ArrayList(); collection1.add("a"); collection.addAll(collection1);
clear: 只是清空集合中的元素,但是次集合对象并没有被回收。
-
collection.clear();
remove: 删除指定元素。
-
collection.remove("a");
removeAll: 删除集合元素。
-
collection.removeAll(collection);
contains: 判断集合中是否包含指定的元素值。
-
System.out.println(collection.contains("a"));
containsAll: 判断此集合中是否包含另一个集合。
-
System.out.println(collection.containsAll(collection1));
isEmpty: 判断集合是否等于空
-
System.out.println(collection.isEmpty());
retainAll: 若集合中拥有另一个集合的所有元素,返回true,否则,返回false。
-
System.out.println(collection1.retainAll(collection));
size: 返回当前集合的大小。
-
System.out.println(collection.size());
toArray: 将集合转换成数组。
-
collection.toArray(); //转换对应类型 Object[] objects = collection.toArray();
List与Set接口(Collection子接口)
List接口存储一组不唯一、有序(插入顺序)的对象。
Set接口存储一组唯一、无序的对象。
Map接口存储一组键值对象,提供key到value的映射。
List:
List list=new ArrayList();
list.add("a");
list.add("1");
list.add("a");
list.add("true");
//[a, 1, a, true]
System.out.println(list);
//a
System.out.println(list.get(0));
//0
System.out.println(list.indexOf("a"));
//2
System.out.println(list.lastIndexOf("a"));
list.set(0,"mm");
//[mm, 1, a, true]
System.out.println(list);
List list1=list.subList(0,2);
//[mm, 1]
System.out.println(list1);
// List of=List.of(1,2,3,4);
ArrayList:
实现了长度可变的数组,在内存中分配连续的空间。
-优点:遍历元素和随机访问元素的效率比较高。
-缺点:添加和删除需要大量移动元素效率低,按照内容查询效率高。
LinkList:
采用链表存储方式。
-优点:插入、删除元素时效率比较高。
-缺点:遍历和随机访问元素效率低。
Vector:
Vector也是List接口的一个子类实现。
Vector跟ArrayList一样,底层都是使用数组进行实现。
Vector和ArrayList区别:
(1)ArrayList是线程不安全的,效率高,Vector线程安全。
(2)ArrayList在进行扩容的时候是扩容1.5倍,Vector扩容原来的2倍。
Set:
set中存放的是无序,唯一的数据。
set不可以通过下标获取对应位置的元素值。
使用treeset底层的实现是treemap,利用红黑树来进行实现。
设置元素的时候,如果是自定义对象,会差找对象中的equals和hashCode的方法
,如果没有,比较的是地址。
树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较;如果是引用类型的话,需要自定义比较器。
HashSet:
采用Hashtable哈希表存储结构。
-优点:添加速度快,查询速度快,删除速度快。
-缺点:无序。
-LinkedHashSet:
–采用哈希表存储结构,同时使用链表维护次序。
–有序(添加顺序)。
HashSet存储了相同对象,不符合实际情况:重写equals和hashCode方法。
TreeSet:
采用二叉树(红黑树)的存储结构。
-优点:有序(排序后的升序),查询速度比List快。
-缺点:查询速度没有HashSet快。
Iterator接口(Collection子接口)
常规的循环:do…while、while、for;还有一种增强for循环的方式,可以简化循环的编写。
所有的集合类都默认实现了Iterable的接口,实现此接口意味着具备了增强for循环的能力,也就是for-each。
增强for循环本质上是用的也是iterator的功能。
-方法:iterator()和foreach()
在iterator的方法中,要求返回一个Iterator的接口子类实例对象,此接口中包含了hasNext()和next()。
在使用iterator进行迭代的过程中如果删除其中的某个元素会报错并发操作异常,如果遍历的同时要修改元素,建议使用listIterator()。
listIterator()迭代器提供了向前和向后两种遍历方式,始终是通过cursor和laster的指针来获取元素值及向下遍历索引,当使用向前遍历的时候必须要保证指针在迭代器的结果,否则无法获取结果值。
// Iterator iterator = list.iterator();
ListIterator iterator = list.listIterator();
while(iterator.hasNext()){
Object o=iterator.next();
if (o.equals(1)){
iterator.remove();
}
System.out.println(o);
}
Comparable接口
此比较器按照name的长度来进行比较。
比较器分类:
-内部比较器
定义在元素的类中,通过实现comparable接口来进行实现。
Person.java:
public class Person implements Comparable{
private String name;
private int age;
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;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Object o) {
Person p=(Person) o;
if(p.name.length()<this.name.length()){
return 1;
}else if(p.name.length()>this.name.length()){
return -1;
}else {
return 0;
}
}
}
SetDemo.java:
public class SetDemo{
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();
treeSet.add(new Person("ooop", 12));
treeSet.add(new Person("io", 9));
treeSet.add(new Person("kdlsjf", 13));
treeSet.add(new Person("fio", 14));
System.out.println(treeSet);
}
}
-外部比较器
定义在当前类中,通过实现comparator接口来实现,但是要将比较器传递到集合中。
Person.java:
public class Person /*implements Comparable*/{
private String name;
private int age;
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;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
// @Override
// public int compareTo(Object o) {
// Person p=(Person) o;
// if(p.name.length()<this.name.length()){
// return 1;
// }else if(p.name.length()>this.name.length()){
// return -1;
// }else {
// return 0;
// }
// }
}
SetDemo.java:
public class SetDemo implements Comparator<Person>{
public static void main(String[] args) {
TreeSet treeSet = new TreeSet(new SetDemo());
treeSet.add(new Person("ooop", 12));
treeSet.add(new Person("io", 9));
treeSet.add(new Person("kdlsjf", 17));
treeSet.add(new Person("fio", 14));
System.out.println(treeSet);
}
@Override
public int compare(Person o1, Person o2) {
if (o1.getAge()>o2.getAge()){
return 1;
}else if (o1.getAge()<o1.getAge()){
return -1;
}else {
return 0;
}
}
}
注意:
如果两者同时存在,使用外部比较器。
当使用比较器的时候,不会调用equals方法。
泛型
当做一些集合的统一操作的时候,需要保证集合的类型是统一的,此时需要泛型来进行限制。
给集合中的元素设置相同的类型就是泛型的基本需求。
在定义对象的时候,通过<>中设置合理的类型来进行实现。
-优点:
1.数据安全;
2.获取数据时,效率高。
泛型的高阶用法:
1.泛型类
类中的方法的返回值类型和属性的类型都可以使用。
public class FanXingClass <A>{
private int id;
private A a;
}
2.泛型接口
(1)子类在进行实现的时候,可以不填写反省类型,此时在创建具体的子类对象的时候才决定使用什么类型。
FanXingDemo.java:
-
FanXingInterfaceSub<Integer> fxi=new FanXingInterfaceSub<Integer>(); fxi.test2(123);
FanXingInterfaceSub.java:
-
public class FanXingInterfaceSub<String> implements FanXingInterface<String>{
(2)子类在实现泛型接口的时候,只在实现父类接口的时候指定父类的泛型类型即可,此时测试方法中的泛型类型必须跟子类保持一致。
-
public class FanXingInterfaceSub implements FanXingInterface<String>{
3.泛型方法
在定义方法的时候,指定方法的返回值和参数是自定义的占用位,可以是类名中的T,也可以是自定义的Q,在返回值前面。
FanXingMethod:
public class FanXingMethod <T>{
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public <Q> void show(Q q){
System.out.println(q);
System.out.println(t);
}
}
4.泛型的上限
如果父类确定了,所有的子类都可以直接使用。
5.泛型的下限
如果子类确定了,子类的所有父类都可以直接传递参数使用。