集合
生活中也有集合的概念,是一个动词
Java中的集合是一个名词,是数据的一种容器,用于容纳数据
java提供了完整的集合框架
问题1:什么时候需要一个容纳数据的容器,也就是集合对象呢?
当存储的数据个数不确定的时候需要用
问题2:如果只是为了容纳数据,可以是直接使用数组,为什么要学习集合?
数组使用起来不方便,在数据个数不确定的场合,数组使用起来不是很方便
总结:
对不确定的有关系的数据进行相同逻辑处理的场合,使用集合是一个不错的选择
集合分类
根据数据的不同,Java集合分为两大体系
单一数据体系:Collection接口定义了相关的规则
成对出现的数据体系:Collection接口定义了相关的规则
所谓的成对的数据,就是2个数据有关系,可以根据第一个数据关联到第二个数据
也称之为键值对数据,(123123,zhangsan) ->(key , value)
Collection和Map接口
Collection常用的子接口
List:按照插入顺序保存数据,数据可以重复
具体的实现类:ArrayList,LinkedList
Set:集,无序保存,数据不能重复
具体的实现类:HashSet
Queue:队列
具体的实现类:ArrayBlockingQueue
Map常用的子接口
具体的实现:HashMap,Hashtable
Collection - ArrayList
ArrayList: Array + List
List:列表,清单,按照插入顺序进行存储
Array:数组,阵列
创建第一个集合对象
ArrayListlist=newArrayList();
ArrayList的增删改查
//增加数据 add方法可以增加数据,只要将数据作为参数传递到add方法即可
//添加数据时,如果集合中没有任何的数据,那么底层会创建长度为10的数组
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.add("zhaoliu");
//获取集合中数据的条数
System.out.println(list.size());
//获取指定位置的数据,采取索引的方式
System.out.println(list.get(1));
//打印集合对象
System.out.println(list);
//遍历集合中的数据
for (inti=0; i<list.size(); i++) {
System.out.println("集合中的数据:"+list.get(i));
}
//如果循环遍历集合数据时,不关心数据的位置,那么可以采用特殊的for循环
for(Objectobj : list){
System.out.println(obj);
}
//将指定位置的数据进行修改,set方法需要传递两个参数,第一个参数表示数据的位置,第二个参数修改的值。
//方法会返回结果,这个结果就是更新前的值
list.set(1,"llllaaa");
//删除数据
list.remove(1);
ArrayList常用方法
ArrayListlist=newArrayList();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
//add方法可以传递两个参数的,第一个参数表示数据增加的位置(索引).第二个参数表示数据
list.add(1,"shuaige");
ArrayList<Object>list1=newArrayList<>();
list1.add("a");
list1.add("b");
list1.add("c");
list.addAll(list1);
System.out.println(list);
//size方法表示集合内部数据的数量
System.out.println(list.size());
//判断集合是否为空
System.out.println(list.isEmpty());
//清空集合
// list.clear();
//删除指定集合中的数据
// list.removeAll(list1);
//判断是否存在某条数据
list.contains("shuaige");
//判断数据在集合中的索引位置,如果不存在表示-1
//如果有两个相同的数据返回的是数据在索引中的第一位置
System.out.println(list.indexOf("zhangsan"));
//将集合转为数组
Object[] objects=list.toArray();
//克隆,复制新集合
Objectclone=list.clone();
ArrayListlist2= (ArrayList) clone;
Collection-LinkedList
LinkedList : Linked + List
Linked: 连接 数据存储和管理的一种方式
LinkedList基本操作
LinkedListlist=newLinkedList();
//增加数据
list.add("zhangsan");
list.addFirst("lisi");
list.add(1,"wangwu");
//获取数据
System.out.println(list.getFirst());
System.out.println(list.getLast());
//遍历数据
System.out.println(list.get(1));
for (inti=0; i<list.size(); i++) {
//System.out.println(list.get(i));
}
//增强for循环
for (Objectobj :list){
System.out.println(obj);
}
//修改数据
list.set(1,"lalala");
//删除数据
list.remove("zhangsan");
//打印集合数据
System.out.println(list);
LinkedList常用方法
LinkedListlist=newLinkedList();
LinkedListlist1=newLinkedList();
//追加数据
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
//向指定位置追加数据
list.add(1,"zhaoliu");
list.addFirst("1");
list.addLast("2");
//向集合里面追加集合
list.addAll(list1);
//删除
list.remove();//删除第一个
list.removeFirst();
list.removeLast();
list.remove(1);
System.out.println(list.size());
System.out.println(list.isEmpty());
list.clear();
list.contains("a");
list.element();//获取第一个数据
list.push("aaaa"); //添加到第一个
list.pop(); //弹出数据
泛型
泛型概述:
Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
常见形式有泛型类、泛型接口、泛型方法。
语法:
<T,…> T称为类型占位符,表示一种引用类型。
好处:
提高代码的重用性。
防止类型转换异常,提高代码的安全性。
泛型类
/**
* 泛型类
* 语法:类名<T>
* T是类型占位符,表示一种引用类型,编写多个使用逗号隔开
*
*/
publicclassmyGeneric<T>{
//1.创建泛型变量
//不能使用new来创建,因为泛型是不确定的类型,也可能拥有私密的构造方法。
Tt;
//2.泛型作为方法的参数
publicvoidshow(Tt) {
System.out.println(t);
}
//泛型作为方法的返回值
publicTgetT() {
returnt;
}
}
/**
* 注意:
* 1.泛型只能使用引用类型
* 2.不同泛型类型的对象不能相互赋值
*/
publicclasstestGeneric {
publicstaticvoidmain(String[] args) {
//使用泛型类创建对象
myGeneric<String>myGeneric1=newmyGeneric<String>();
myGeneric1.t="tang";
myGeneric1.show("he");
myGeneric<Integer>myGeneric2=newmyGeneric<Integer>();
myGeneric2.t=10;
myGeneric2.show(20);
Integerinteger=myGeneric2.getT();
}
}
泛型接口
/**
* 泛型接口
* 语法:接口名<T>
* 注意:不能创建泛型静态常量
*/
publicinterfaceMyInterface<T> {
//创建常量
StringnameString="tang";
Tserver(Tt);
}
/**
* 实现接口时确定泛型类
*/
publicclassMyInterfaceImplimplementsMyInterface<String>{
@Override
publicStringserver(Stringt) {
System.out.println(t);
returnt;
}
}
//测试
MyInterfaceImplmyInterfaceImpl=newMyInterfaceImpl();
myInterfaceImpl.server("xxx");
//xxx
/**
* 实现接口时不确定泛型类
*/
publicclassMyInterfaceImpl2<T>implementsMyInterface<T>{
@Override
publicTserver(Tt) {
System.out.println(t);
returnt;
}
}
COPY//测试
MyInterfaceImpl2<Integer>myInterfaceImpl2=newMyInterfaceImpl2<Integer>();
myInterfaceImpl2.server(2000);
//2000
泛型方法
/**
* 泛型方法
* 语法:<T> 返回类型
*/
publicclassMyGenericMethod {
public<T>voidshow(Tt) {
System.out.println("泛型方法"+t);
}
}
COPY//测试
MyGenericMethodmyGenericMethod=newMyGenericMethod();
myGenericMethod.show("tang");
myGenericMethod.show(200);
myGenericMethod.show(3.14);
泛型集合
概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
特点
编译时即可检查,而非运行时抛出异常。
访问时,不必类型转换(拆箱)。
不同泛型指尖引用不能相互赋值,泛型不存在多态。
比较器
publicclassCompareDemo {
publicstaticvoidmain(String[] args) {
ArrayListarrayList=newArrayList();
arrayList.add(1);
arrayList.add(3);
arrayList.add(2);
arrayList.sort(newNumberComparator());
}
}
classNumberComparatorimplementsComparator<Integer> {
@Override
publicintcompare(Integero1, Integero2) {
//如果第一个数比第二个数要大,那么返回结果为正数,表示升序
//如果第一个数比第二个数要小,那么返回结果为负数,表示升序
//如果第一个数和第二个数相等,那么返回0
returno1-o2;
}
}
}
ArrayList和LinkerList对比
ArrayList:必须开辟连续空间,查询快,增删慢。
LinkedList:无需开辟连续空间,查询慢,增删快。
HashSet
特点:无序、无下标、元素不可重复。
方法:全部继承自Collection中的方法。
底层结构:数组+链表
基本操作如下:
HashSetset=newHashSet();
//增加数据
set.add("zhangsan");
set.add("zhangsan");
set.add("lisi");
set.add("wangwu");
//修改数据 不能修改数据
//删除数据
set.remove("wangwu");
//查询数据
for (Objecto : set) {
System.out.println(o);
基于HashCode计算元素存放位置。
当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入。
注:hashSet存储过程:
根据hashCode计算保存的位置,如果位置为空,则直接保存,否则执行第二步。执行equals方法,如果方法返回true,则认为是重复,拒绝存储,否则形成链表。存储过程实际上就是重复依据,要实现“注”里的问题,可以重写hashCode和equals代码:
@Override
publicinthashCode() {
finalintprime=31;
intresult=1;
result=prime*result+age;
result=prime*result+ ((name==null) ?0 : name.hashCode());
returnresult;
}
@Override
publicbooleanequals(Objectobj) {
if (this==obj)
returntrue;
if (obj==null)
returnfalse;
if (getClass() !=obj.getClass())
returnfalse;
Personother= (Person) obj;
if (age!=other.age)
returnfalse;
if (name==null) {
if (other.name!=null)
returnfalse;
} elseif (!name.equals(other.name))
returnfalse;
returntrue;
}
Queue
// ArrayBlockingQueue: Array + Blocking(阻塞,堵住) + queue
ArrayBlockingQueuequeue=newArrayBlockingQueue(3);
// queue.add("zhangsan");
// queue.add("lisi");
// queue.add("wangwu");
// queue.add("wangwu");//发生错误,Queue full
// queue.put("zhangsan");
// System.out.println("第一个人挂号");
// queue.put("lisi");
// System.out.println("第二个人挂号");
// queue.put("wangwu");
// System.out.println("第三个人挂号");
// queue.put("zhaoliu");
// System.out.println("第四个人挂号");
//添加数据
queue.offer("zhangsan");
queue.offer("zhangsan");
queue.offer("zhangsan");
//取数据
queue.poll();//返回布尔类型
queue.take();//会阻塞 等进入再取
System.out.println(queue);
HashMAP
HashMap一旦循环遍历时,那么增删数据,就会发生错误
publicclassStudent {
privateStringname;
privateintid;
publicStudent(Stringname, intid) {
super();
this.name=name;
this.id=id;
}
publicStringgetName() {
returnname;
}
publicvoidsetName(Stringname) {
this.name=name;
}
publicintgetId() {
returnid;
}
publicvoidsetId(intid) {
this.id=id;
}
@Override
publicStringtoString() {
return"Student [name="+name+", age="+id+"]";
}
}
HashMap<Student, String>hashMap=newHashMap<Student, String>();
Students1=newStudent("tang", 36);
Students2=newStudent("yu", 101);
Students3=newStudent("he", 10);
//1.添加元素
hashMap.put(s1, "成都");
hashMap.put(s2, "杭州");
hashMap.put(s3, "郑州");
//添加失败,但会更新值
hashMap.put(s3,"上海");
//添加成功,不过两个属性一模一样;
//注:假如相同属性便认为是同一个对象,怎么修改?
hashMap.put(newStudent("he", 10),"上海");
System.out.println(hashMap.toString());
//2.删除元素
hashMap.remove(s3);
System.out.println(hashMap.toString());
//3.遍历
//3.1 使用keySet()遍历
for (Studentkey : hashMap.keySet()) {
System.out.println(key+" "+hashMap.get(key));
}
//3.2 使用entrySet()遍历
for (Entry<Student, String>entry : hashMap.entrySet()) {
System.out.println(entry.getKey()+" "+entry.getValue());
}
//4.判断
//注:同上
System.out.println(hashMap.containsKey(newStudent("he", 10)));
System.out.println(hashMap.containsValue("成都"));
HashMap和Hashtable区别
实现方式不一样:继承父类不同
底层结构容量不同:HashMap(16),Hashtable(11)
HashMap的K,V都可以为null , Hashtable不可以
HashMap的数据定位采用的是Hash算法,但是Hashtable采用的是Hashcode
HashMap性能较高,Hashtable性能较低
迭代器
HashMap<String, Integer>map=newHashMap<String,Integer>();
map.put("zs",1);
map.put("ls",2);
map.put("ww",3);
Set<String>keys=map.keySet();
//迭代器
Iterator<String>iterator=keys.iterator();
// hasNext方法用于判断是否存在下一条数据
while (iterator.hasNext()){
//获取下一条数据
Stringkey=iterator.next();
if ("ls".equals(key)){
//remove方法只能对当前数据进行删除
iterator.remove();
}
System.out.println(map.get(key));
}
工具类
List<Integer>list=newArrayList<Integer>();
list.add(20);
list.add(10);
list.add(30);
list.add(90);
list.add(70);
//sort排序
System.out.println(list.toString());
Collections.sort(list);
System.out.println(list.toString());
System.out.println("---------");
//binarySearch二分查找
inti=Collections.binarySearch(list, 10);
System.out.println(i);
//copy复制
List<Integer>list2=newArrayList<Integer>();
for(inti1=0;i1<5;++i1) {
list2.add(0);
}
//该方法要求目标元素容量大于等于源目标
Collections.copy(list2, list);
System.out.println(list2.toString());
//reserve反转
Collections.reverse(list2);
System.out.println(list2.toString());
//shuffle 打乱
Collections.shuffle(list2);
System.out.println(list2.toString());
//补充:list转成数组
Integer[] arr=list.toArray(newInteger[0]);
System.out.println(arr.length);
//补充:数组转成集合
String[] nameStrings= {"tang","he","yu"};
//受限集合,不能添加和删除
List<String>list3=Arrays.asList(nameStrings);
System.out.println(list3);