为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方法。
数组和集合类同是容器,有何不同?
数组虽然也可以存储对象,但长度是固定的,集合长度是可变的;数组中可以存储基本数据类型,集合只能存储对象。
集合类的特点:
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
1.集合框架的构成及分类:
Java中集合类的关系图:(如下所示)
2.集合框架中的常用接口:
Collection接口有两个子接口:
List(列表)、Set(集)
List:可存放重复元素,元素存取是有序的
Set:不可以存放重复元素,元素存储是无序的
3.常用类:
◆List接口中常用类:
·Vector:线程安全,但速度慢,已经被ArrayList替代
·ArrayList:线程不安全,查询速度快
·LinkedList:链表结构,增删速度快
◆Set接口中常用的类
HashSet:线程不安全,存取速度快
TreeSet:线程不安全,可以对Set集合中元素进行排序
4.Collection定义了集合框架的共性功能:
●添加:
boolean
add(E e)——添加一个元素
boolean
addAll(collection)——添加一个集合
示例:
class CollectionDemo {
public static void main(String[] args) {
// 新建一个ArrayList
ArrayList al1 = new ArrayList();
// 每次添加一个元素
al1.add("java001");
al1.add("java002");
al1.add("java003");
System.out.println(al1); // 结果:[java001,java002, java003]
ArrayList al2 = new ArrayList();
// 添加集合
al2.addAll(al1);
System.out.println(al2); // 结果:[java001,java002, java003]
}
}
●删除:
boolean
remove(intindex)——按索引移除
boolean
removeAll(collection)——移除一个集合
void clear()——清空集合
示例:
class CollectionDemo {
public static void main(String[] args) {
//新建一个ArrayList
ArrayList al1 = new ArrayList();
//添加四个元素
al1.add("java001");
al1.add("java002");
al1.add("java003");
al1.add("java004");
System.out.println(al1); // 结果:[java001, java002, java003, java004]
//删除脚标为2的元素
al1.remove(2);
System.out.println(al1); // 结果:[java001, java002, java004]
ArrayList al2 = new ArrayList();
al2.add("java001");
al2.add("java002");
//删除一个集合
al1.removeAll(al2);
System.out.println(al1); //结果:[java004]
//清空集合
al2.clear();
System.out.println(al2); // 结果:[]
}
}
●判断:
boolean
contains(Objecto)——判断集合是否包含o元素
boolean
isEmpty()——判断集合是否为空
示例:
class CollectionDemo {
public static void main(String[] args) {
//新建一个ArrayList
ArrayList al1 = new ArrayList();
//添加四个元素
al1.add("java001");
al1.add("java002");
al1.add("java003");
al1.add("java004");
ArrayList al2 = new ArrayList();
System.out.println(al1); // 结果:[java001, java002, java003,java004]
//判断al1中是否包含元素java003
System.out.println(al1.contains("java003")); // 结果:true。表示存在这个元素
//判断al1中是否包含元素java007
System.out.println(al1.contains("java007")); // 结果:false。表示不存在这个元素
//判断al1是否为空
System.out.println(al1.isEmpty()); // 结果:false。表示al1不为空
//判断al2是否为空
System.out.println(al2.isEmpty()); // 结果:true。表示al2为空
}
}
●获取:
intsize()——获取集合长度
Eget(int index)——获取index位置的元素
Iteratoriterator()——迭代元素
示例:
class CollectionDemo {
public static void main(String[] args) {
//新建一个ArrayList
ArrayList al1 = new ArrayList();
//添加四个元素
al1.add("java001");
al1.add("java002");
al1.add("java003");
al1.add("java004");
// 获取al1的长度
System.out.println("size="+ al1.size());
// 获取指定指定位置的元素
System.out.println("脚标为2的元素为:" + al1.get(2));
// 获取al1中的元素
for (Iterator it = al1.iterator();it.hasNext();) {
System.out.println(it.next());
}
}
}
运行结果:
size=4
脚标为2的元素为:java003
java001
java002
java003
java004
●获取交集:
boolean
retainAll(collection)
示例:
class CollectionDemo {
public static void main(String[] args) {
//新建一个ArrayList
ArrayList al1 = new ArrayList();
//添加四个元素
al1.add("java001");
al1.add("java002");
al1.add("java003");
al1.add("java004");
System.out.println("al1="+ al1); // 结果:al1=[java001, java002, java003, java004]
ArrayList al2 = new ArrayList();
al2.add("java001");
al2.add("java004");
al2.add("java009");
System.out.println("al2="+ al2); // 结果:al2=[java001, java004, java009]
//al1与al2取交集并打印
al1.retainAll(al2);
System.out.println(al1); // 结果:[java001, java004]
ArrayList al3 = new ArrayList();
al3.add("java006");
al3.add("java009");
//al1与al3取交集并打印
al1.retainAll(al3);
System.out.println(al1); // 结果:[]
}
}
●集合变数组:
T[]toArray(T[] a);
示例:
class CollectionDemo {
public static void main(String[] args) {
//新建一个ArrayList
ArrayList al1 = new ArrayList();
//添加四个元素
al1.add("java001");
al1.add("java002");
al1.add("java003");
al1.add("java004");
System.out.println("al1="+ al1);
//将al1转成Object数组
Object[] obj=al1.toArray();
//System.out.println(obj);
//遍历数组
for(int x=0;x
运行结果:
al1=[java001,java002, java003, java004]
java001
java002
java003
java004
附注:集合中存储的都是对象的引用(地址)
5.迭代:
从上面的获取的例子中看到获取List集合的方式有:
get(intindex):通过脚标获取元素
iterator():通过迭代方法获取迭代器对象
那什么是迭代器呢?
就是取出集合中元素的一种方式,会直接访问集合中的元素,所以将迭代器通过内部类的形式来进行描述,通过容器的iterator()方法获取该内部类的对象。
因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器
使用格式:
(一)
for(Iteratoriter=l.iterator();iter.hasNext();){
System.out.println(it.next());
}
(二)
Iteratoriter=i.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
注意:
两种方式的区别——第一种方式比较节省内存,因为for循环中的变量用完就释放了,while则还在内存中存在,建议使用第一种方式
迭代注意事项:
·迭代器在Collection接口中是通用的,它替代了Vector类中的Eunmeration(枚举);
·迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException;
·迭代器的next方法返回值类型是Object,所以要记得类型转换。
思考:为什么next方法的返回值类型是Object的呢?——因为集合中存储的元素是任意类型,既可以是字符串,也可以是对象,也可以是整型。
6.List集合:
◆ArrayList:
底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢;线程不同步。
◆LinkedList:
底层使用的链表数据结构。特点:增删速度很快,查询稍慢;线程不同步。
◆Vector:
底层是数组数据结构。因为效率低,被ArrayList替代了;线程同步。
★List特有方法介绍:
●增:
void add(index,element)——在指定位置插入指定元素
boolean addAll(index,Collection)——在指定位置插入集合
示例:
class ArrayListDemo {
public static void main(String[] args) {
List l1 = new ArrayList();
l1.add("java01");
l1.add("java02");
l1.add("java03");
l1.add("java04");
System.out.println(l1); // 结果:[java01, java02, java03,java04]
// 在脚标为2的位置插上元素java05
l1.add(2, "java05");
System.out.println(l1); // 结果:[java01, java02, java05,java03, java04]
List l2 = new ArrayList();
l2.add("java201");
l2.add("java202");
l2.add("java203");
l2.add("java204");
System.out.println(l2); // 结果:[java201, java202,java203, java204]
// 在l2脚标为2的位置上将l1集合插进去
l2.addAll(2, l1);
System.out.println(l2); // 结果:[java201, java202,java01, java02, java05, java03, java04, java203, java204]
}
}
●删:
E remove(intindex)——移除列表中指定位置的元素
示例:
class ArrayListDemo {
public static void main(String[] args) {
List l1 = new ArrayList();
l1.add("java01");
l1.add("java02");
l1.add("java03");
l1.add("java04");
System.out.println(l1); // 结果:[java01, java02, java03, java04]
// 移除脚标为2的元素
l1.remove(2);
System.out.println(l1); // 结果:[java01, java02, java04]
}
}
●改:
E set(index,element)——用指定元素替换列表中指定位置的元素
示例:
class ArrayListDemo {
public static void main(String[] args) {
List l1 = new ArrayList();
l1.add("java01");
l1.add("java02");
l1.add("java03");
l1.add("java04");
System.out.println(l1); // 结果:[java01, java02, java03, java04]
// 把脚标为2的元素改成java999
l1.set(2, "java999");
System.out.println(l1); // 结果:[java01, java02, java999, java04]
}
}
●查:
E get(index)——获取列表中指定位置的元素
List subList(from,to)——获取从from到to直接的元素
ListIterator listIterator()——返回列表元素的列表迭代器
int indexOf(obj)——获取指定元素的位置
示例:
class ArrayListDemo {
public static void main(String[] args) {
List l1 = new ArrayList();
l1.add("java01");
l1.add("java02");
l1.add("java03");
l1.add("java04");
l1.add("java05");
l1.add("java06");
l1.add("java07");
l1.add("java08");
System.out.println(l1);// 结果:[java01, java02, java03,java04, java05,java06, java07, java08]
// 获取脚标为3的元素
System.out.println(l1.get(3)); // 结果:java04
// 获取脚标从2到4的子集合
System.out.println(l1.subList(2,5)); // 结果:[java03, java04, java05]
// 获取指定元素的位置
System.out.println(l1.indexOf("java07")); // 结果:6
//列表迭代器ListIterator获取元素
for(Iteratorli=l1.iterator();li.hasNext();){
System.out.print(li.next()+""); //结果:java01java02 java03 java04 java05 java06 java07 java08
}
//ListIterator可以对集合内容进行修改
for(ListIteratorli=l1.listIterator();li.hasNext();){
//System.out.println(li.next());
Objectobj=li.next();
if(obj.equals("java03"))
li.set("java009");
}
System.out.println("\r\n"+"修改后");
//再次获取l1中的元素
for(Iteratorli=l1.iterator();li.hasNext();){
System.out.print(li.next()+""); //结果:java01java02 java009 java04 java05 java06 java07 java08
}
}
}
总结:
List集合特有的迭代器ListIterator——是Iterator的子接口
在迭代时,不可以通过集合对象的方法操作结合中的元素,因为会产生ConcurrentModificationException异常,所以在迭代时,只能用迭代器的方法操作元素,但是Iterator方法功能是有限的,只能对元素进行判断、取出、删除的操作;如果想要其他的操作如添加、修改就需要使用其子接口ListIterator。
ListIterator还可以逆向遍历(对应使用hasPrevious()、previous())
练习一:(去除ArrayList集合中的重复元素)
思路:
通过迭代方式获取ArrayList中的元素,将获取到的元素添加到新的ArrayList集合中,通过contains判断是否存在,不存在就添加进新的集合中。
代码实现:
class ArrayListTest {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java01");
al.add("java03");
System.out.println(al); // 结果:[java01, java02, java03, java01,java03]
al= singleElement(al);
System.out.println(al); // 结果:[java01, java02, java03]
}
public static ArrayList singleElement(ArrayList al) {
ArrayList newAl = new ArrayList();
for(Iterator it = al.iterator(); it.hasNext();) {
Objectobj = it.next();
//如果newAl中没有的话,就添加进去
if(!newAl.contains(obj))
newAl.add(obj);
}
return newAl;
}
}
练习二:(将自定义对象作为元素存到ArrayList中,并取出重复元素)
思路:
1.对学生进行描述,将数据封装进学生对象(同名同年龄视为同一个对象)
2.定义集合容器,将学生存入
3.取出元素
代码实现:
class 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 int getAge() {
return age;
}
public boolean equals(Object obj) {
if(!(obj instanceof Student))
return false;
Student s = (Student) obj;
return this.name.equals(s.name) && this.age == s.age;
}
}
class ArrayListTest {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add(newStudent("zhangsan01", 34));
al.add(newStudent("zhangsan02", 29));
al.add(newStudent("zhangsan01", 34));
al.add(newStudent("zhangsan04", 35));
al.add(newStudent("zhangsan02", 29));
for(Iterator it = al.iterator();it.hasNext();) {
Student s = (Student) it.next();
System.out.println(s.getName()+ ":" + s.getAge());
}
System.out.println("------");
al= singleElement(al);
for(Iterator it = al.iterator();it.hasNext();) {
Student s = (Student) it.next();
System.out.println(s.getName()+ ":" + s.getAge());
}
}
public static ArrayList singleElement(ArrayListal) {
ArrayList newAl = new ArrayList();
Iterator it = al.iterator();
while(it.hasNext()) {
Object obj = it.next();
if(!newAl.contains(obj))
newAl.add(obj);
}
return newAl;
}
}
运行结果:
zhangsan01:34
zhangsan02:29
zhangsan01:34
zhangsan04:35
zhangsan02:29
------
zhangsan01:34
zhangsan02:29
zhangsan04:35
★Vector演示:
class VectorDemo {
public static void main(String[] args) {
//创建一个Vector集合
Vector v = new Vector();
//添加元素
v.add("java01");
v.add("java02");
v.add("java03");
v.add("java04");
//通过枚举的方式取出元素
for(Enumeration en = v.elements(); en.hasMoreElements();) {
System.out.println(en.nextElement());
}
}
}
运行结果:
java01
java02
java03
java04
总结:
枚举就是Vector特有的取出方式,枚举和迭代器很像,实际是一样的。
但是因为枚举的名称以及方法的名称都过长,所以被迭代器取代了。
★LinkedList特有方法介绍:
●添加:
void addFirst(E e)——将指定元素插入此列表的开头;被offerFirst(E e)替代
void addLast(E e)——将指定元素添加到此列表的结尾;被offerLast(E e)替代
示例:
class LinkedListDemo {
public static void main(String[] args) {
LinkedList ll = new LinkedList();
ll.add("java01");
ll.add("java02");
ll.add("java03");
System.out.println(ll); // 结果:[java01, java02, java03]
//在ll开头插上元素javafirst01
ll.offerFirst("javafirst");
System.out.println(ll); // 结果:[javafirst, java01, java02,java03]
//在ll尾部插上元素javalast01
ll.offerLast("javalast");
System.out.println(ll); // 结果:[javafirst, java01, java02,java03,javalast]
}
}
●获取:如果集合中没有元素,会出现NoSuchElementException
E getFirst()——返回此列表的第一个元素;被peekFirst()替代
E getLast()——返回此列表的最后一个元素;被peekLast()替代
示例:
class LinkedListDemo {
public static void main(String[] args) {
LinkedListll = new LinkedList();
ll.add("java01");
ll.add("java02");
ll.add("java03");
System.out.println(ll); // 结果:[java01, java02, java03]
//获取第一个元素
System.out.println(ll.peekFirst()); // 结果:java01
//获取最后一个元素
System.out.println(ll.peekLast()); // 结果:java03
}
}
●删除:如果集合中没有元素,会出现NoSuchElementException
E removeFirst()——移除并返回此列表的第一个元素;被pollFirst()替代
E removeLast()——移除并返回此列表的最后一个元素;被pollLast()替代
示例:
class LinkedListDemo {
publicstatic void main(String[] args) {
LinkedList ll = new LinkedList();
ll.add("java01");
ll.add("java02");
ll.add("java03");
System.out.println(ll); // 结果:[java01, java02, java03]
//删除第一个元素
ll.pollFirst();
System.out.println(ll); // 结果:[java02, java03]
ll.pollLast();
System.out.println(ll); // 结果:[java02]
}
}
练习:(使用LinkedList模拟一个堆栈或者队列数据结构)
堆栈:先进后出
队列:先进先出
代码实现:
class DuiZhan {
private LinkedList link;
DuiZhan(){
link= new LinkedList();
}
public void myAdd(Object obj) {
link.addLast(obj);
}
//后进先出,从最后一个开始移除
public Object myGet() {
return link.removeLast();
}
public boolean isNull() {
return link.isEmpty();
}
}
class DuiLie {
private LinkedList link;
DuiLie(){
link= new LinkedList();
}
public void myAdd(Object obj) {
link.addLast(obj);
}
//先进先出,从第一个开始移除
public Object myGet() {
return link.removeFirst();
}
public boolean isNull() {
return link.isEmpty();
}
}
class LinkedListTest {
publicstatic void main(String[] args) {
//新建一个堆栈对象dz
DuiZhan dz = new DuiZhan();
dz.myAdd("php01");
dz.myAdd("php02");
dz.myAd("php03");
dz.myAdd("php04");
while(!dz.isNull()) {
System.out.println(dz.myGet());
}
System.out.println("--------");
//新建一个队列对象dl
DuiLie dl = new DuiLie();
dl.myAdd("java01");
dl.myAdd("java02");
dl.myAdd("java03");
dl.myAdd("java04");
while(!dl.isNull()) {
System.out.println(dl.myGet());
}
}
}
运行结果:
php04
php03
php02
php01
--------
java01
java02
java03
java04
7.Set集合
◆HashSet:
底层数据结构是哈希表。存取速度快,线程不安全的,不同步。
保证元素唯一性的原理:判断元素的hashCode值是否相同,如果相同,还会继续判断元素的equals方法,是否为true。
◆TreeSet:
底层数据结构是二叉树。线程不安全,不同步,可以对Set集合中元素进行排序。
保证元素唯一性的依据:compareTo方法return 0。
Set集合的功能和Collection是一致的
★HashSet讲解:
用程序验证set集合是无序的,元素不重复的
class HashSetDemo {
public static void main(String[] args) {
Set s=new HashSet();
s.add("java01");
s.add("java02");
s.add("java03");
s.add("java01");
s.add("java03");
System.out.println(s); //结果:[java03, java02, java01]
}
}
问:那么HashSet是如何保证元素唯一性的呢?
答:是通过元素的两个方法:hashCode()和equals()方法来完成的,如果元素的hashCode值相同的话,才会判断equals是否为true;如果hashCode值不同,不会调用equals。
附注:
对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法。
练习:(将自定义对象存入到HashSet中,姓名和年龄相同则为同一人,去除相同对象)
思路:通过复写hashCode和equals方法
代码实现:
class Person {
private String name;
private int age;
Person(String name, int age) {
this.name= name;
this.age= age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
//覆盖hashCode()
publicint hashCode() {
//System.out.println(this.name+"....hashCode");
return name.hashCode() + age * 30;
}
//覆盖equals()
publicboolean equals(Object obj) {
if(!(obj instanceof Person))
return false;
Personp = (Person) obj;
//System.out.println(this.name+"...equals.."+p.name);
return this.name.equals(p.name) && this.age == p.age;
}
}
class HashSetTest {
public static void main(String[] args) {
Set s=new HashSet();
s.add(newPerson("zhaoliu03",24));
s.add(newPerson("zhaoliu01",20));
s.add(newPerson("zhaoliu02",26));
s.add(newPerson("zhaoliu01",20));
s.add(newPerson("zhaoliu02",26));
for(Iterator it=s.iterator();it.hasNext();){
Person p=(Person)it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
}
运行结果:
zhaoliu01:20
zhaoliu02:26
zhaoliu03:24
★TreeSet讲解:
先看一个例子:
class TreeSetDemo {
public static void main(String[] args) {
Set s=new TreeSet();
s.add("bca");
s.add("b");
s.add("cba");
s.add("abcd");
s.add("aaa");
for(Iterator it=s.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
运行结果为:
aaa
abcd
b
bca
cba
我们从运行结果中不难发现:TreeSet默认排序方式是按照字母的自然顺序进行的
●第一种排序方式
让元素自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法,这种方式也称为元素的自然排序,或者叫做默认排序。
示例:(需求:往TreeSet集合中存储自定义对象学生,想按照学生的年龄进行排序)
class Student implements Comparable {
private String name;
private int age;
Student(String name, int age) {
this.name= name;
this.age= age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public int compareTo(Object obj) {
if(!(obj instanceof Student))
thrownew RuntimeException("不是学生对象");
Student s = (Student) obj;
//System.out.println(this.name+ "....compareto....." + s.name);
if(this.age > s.age)
return 1;
if(this.age == s.age)
return this.name.compareTo(s.name);
return -1;
}
}
class TreeSetDemo {
public static void main(String[] args) {
Set s = new TreeSet();
s.add(newStudent("zhaoliu", 20));
s.add(newStudent("liusan", 22));
s.add(newStudent("lisi", 20));
s.add(newStudent("chenze", 22));
s.add(newStudent("qianyi", 24));
for(Iterator it = s.iterator(); it.hasNext();) {
Student stu = (Student) it.next();
System.out.println(stu.getName()+ ":" + stu.getAge());
}
}
}
运行结果:
lisi:20
zhaoliu:20
chenze:22
liusan:22
qianyi:24
总结:
排序时,当主要条件相同时,一定判断一下次要条件。
●第二种排序方式
当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时就需要让集合自身具备比较性,定义比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
附注:当两种排序方式都存在的时候,以比较器为主。
问:如何定义比较器?
答:定义一个类,实现Comparator接口,覆盖compare方法即可。
示例:(在不改变方式一程序的情况下,想按照姓名进行排序)
这时我们需要用到自定义比较器的方式
代码如下:
class MyCompare implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Students1 = (Student) o1;
Students2 = (Student) o2;
intnum = s1.getName().compareTo(s2.getName());
if(num == 0)
returnnew Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
return num;
}
}
再将上面代码中的Set s= new TreeSet();一句改成Set s =new TreeSet(new MyCompare());即可实现按照姓名排序。
运行结果:
chenze:22
lisi:20
liusan:22
qianyi:24
zhaoliu:20
练习一:(按照字符串长度排序)
思路:字符串本身具备比较性,但是它的比较方式不是所需要的,这时就需要定义比较器
代码实现:
class MyCompare implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Strings1 = (String) o1;
Strings2 = (String) o2;
int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num == 0)
return s1.compareTo(s2);
return num;
}
}
class TreeSetDemo2 {
public static void main(String[] args) {
Set s = new TreeSet(new MyCompare());
s.add("abcd");
s.add("cc");
s.add("cba");
s.add("aaa");
s.add("z");
s.add("hahaha");
System.out.println(s);
}
}
运行结果:
[z, cc, aaa,cba, abcd, hahaha]
练习二:(将字符串中的数值进行排序。使用TreeSet完成。“90 -7 0 18 2 45 4”)
思路:
1.将字符串切割
2.可以将这些对象存入到TreeSet集合中,因为TreeSet自身具备排序功能
代码实现:
class TreeSetDemo2 {
public static void main(String[] args) {
String str="90 -7 0 18 2 45 4";
String[] arr=str.split(" ");
TreeSet ts=new TreeSet();
for(intx=0;x
运行结果:
[-7, 0, 2, 4, 18, 45, 90]
二、泛型
JDK1.5版本以后出现新特性,用于解决安全问题,是一个类型安全机制。
优点:
1.将运行时期出现的ClassCastException问题转移到了编译时期,方便与程序员解决问题,让运行时期问题减少,提高安全性;
2.避免了强制转换的麻烦。
格式:
通过“<>”来定义要操作的引用数据类型
何时使用?
通常在集合框架中常见,只要见到“< >”就要定义类型,当使用集合时,将集合中要存储的数据类型作为参数传递到“< >”中即可
示例:
class GenericDemo {
public static void main(String[] args) {
// 定义集合中只可以加入String类型数据
ArrayList al = new ArrayList();
al.add("abc01");
al.add("abc02");
al.add("abc03");
//al.add(4);// 当加入Integer类型数据时,报错
for(Iterator it = al.iterator(); it.hasNext();) {
System.out.println(it.next());
}
System.out.println("-----");
// 定义集合中只可以加入Integer类型数据
ArrayList al2 = newArrayList();
al2.add(1);
al2.add(3);
al2.add(5);
// al2.add("ada");//当加入String类型数据时,报错
for (Iterator it =al2.iterator(); it.hasNext();) {
System.out.println(it.next());
}
}
}
运行结果:
abc01
abc02
abc03
-----
1
3
5
练习:(将Stirng类型数据存入到TreeSet中,按照长度对字符串进行排序)
class GenericDemo {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new LenComparator());
ts.add("abcd");
ts.add("cc");
ts.add("cba");
ts.add("aaa");
ts.add("z");
ts.add("hahaha");
for(Iterator it =ts.iterator(); it.hasNext();) {
System.out.println(it.next());
}
}
}
class LenComparator implementsComparator {
public int compare(String s1, String s2) {
int num = newInteger(s1.length()).compareTo(new Integer(s2.length()));
if(num == 0)
returns1.compareTo(s2);
return num;
}
}
运行结果:
z
cc
aaa
cba
abcd
hahaha
思考:
如果按长度从到短该如何排序呢?——只需要将比较器中的s1和s2换一下位置即可
1.泛型类:
问:什么时候定义泛型类?
答:当类中需要操作的引用数据类型不确定的时候。
示例:
//定义一个传递指定类型的工具类
class Utils{
private QQ q;
public void setObject(QQ q){
this.q=q;
}
publicQQ getObject(){
return q;
}
}
class Worker{}
class Student{}
class GenericDemo {
public static void main(String[] args) {
//定义一个存储Student类型的工具对象
Utils stu=new Utils();
stu.setObject(newStudent());
stu.getObject();
//定义一个存储Worker类型的工具对象
Utils w=new Utils();
w.setObject(newWorker());
w.getObject();
}
}
2.泛型方法
泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法中。
示例:
class Demo {
//定义与类类型一致
public void show(T t) {
System.out.println("show:"+ t);
}
//定义随意类型,可以与类类型不一致,比如类类型是String,这里可以定义为其他基本类型,例如Integer……
public void print(Q q) {
System.out.println("print:"+ q);
}
public static void method(W w) {
System.out.println("method:"+ w);
}
/*出错。静态方法不可以访问类上定义的泛型
publicstatic void method_2(T t) {
System.out.println("method_2:"+ t);
}*/
}
class GenericDemo {
public static void main(String[] args) {
//将Demo定义为String类型
Demo d = new Demo();
d.show("hah");
//传递Integer类型
d.print(5);
//传递String类型
d.print("hehe");
Demo.method(11);
System.out.println("------");
//将Demo定义为Integer类型
Demo d1 = new Demo();
d1.show(3);
//可以定义成String类型
d1.print(newString("test"));
d1.print(5);
Demo.method("ghajga");
}
}
运行结果:
show:hah
print:5
print:hehe
method:11
------
show:3
print:test
print:5
method:ghajga
附注:
静态方法不可以访问类上定义的泛型。如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
3.泛型接口
将泛型定义在接口上
示例:
interface Inter {
void show(T t);
}
class InterImpl implements Inter {
public void show(T t) {
System.out.println("show:"+ t);
}
}
class GenericDemo {
publicstatic void main(String[] args) {
//定义为String类型
InterImpl ii1 = new InterImpl();
ii1.show("erae");
System.out.println("----");
//定义为Integer类型
InterImpl ii2 = new InterImpl();
ii2.show(43);
}
}
运行结果:
show:erae
----
show:43
练习:(定义多个子类继承父类并存入TreeSet,子类名字进行排序)
思路:定义一个父类(Person),写两个子类(Student、Worker)再存入到TreeSet中按照姓名进行排序。
代码实现:
class Person{
private String name;
private int age;
Person(Stringname){
this.name=name;
}
publicString getName(){
return name;
}
publicint getAge(){
return age;
}
}
class Student extends Person{
Student(Stringname) {
super(name);
}
}
class Worker extends Person{
Worker(Stringname){
super(name);
}
}
//将比较器类型定义成父类的类型
class Comp implements Comparator{
publicint compare(Person p1,Person p2){
return p1.getName().compareTo(p2.getName());
}
}
class GenericDemo {
public static void main(String[] args) {
TreeSet ts1=new TreeSet(new Comp());
ts1.add(newStudent("student----03"));
ts1.add(newStudent("student----02"));
ts1.add(newStudent("student----06"));
ts1.add(newStudent("student----01"));
for(Iterator it=ts1.iterator();it.hasNext();){
System.out.println(it.next().getName());
}
System.out.println("------");
TreeSet ts2=new TreeSet(new Comp());
ts2.add(newWorker("worker---03"));
ts2.add(newWorker("worker---02"));
ts2.add(newWorker("worker---06"));
ts2.add(newWorker("worker---01"));
for(Iterator it=ts2.iterator();it.hasNext();){
System.out.println(it.next().getName());
}
}
}
运行结果:
student----01
student----02
student----03
student----06
------
worker---01
worker---02
worker---03
worker---06
4.泛型限定:
从上面的练习中可以看到,主函数中调用的两个对象不一致,但是都有遍历集合中的元素操作,为了代码的简约,我们可以定义一个共同的打印方法来实现,这里就是我们接下来要说明的泛型限定。
通配符(占位符):?
格式:
?extends E:可以接收E类型或者E的子类型——上限
?super E:可以接受E类型或者E的父类型——下限
将上面的例子进行重新的编写,代码如下(这里定义一个泛型限定的泛型方法):
//其他代码不变,将主函数进行更改:
class GenericDemo {
publicstatic void main(String[] args) {
TreeSet ts1=new TreeSet(new Comp());
ts1.add(newStudent2("student----03"));
ts1.add(newStudent2("student----02"));
ts1.add(newStudent2("student----06"));
ts1.add(newStudent2("student----01"));
printCollection(ts1);
System.out.println("------");
TreeSet ts2=new TreeSet(new Comp());
ts2.add(newWorker2("worker---03"));
ts2.add(newWorker2("worker---02"));
ts2.add(newWorker2("worker---06"));
ts2.add(newWorker2("worker---01"));
printCollection(ts2);
}
//定义一个上限的泛型方法
public static void printCollection(Collection extendsPerson> s){
for(Iterator extends Person> it=s.iterator();it.hasNext();){
System.out.println(it.next().getName());
}
}
}
运行结果也与上面结果一致。
三、Map集合
Map集合存储K-V对,一对一对往里存,而且保证键的唯一性。
Map存储元素使用put方法,Collection使用add方法
常用子类:
·HashTable:底层数据结果是哈希表。不可以存入null键和null值,该集合是线程同步的,jdk1.0开始,效率低。(已经被HashMap替代)
·HashMap:底层数据结构是哈希表。可以存入null键和null值,该集合是不同步的,将HashTable替代了,jdk1.2,效率高
·TreeMap:底层数据结构是二叉树。线程不同步,可以将map集合中的键进行排序
其实和Set很像,Set底层就是用的Map集合。
1常用的一些方法:
●添加:
Vput(K key,V value)——存入key与value对
voidputAll(Map extends K,? extends V> m)——将m集合复制到已有集合
示例:
class MapDemo {
public static void main(String[] args) {
Map map1 = new HashMap();
System.out.println(map1.put(1,"zhangsan")); // 结果:null
System.out.println(map1.put(1,"lisi")); //结果:zhagnsan
map1.put(3,"zhaoliu");
map1.put(2,"xuer");
//第一次存的数据将被覆盖,并且返回值为被覆盖的值
System.out.println(map1); // 结果:{1=lisi, 2=xuer, 3=zhaoliu}
Map map2 = new HashMap();
map2.put(6,"java");
map2.put(1,"php");
System.out.println(map2); // 结果:{1=php, 6=java}
//覆盖已有的键值对
map2.putAll(map1);
System.out.println(map2); // 结果:{1=lisi, 2=xuer, 3=zhaoliu,6=java}
}
}
●删除:
voidclear()——清空集合
Vremove(Object key)——根据指定key,删除元素
示例:
class MapDemo {
public static void main(String[] args) {
Map map1 = new HashMap();
map1.put(1,"zhangsan");
map1.put(3,"zhaoliu");
map1.put(2,"xuer");
map1.put(4,"java");
map1.put(5,"c++");
System.out.println(map1); //结果:{1=zhangsan,2=xuer, 3=zhaoliu, 4=java,5=c++}
map1.remove(2); // 结果:{1=zhangsan, 3=zhaoliu, 4=java,5=c++}
System.out.println(map1);
// 删除不存在的键值对时,返回false
System.out.println(map1.remove(3,"java")); // 结果:false
System.out.println(map1); // 结果:{1=zhangsan, 3=zhaoliu, 4=java, 5=c++}
//删除存在的键值对时,返回true
System.out.println(map1.remove(3,"zhaoliu")); // 结果:true
System.out.println(map1); // 结果:{1=zhangsan, 4=java, 5=c++}
//清空集合
map1.clear();
System.out.println(map1); // 结果:{}
}
}
●判断:
booleancontainsKey(Object key)——根据key判断元素是否存在,存在则返回 true。
booleancontiansValue(Object value)——根据value判断元素是否存在,存在则返回 true。
booleanisEmpty()——判断集合是否为空
示例:
class MapDemo {
public static void main(String[] args) {
Map map1 = new HashMap();
//判读集合是否为空
System.out.println(map1.isEmpty());//结果:true
//给集合添加元素
map1.put(1,"java");
map1.put(2,"c++");
map1.put(3,"c");
map1.put(4,"php");
//再次判读集合是否为空
System.out.println(map1.isEmpty()); //结果:false
//判断集合是否存在键为3的元素
System.out.println(map1.containsKey(3)); //结果:true
//判断集合是否存在键为9的元素
System.out.println(map1.containsKey(9)); //结果:false
//判断集合是否存在一个值元素为“java”的元素
System.out.println(map1.containsValue("java")); //结果:true
//判断集合是否存在一个值元素为“java2”的元素
System.out.println(map1.containsValue("java2")); //结果:false
}
}
●获取:
Vget(Object Key)——根据key获取对应的value
intsize()——返回此映射中的键-值映射关系数
Collection
下面两个将单独讲解
★Set
★Set
示例:
class MapDemo {
public static void main(String[] args) {
Map map1 = new HashMap();
//给集合添加元素
map1.put(1,"java");
map1.put(2,"c++");
map1.put(4,"php");
map1.put(3,"c");
//根据key获取对应的值,如果存在返回值
System.out.println(map1.get(2));
//根据key获取对应的值,如果不存在返回null
System.out.println(map1.get(6));
//获取集合的长度
System.out.println(map1.size());
//通过values获取集合的所有值
Collection a=map1.values();
for(Iterator it=a.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
运行结果:
c++
null
4
java
c++
c
php
2.Map集合常用的两种取出方式
★Set
因为Set具备迭代器功能,先通过迭代方式取出所有的键,再根据get方法,获取每一个键对应的值即可。
示例:
class MapDemo {
public static void main(String[] args) {
Map map1 = new HashMap();
//给集合添加元素
map1.put(1,"java");
map1.put(2,"c++");
map1.put(4,"php");
map1.put(3,"c");
//将map1的键通过keySet方法存到set集合中
Set keySet = map1.keySet();
//再通过迭代方法获取每一个键,再通过键获取值
for(Iterator it = keySet.iterator(); it.hasNext();) {
int key = it.next();
String value = map1.get(key);
System.out.println(key+ ":" + value);
}
}
}
运行结果:
1:java
2:c++
3:c
4:php
总结:
取出原理:将Map集合转成Set集合,再通过迭代器取出。
★Set
示例:
class MapDemo3 {
publicstatic void main(String[] args) {
Map map = new HashMap();
map.put(1,"java");
map.put(2,"c++");
map.put(4,"php");
map.put(3,"b");
//将Map的映射关系通过entrySet方法存入到Set集合中
Set> entrySet = map.entrySet();
for(Iterator> it = entrySet.iterator();it.hasNext();) {
Map.Entry me=it.next();
//通过Map.Entry中的getKey和getValue方法获取键与值
int key=me.getKey();
String value=me.getValue();
System.out.println(key+":"+value);
}
}
}
运行结果:
1:java
2:c++
3:b
4:php
总结:
Entry其实就是Map中的一个static内部接口。
附注:Map集合之所以被使用,是因为其中的元素是以键值对形式存在的。
按照这样的思想:我们可以做一个实验,比如一个学校有很多年级,每个年级有不同的班级,不同的班级有不同的学生。这和我国行政区划也很相似,我们不防模拟一下这种情况。
示例:(以学校有多个班级为例)
class Student {
private String name;
private int id;
Student(int id, String name) {
this.id= id;
this.name= name;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
}
class MapTest {
public static void main(String[] args) {
//建一个学校对象,存的是班级与学生的关系(一对多)
Map> school = new HashMap>();
//建立班级对象,班级中添加的是学生集合
List bj1 = new ArrayList();
List bj2 = new ArrayList();
//添加两个班级
school.put("bj1",bj1);
school.put("bj2",bj2);
//给第一个班级添加学生
bj1.add(newStudent(1, "zhangsan-1"));
bj1.add(newStudent(2, "lisi-1"));
bj1.add(newStudent(3, "zhaoliu-1"));
//给第二个班级添加学生
bj2.add(newStudent(1, "zhangsan-2"));
bj2.add(newStudent(2, "lisi-2"));
bj2.add(newStudent(3, "zhaoliu-2"));
//获取学校学生信息
getInfo(school);
}
public static void getInfo(Map> a) {
//方法一:
Set>> entrySet = a.entrySet();
for(Iterator>> it =entrySet.iterator(); it.hasNext();) {
Map.Entry> me = it.next();
StringroomName = me.getKey();
List room = me.getValue();
System.out.println(roomName+ ":");
getRoomInfo(room);
}
//方法二:
/*
SetkeySet = a.keySet();
for(Iterator it = keySet.iterator(); it.hasNext();) {
StringroomName=it.next();
List room=a.get(roomName);
System.out.println(roomName+":");
getRoomInfo(room);
*/
}
}
//根据教室获取学生信息
private static void getRoomInfo(List room) {
for(Iterator it = room.iterator(); it.hasNext();) {
Student s = it.next();
System.out.println(" " + s.getId() + ":" +s.getName());
}
}
}
运行结果:
bj1:
1:zhangsan-1
2:lisi-1
3:zhaoliu-1
bj2:
1:zhangsan-2
2:lisi-2
3:zhaoliu-2
练习一:(通过HashMap存入学生对象,并保证学生对象的唯一性(当姓名与年龄相同为同一对象))
思路:
1.描述学生类,
2.定义Map容器,将学生以键值对形式存入
3.获取Map集合中的元素
代码实现:
class Student {
private String name;
private int age;
Student(String name, int age) {
this.name= name;
this.age= age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public boolean equals(Object obj) {
if (!(obj instanceof Student))
throw new RuntimeException("不是学生类型");
Student s = (Student) obj;
return this.name.equals(s.name)&& this.age == s.age;
}
public int hashCode() {
return name.hashCode() + age * 11;
}
}
class MapTest {
public static void main(String[] args) {
Map map=new HashMap<>();
map.put(newStudent("a",23), "shanghai");
map.put(newStudent("b",22), "tianjin");
map.put(newStudent("b",22), "tianjin2");
map.put(newStudent("c",25), "beijign");
map.put(newStudent("d",20), "nanjing");
map.put(newStudent("e",23), "shanghai2");
map.put(newStudent("a",23), "shanghai23");
//第一张取出方式
for(Iterator it=map.keySet().iterator();it.hasNext();){
Student s=it.next();
String address=map.get(s);
System.out.println(s.getName()+":"+s.getAge()+"..."+address);
}
System.out.println("-----------------------");
//第二种取出方式
Set> entrySet=map.entrySet();
for(Iterator> it=entrySet.iterator();it.hasNext();){
Map.Entry me=it.next();
Student s=me.getKey();
String address=me.getValue();
System.out.println(s.getName()+":"+s.getAge()+"..."+address);
}
}
}
运行结果:
d:20...nanjing
e:23...shanghai2
b:22...tianjin2
c:25...beijign
a:23...shanghai23
-----------------------
d:20...nanjing
e:23...shanghai2
b:22...tianjin2
c:25...beijign
a:23...shanghai23
练习二 :(对上个练习中的学生按照年龄进行升序排序)
因为数据是以键值对形式存在的,所以要使用可以排序的Map集合——TreeMap
第一种方式:Student实现Comparable,复写compareTo方法
代码片段:
//将Student实现Comparable,并复写compareTo方法
class Student implementsComparable {
……(其余代码不变)
//覆盖compareTo方法
publicint compareTo(Student s) {
int num = new Integer(this.age).compareTo(new Integer(s.age));
if(num == 0)
return this.name.compareTo(s.name);
retur nnum;
}
}
//再将上个练习中主函数的HashMap改成TreeMap即可。
MapTest {
publicstatic void main(String[] args) {
Map map=new TreeMap();
map.put(newStudent("zhangsan",20), "shanghai");
map.put(newStudent("lisi",22), "tianjin");
map.put(newStudent("liuqi",23), "nanjing");
map.put(newStudent("zhaoliu",24), "hebei");
map.put(newStudent("wangtian",22), "wuhan");
map.put(newStudent("zhouliu",21), "fushun");
Set keySet=map.keySet();
for(Iterator it=keySet.iterator();it.hasNext();){
Student s=it.next();
String address=map.get(s);
System.out.println(s.getName()+":"+s.getAge()+"..."+address);
}
}
}
运行结果:
zhangsan:20...shanghai
zhouliu:21...fushun
lisi:22...tianjin
wangtian:22...wuhan
liuqi:23...nanjing
zhaoliu:24...hebei
第二种方式:通过自定义比较器,复写compare方法
//student类还是和第一次一样
//定义自定义比较器
class Compl implements Comparator{
public int compare(Student s1, Student s2) {
int num=new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
if(num==0)
return s1.getName().compareTo(s2.getName());
return num;
}
}
//再将比较器传递给TrreMap的构造函数即可
class MapTest2 {
public static void main(String[] args) {
Map map=new TreeMap(new Compl());
map.put(newStudent("zhangsan",20), "shanghai");
map.put(newStudent("lisi",22), "tianjin");
map.put(newStudent("liuqi",23), "nanjing");
map.put(newStudent("zhaoliu",24), "hebei");
map.put(newStudent("wangtian",22), "wuhan");
map.put(newStudent("zhouliu",21), "fushun");
Set keySet=map.keySet();
for(Iterator it=keySet.iterator();it.hasNext();){
Student s=it.next();
String address=map.get(s);
System.out.println(s.getName()+":"+s.getAge()+"..."+address);
}
}
}
运行结果与上面一个一致。
练习三:(获取该字符串"sdfgzxcvasdfxcvdf"中的字母出现的次数。希望打印结果:a(1)c(2).....)
思路:
通过结果可以发现,每一个字母与次数之间有键值对的关系,这时就想到了Map集合。
步骤:
1.将字符串转换成字符数组,因为要对每一个字母进行操作;
2.定义一个Map集合,因为打印结果的字母是有顺序的,所以使用TreeMap集合;
3.遍历字符数组
将每一个字母作为键去查Map集合,如果返回null,将该字母和1存入到Map集合中,如果返回的不是null,说明该字母已经在Map中存在并有相应的次数,那么就 获取次数并进行自增,然后将字母和自增后的次数存入到Map集合中,覆盖字母之前所对应的次数
4.将Map集合中的数据变成指定的字符串形式返回。
代码实现:
class TreeMapTest {
publicstatic void main(String[] args) {
Strings = charCount("sdfgzxcvasdfxcvdf ");
System.out.println(s);
}
publicstatic String charCount(String str) {
char[] ch = str.toCharArray();
Map map = new TreeMap();
int count = 0;
for(int x = 0; x < ch.length; x++) {
if(!((ch[x] >= 'a' && ch[x] <= 'z') || (ch[x] >= 'A' &&ch[x] <= 'Z'))) {
continue;
}
//System.out.println(map.get(ch[x]));
Integer value = map.get(ch[x]);
//如果存在的话,获取次数
if(value != null)
count= value;
//自增
count++;
map.put(ch[x],count);
count= 0;
}
StringBuilder sb = new StringBuilder();
Set> entrySet = map.entrySet();
for(Iterator> it = entrySet.iterator();it.hasNext();){
Map.Entry me = it.next();
Character cha = me.getKey();
Integer value = me.getValue();
sb.append(cha+ "(" + value + ")");
}
return sb.toString();
}
}
运行结果:
a(1)c(2)d(3)f(3)g(1)s(2)v(2)x(2)z(1)
四、Collections&Arrays
1. Collections
集合框架的工具类,里面定义的都是静态方法
问:Collections和Collection的区别:
答:Collections是集合框架中的一个工具类,该类中的方法都是静态的,提供的方法有可以对List集合进行排序,二分查找等方法,通常常用的集合都是线程不安全的,因为要提高效率,在多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。
Collection是集合框架中的一个顶层接口,里面定义了单列集合的共性方法,有两个常用的子类:List——对元素都有定义索引,有序的,元素可以重复;Set无序,元素不可以重复。
●排序:(1.根据自然顺序进行排序、2.自定义比较器进行排序)
示例一:(自然排序)
class CollectionsDemo {
public static void main(String[] args) {
List list = new ArrayList();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}
运行结果:
[abcd,aaa, zz, kkkkk, qq, z]
[aaa,abcd, kkkkk, qq, z, zz]
示例二:(自定义比较器排序)
//定义按照长度排序比较器
class Comp implements Comparator{
publicint compare(String s1, String s2) {
int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num==0)
return s1.compareTo(s2);
return num;
}
}
class CollectionsDemo {
public static void main(String[] args) {
List list = new ArrayList();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
System.out.println(list);
Collections.sort(list,new Comp());
System.out.println(list);
}
}
运行结果:
[abcd,aaa, zz, kkkkk, qq, z]
[z,qq, zz, aaa, abcd, kkkkk]
●获取最大值与最小值(自然排序、自定义比较器排序)
//定义按照长度排序比较器
class Comp implements Comparator {
public int compare(String s1, String s2) {
int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num == 0)
return s1.compareTo(s2);
return num;
}
}
class CollectionsDemo {
public static void main(String[] args) {
List list = new ArrayList();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
System.out.println(list);
//获取自然排序最大值
System.out.println("自然排序最大:" +Collections.max(list));
//获取自然排序最小值
System.out.println("自然排序最小:" +Collections.min(list));
//Collections.sort(list);
//自定义比较器获取长度最大值
System.out.println("长度最大:" + Collections.max(list, new Comp()));
//自定义比较器获取长度最小值
System.out.println("长度最小:" + Collections.min(list, new Comp()));
}
}
运行结果:
[abcd,aaa, zz, kkkkk, qq, z]
自然排序最大:zz
自然排序最小:aaa
长度最大:kkkkk
长度最小:z
●查找
class CollectionsDemo {
public static void main(String[] args) {
List list = new ArrayList();
list.add("abcd");
list.add("aaa");
list.add("zz");
list.add("kkkkk");
list.add("qq");
list.add("z");
Collections.sort(list);
System.out.println(list);
//通过二分查找“abcd”存在的话,返回索引值
System.out.println(Collections.binarySearch(list,"abcd"));
//通过二分查找“aaaaaa”不存在的话,返回-(插入点的值)-1
System.out.println(Collections.binarySearch(list,"aaaaaa"));
}
}
运行结果:
[aaa,abcd, kkkkk, qq, z, zz]
1
-2
●强行逆转
class TreeSetDemo {
public static void main(String[] args) {
Set s1=new TreeSet();
s1.add("abv");
s1.add("a");
s1.add("abvdsdf");
s1.add("abvdfsafasdgfas");
s1.add("garegasgge");
System.out.println(s1);
//这里通过Collections的reverseOrder方法强行逆转了
Set s2=new TreeSet(Collections.reverseOrder());
s2.add("abv");
s2.add("a");
s2.add("abvdsdf");
s2.add("abvdfsafasdgfas");
s2.add("garegasgge");
System.out.println(s2);
}
}
运行结果:
[a,abv, abvdfsafasdgfas, abvdsdf, garegasgge]
[garegasgge,abvdsdf, abvdfsafasdgfas, abv, a]
附注:
同样在构造函数定义的比较器也可以传递给reverseOrder方法进行强行逆转,这里不再进行演示。
●Collections还可以将非同步的线程改为同步线程。
●shuffle方法还可以将集合中的元素随机排放。
●replaceAll方法可以用新值替换旧值,reverse方法可将集合反转
示例:
class TreeSetDemo {
public static void main(String[] args) {
List list=new ArrayList();
list.add("abd");
list.add("aaa");
list.add("abddaf");
list.add("hello");
System.out.println("原集合:"+list);
//把aaa替换成hahaha
Collections.replaceAll(list,"aaa", "hahaha");
System.out.println("修改后:"+list);
//将list反转
Collections.reverse(list);
System.out.println("反转后:"+list);
}
}
运行结果:
原集合:[abd, aaa, abddaf, hello]
修改后:[abd, hahaha, abddaf, hello]
反转后:[hello, abddaf, hahaha, abd]
●fill方法还可以将list集合中所有的元素替换成指定元素。
示例:
class TreeSetDemo {
public static void main(String[] args) {
List list=new ArrayList();
list.add("abd");
list.add("aaa");
list.add("abddaf");
System.out.println(list);
Collections.fill(list,"haha");
System.out.println(list);
}
}
运行结果:
[abd,aaa, abddaf]
[haha,haha, haha]
2. Arrays
用于操作数组的工具类,里面都是静态方法
●将数组转成List集合
示例:
class ArraysDemo {
public static void main(String[] args) {
String[] arr = { "abv", "dfa", "zde" };
List list = Arrays.asList(arr);
System.out.println(list);
//可以修改,将脚标为1的元素修改为haha
list.set(1,"haha");
System.out.println(list);
//删除和添加都会产生UnsupportedOperationException异常
//list.remove(1);
//list.add("dafd");
}
}
运行结果:
[abv,dfa, zde]
[abv, haha,zde]
附注:
问:把数组编程集合有什么好处?
答:可以使用集合的思想和方法来操作数组中的元素。可以使用contains、get、indexOf、subList等方法,将数组变成集合,不可以使用集合的增删方法,因为数组的长度是固定的。
如果数组中的元素都是对象,那么变成集合后,数组中的元素就直接转成集合中的元素;
如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
●对数组进行排序
●对数组进行二分查找
▲将集合变数组
Collection接口中的toArray方法
示例:
class CollectionToArray {
publicstatic void main(String[] args) {
List list =new ArrayList();
list.add("avd1");
list.add("avd2");
list.add("avd3");
list.add("avd4");
String[] arr=list.toArray(new String[list.size()]);
System.out.println(Arrays.toString(arr));
}
}
运行结果:
[avd1,avd2, avd3, avd4]
附注:
问:指定类型的数组长度要定义多长呢?
答:当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组,长度为集合的size;当指定类型的数组长度大于了集合的size,就不会新创建了数组,而是使用传递进来的数组,所以创建一个刚刚好的数组最优,长度为集合的size。
问:为什么要建集合变成数组?
答:为了限定对元素的操作,比如:不需要进行增删操作。
五、增强for语句
Collection在1.5后出现的父接口Iterable就提供了这个for语句
格式:
for(数据类型变量名:数组或集合){
执行语句;
}
作用:简化了对数组,集合的遍历
对集合进行遍历——只能获取集合元素,不能对集合进行操作。
示例:
class ForDemo {
public static void main(String[] args) {
//对ArrayList进行高级for循环操作
List al = new ArrayList();
al.add("abc");
al.add("bcd");
al.add("def");
for(String s : al) {
System.out.println(s);
}
System.out.println("--------");
//对数组进行高级for循环
int[] arr = { 3, 2, 3, 1 };
for(int s : arr) {
System.out.println(s);
}
System.out.println("--------");
//对Map集合进行高级for循环,两种方式
Map hm = new HashMap();
hm.put(1,"as");
hm.put(2,"bv");
hm.put(4,"ds");
hm.put(3,"cs");
Set keySet = hm.keySet();
//方式一:
for(Integer i : keySet) {
System.out.println(i+ ":" + hm.get(i));
}
System.out.println("--------");
//方式二:
for(Map.Entry me : hm.entrySet()) {
System.out.println(me.getKey()+ ":" + me.getValue());
}
}
}
运行结果:
abc
bcd
def
--------
3
2
3
1
--------
1:as
2:bv
3:cs
4:ds
--------
1:as
2:bv
3:cs
4:ds
附注:
高级for与迭代器的区别:
迭代器除了遍历,还可以进行remove集合中的元素的操作,如果是ListIterator的话,还可以在遍历的过程中对集合进行增删改查的操作。
问:传统for和高级for有啥区别?
答:高级for有一个局限性,必须有被遍历的目标,建议在遍历数组的时候,还是希望用传统for,因为传统for可以定义脚标。
六、可变参数
JDK1.5版本出现的新特性,常常定义在函数上,在使用时注意:可变参数一定要定义在参数列表最后面。
格式:
返回值类型 函数名(参数类型… 形式参数){
执行语句;
}
其实接收的是一个数组,可以指定实际参数个数
示例:
class ParamMethod {
public static void main(String[] args) {
method_1(2,3, 4);
method_2(1,2, 3, 4);
}
public static void method_1(int... arr) {
System.out.println("长度为:" + arr.length);
}
//可以在可变参数列表前面定义参数,不可以在其后面定义
public static void method_2(int a, int... arr) {
int sum = 0;
for(int x = 0; x < arr.length; x++) {
sum+= arr[x];
}
System.out.println("sum="+ (sum + a));
}
}
运行结果:
长度为:3
sum=10
附注:
1.可变参数其实就是数组的简写形式,不用每次手动建立数组对象,只要建要操作的元素作为参数传递即可,隐式地将这些参数封装成了数组
2.可变参数一定要定义在参数列表最后面。
七、静态导入
格式示例:
importstatic java.util.Arrays.*;//导入的是Arrays这个类中的所有静态成员
importstatic java.util.Colletions.*;//导入Collections中的所有静态成员
注意:
当类名重名时,需要指定具体的包名;
当方法重名时,需要指定具备所属的对象或者类