目录
一、集合
集合和数组都为容器,有何不同?
- 数组虽为容器,但是数组的长度是固定的;集合长度是不固定的。
- 数组存储的是基本数据类型,集合存储的是对象(引用数据类型)。
集合特点:集合只存储对象,集合长度是可变的,集合可以存储不同类型的对象。
添加元素,参数类型为Object,以便接收任意类型对象。
集合中存储的都是对象的引用(地址)
打印集合名,eg:System.out.println(list);打印出来的是封装在[ ]之间,以“,”隔开的,已添加在集合中的对象内容。
常用集合分类图
证实集合中存储的是对象的引用:
import java.util.ArrayList;
import java.util.List;
/**
*
* 证实集合中存储的是对象的引用
*/
public class Demo1 {
public static void main(String[] args) {
List<Student> list1=new ArrayList<>();
List<Student> list2=new ArrayList<>();
Student stu=new Student();
list1.add(stu);
list2.add(stu);
for(Student s:list2){
s.setId(10);
s.setName("zhangsan");
}
for(Student s:list1){
System.out.println(s.getId()+","+s.getName());
}
}
}
public class Student {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
相关基本操作:
添加元素:集合名.add();
删除元素:集合名.remove();
集合名.clear();//清空集合
判断长度:集合名.size();
判断元素:集合名.contains(元素);
集合名.isEmpty();//判断集合是否为空
取交集:集合1.retainAll(集合2)//集合1中只保留和集合2相同的部分
集合1.removeAll(集合2)//集合1中只保留和集合2不同的部分
遍历集合:迭代器Iterator
1.
for(Iterator it=集合.iterator();it.hasNext(); ){
System.out.println(it.next());
}
2.
Iterator it=集合.iterator();
while(集合.hasNext()){
System.out.println(it.next());
}
二、List
特点:元素有序,元素可以重复,因为该集合体系有索引。
ArrayList——底层数据结构为数组结构;线程不安全
特点:查询快,增删慢
LinkedList——底层数据结构是链表结构;线程不安全
特点:查询慢,增删快
Vector——底层数据结构是数组结构;线程安全
特点:增删查询都比较慢(后被ArrayList代替)
List集合的特有方法( 凡是可以操作角标的方法都是List集合体系特有的方法)
增:add(index,element)
addAll(index,Collection)
删:remove(index)
改:set(index,element)
查:get(index)
subList(from,to)//获取角标from到to这段元素(包含前不包含尾)
ListIterator();列表迭代器
//获取所有元素
for(int x=0;x<集合.size;x++){
System.out.pritnln(集合.get(x));
}
并发访问:在迭代过程中,添加或删除元素,会引发并发修改异常
eg:在集合al中含有元素Java01,Java02,Java03;
Iterator it=al.iterator();
while(it.hasNext()){
Object obj=it.next();
if(obj.equals("java2")){
al.add("Java0005");
}
System.out.println(obj);进行判断
}
由上述示例可知:Iterator有局限性(在遍历过程中,只能进行判断,取出,移除 )。所以引出了列表迭代器(ListIterator,是Iterator的子接口,List特有的迭代器)。
在迭代时,不可以通过集合对象的方法操作集合中的元素,否则会引起并发修改异。只能使用迭代器的方法操作元素,可是Iterator的方法是有限的,只能对元素进行判断,取出,删除操作。如果想要其他操作(如添加,修改等),就需要使用其子接口ListIterator。
ListIterator的特有方法:hasPrevious()逆向遍历列表。
1.Vector
枚举是Vector特有的方法(其实枚举和迭代是一样的);
由于枚举的名称以及方法的名称都过于长。
Enumeration en=v.elements();//e为集合名称
while(en.hasMoreElements()){
System.out.println(en.nextElement());
}
举例说明:
package listPackage;
import java.util.Enumeration;
import java.util.Vector;
public class Demo2 {
public static void main(String[] args) {
Vector<Student> v=new Vector<>();
Student stu1=new Student(1,"zhangsan");
Student stu2=new Student(2,"lisi");
Student stu3=new Student(3,"wangwu");
v.add(stu1);
v.add(stu2);
v.add(stu3);
Enumeration en=v.elements();
while(en.hasMoreElements()){
System.out.println(en.nextElement());
}
}
}
public class Student {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
输出:
Student{id=1, name='zhangsan'}
Student{id=2, name='lisi'}
Student{id=3, name='wangwu'}
2.LinkedList
- 添加方法:
addFirst()//从链表集合的最前面添加进链表
addLast()//从链表集合的最后面添加进链表
- 获取元素(不删除元素)
getFirst()//获取链表集合的第一个元素
getLast()//获取链表集合的最后一个元素
如果链表集合中没有元素,会出现NoSuchElementException
- 获取元素(删除元素)
removeFirst()//返回链表集合的第一个元素(该元素会从链表中移除)
removeLast()//返回链表集合的最后一个元素(该元素会从链表中移除)
如果链表集合中没有元素,会出现NoSuchElementException
在JDK1.6出现了以上方法的替代方法:
- 添加方法:
offerFirst()//从链表集合的最前面添加进链表
OfferLast()//从链表集合的最后面添加进链表
- 获取元素(不删除元素)
peekFirst()//获取链表集合的第一个元素
peekLast()//获取链表集合的最后一个元素
如果链表集合中没有元素,会返回Null
- 获取元素(删除元素)
pollFirst()//返回链表集合的第一个元素(该元素会从链表中移除)
pollLast()//返回链表集合的最后一个元素(该元素会从链表中移除)
如果链表集合中没有元素,会返回Null
遍历元素
while(!link.isEmpty()){
System.out.println(link.getFirst())
}
利用LinkedList完成队列和堆栈的模拟:
https://blog.csdn.net/The_Best_Hacker/article/details/89954983
三、Set
特点:元素是无序的,存入与取出的顺序不一定一致,元素无重复。
HashSet——底层数据结构为哈希表;非线程安全
TreeSet——底层数据结构是二叉树;非线程安全
1.HashSet
HashSet中存入元素,保证元素的无重复,需要:
(1)重写hashCode()方法,改为自定义方法。因为HashSet存值是通过hash码开辟空间存的,所以改写的hashCode需返回同一个hash值。
如:
public int hashCode(){
return name.hashCode()+age*11;
//如果两元素哈希值不同,存入集合中; 若相同,调用equals方法,比较其内容是否相同,若相同则不存,
//若不同存入集合。
}
(2)调用equals方法比较
public boolean equals(Object obj){
if(!obj instanceof Person){
return false;
}
Person p=(Person)obj;
return this.name.equals(p.name)&&this.age==p.age;
}
举例:
package setPackage;
import java.util.HashSet;
import java.util.Set;
public class Demo1 {
public static void main(String[] args) {
Set<Student> set=new HashSet<>();
Student stu1=new Student(1,"zhangsan");
Student stu2=new Student(2,"lisi");
Student stu3=new Student(3,"wangwu");
Student stu4=new Student(1,"zhangsan");
set.add(stu1);
set.add(stu2);
set.add(stu3);
set.add(stu4);
for(Student stu:set){
System.out.println(stu.toString());
}
}
}
public class Student {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public int hashCode(){
return id+name.hashCode();
}
public boolean equals(Object obj){
if(!(obj instanceof Student)){
return false;
}
Student stu=(Student)obj;
return this.name.equals(stu.name)&&this.id==stu.id;
}
}
输出:
Student{id=2, name='lisi'}
Student{id=1, name='zhangsan'}
Student{id=3, name='wangwu'}
总结:
HashSet如何保证元素的唯一性?
HashSet是通过hashCode方法和equals方法完成的。
对于判断元素是否存在,依赖的是元素的hashCode和equals方法。
2.TreeSet
可以对Set集合中的元素进行排序。注意:排序时,当主要条件相同时,一定要判断次要条件。TreeSet自身会除掉重复元素,不需要重写方法。
TreeSet排序的第一种方式(Compareable):让元素自身具备比较性。元素需要实现Comparable接口,覆盖CompareTo方法。这种方式也称为元素的自然排序或者叫做默认排序。
TreeSet排序的第二种方式(Comparator):当元素自身不具有比较性,或者具备的比较性不是做需要的。这时就需要让集合自身具备比较性(例如:Set<Student> set=new TreeSet<>(new MyComparator))。在集合初始化时,就有了比较方式。定义比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。定义一个类实现Comparator接口,覆盖compare方法。
当两种排序都存在的时候(按元素排序,按集合排序),以比较器Comparator为主。
例如:
package setPackage;
import java.util.Set;
import java.util.TreeSet;
public class Demo3 {
public static void main(String[] args) {
Set<Person> ts=new TreeSet<>(new MyCompare());
Person t1=new Person(12,"zhangsan");
Person t2=new Person(21,"lisi");
Person t3=new Person(33,"wangwu");
Person t4=new Person(14,"zhangsan");
Person t5=new Person(12,"zhangsan");
ts.add(t1);
ts.add(t2);
ts.add(t3);
ts.add(t4);
ts.add(t5);
for(Person p:ts){
System.out.println(p.toString());
}
}
}
package setPackage;
public class Person implements Comparable{
//排序方式,按照id的大小排序
private int id;
private String sname;
public Person(int id, String sname) {
this.id = id;
this.sname = sname;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", sname='" + sname + '\'' +
'}';
}
public int compareTo(Object obj){
if(!(obj instanceof Person)){
throw new RuntimeException("非人类信息");
}
Person stu=(Person)obj;
if(this.id>stu.id){
return 1;
}
if(this.id==stu.id){
return this.sname.compareTo(stu.sname);
}
return -1;
}
}
package setPackage;
import java.util.Comparator;
public class MyCompare implements Comparator {
//排序方式:按照人名的字母排序
public int compare(Object obj1,Object obj2){
if(!((obj1 instanceof Person)||(obj2 instanceof Person))){
throw new RuntimeException("含有不属于人的信息");
}
Person t1=(Person)obj1;
Person t2=(Person)obj2;
int num=t1.getSname().compareTo(t2.getSname());
if(num==0){
return t1.getId()-t2.getId();
}
return num;
}
}
输出:
Student{id=21, sname='lisi'}
Student{id=33, sname='wangwu'}
Student{id=12, sname='zhangsan'}
Student{id=14, sname='zhangsan'}
具体示例见:https://blog.csdn.net/The_Best_Hacker/article/details/89970061
若要输出集合(怎样加进去,怎样输出来,即:先入先出)
public int compareTo(Object obj){
return 1;
}
若要输出集合(先入后出)
public int compareTo(Object obj){
return -1;
}
四、Map
Map集合:该集合存储键值对。一对一对的存,而且要保证键的唯一性。(键与值之间用=相连)。
HashTable——底层数据结构是哈希表,不可以存入null作为键值。(同步安全,效率低)
HashMap——底层数据结构是哈希表,可以存入null键和null值。(不同步不安全,效率高)
TreeMap——底层数据结构是二叉树,可以用于给Map中的键进行排序。(不同步不安全,效率高)
常用方法:
- 1.添加
put(k,v):返回键对应的原来值,刚开始添加的时候,返回的是null,若是同一键值,则后添加的会覆盖原有的键值,并返回被覆盖的值
putAll(Map<? extends K,? extends Value> m):向集合中添加元素,元素为集合类型
- 2.删除
clear()//清空集合
remove(Object obj)//删除键对应的元素,若集合不存在key,则返回null
- 3.判断
containsValue(Object value)//判断集合是否存在value
containsKey(Object key)//判断集合是否存在key
isEmpty()//判断集合是否为空
- 4.获取
get(Object key)//可以通过get方法返回值判断一个值是否存在,通过返回null来判断。
size()//获取集合的大小,包含多少个元素
values()//返回的是一个包含所有value的集合
遍历集合
keySet:将map中所有键存入Set集合中,因为Set集合具备迭代器。
Set<String> keySet=map.keySet();
Iterator it=keySet.iterator();
while(it.hasNext()){
System.out.println(map.get(it.next()));
}
Map集合的取出原理:将map集合转成set集合,再通过迭代器取出。
entrySet:将map集合的映射关系存入到Set集合,而这个关系的数据类型为Map.Entry
Set<Map.Entry<String,String>> entrySet=map.entrySet();
Iterator<Map.Entry<String,String>> it=entrySet.iterator();
while(it.hasNext()){
Map.Entry<String,String> me=it.next();
System.out.println(me.getKey()+"...."+me.getValue());
}
Map集合的取出原理:先获取Map.Entry关系,在通过Map.Entry中的getKey()和getValue()方法获取关系中的键和值。
举例:
package mapPackage;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo1 {
public static void main(String[] args) {
Map<Integer,String> map=new Hashtable<>();
map.put(1,"我爱学习");
map.put(2,"沉迷学习");
map.put(3,"无法自拔");
map.put(1,"学习爱我");
/* //遍历集合:通过迭代器遍历
Set<Integer> set=map.keySet();
Iterator it=set.iterator();
while(it.hasNext()){
System.out.println(map.get(it.next()));
}
无法自拔
沉迷学习
学习爱我
*/
//entrySet:将map集合的映射关系存入到Set集合,而这个关系的数据类型为Map.Entry
Set<Map.Entry<Integer,String>> entry=map.entrySet();
Iterator<Map.Entry<Integer,String>> it=entry.iterator();
while(it.hasNext()){
Map.Entry<Integer,String> me=it.next();
System.out.println(me.getKey()+","+me.getValue());
}
}
}
输出:
3,无法自拔
2,沉迷学习
1,学习爱我