Java学习日记(九)Collection、泛型、Map集合、Collections&Arrays、增强for语句、可变参数、静态导入

一、Collection

为什么出现集合类?

面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方法。

数组和集合类同是容器,有何不同?

数组虽然也可以存储对象,但长度是固定的,集合长度是可变的;数组中可以存储基本数据类型,集合只能存储对象。

集合类的特点:

集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

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<obj.length;x++){
                     System.out.println(obj[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

附注:

对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCodeequals方法。

练习:(将自定义对象存入到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<arr.length;x++){
                     ts.add(Integer.parseInt(arr[x]));
              }
              System.out.println(ts);
      }
}

运行结果:

[-7, 0, 2, 4, 18, 45, 90]

 

二、泛型

JDK1.5版本以后出现新特性,用于解决安全问题,是一个类型安全机制。

优点:

       1.将运行时期出现的ClassCastException问题转移到了编译时期,方便与程序员解决问题,让运行时期问题减少,提高安全性;

       2.避免了强制转换的麻烦。

格式:

       通过“<>”来定义要操作的引用数据类型

何时使用?

       通常在集合框架中常见,只要见到“< >”就要定义类型,当使用集合时,将集合中要存储的数据类型作为参数传递到“< >”中即可

示例:

class GenericDemo {

       public static void main(String[] args) {
              // 定义集合中只可以加入String类型数据
              ArrayList<String> al = new ArrayList<String>();
              al.add("abc01");
              al.add("abc02");
              al.add("abc03");
              //al.add(4);// 当加入Integer类型数据时,报错
              for(Iterator<String> it = al.iterator(); it.hasNext();) {
                     System.out.println(it.next());
              }
              System.out.println("-----");
              // 定义集合中只可以加入Integer类型数据
              ArrayList<Integer> al2 = newArrayList<Integer>();
              al2.add(1);
              al2.add(3);
              al2.add(5);
              // al2.add("ada");//当加入String类型数据时,报错
              for (Iterator<Integer> 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<String> ts = new TreeSet<String>(new  LenComparator());
              ts.add("abcd");
              ts.add("cc");
              ts.add("cba");
              ts.add("aaa");
              ts.add("z");
              ts.add("hahaha");
              for(Iterator<String>  it =ts.iterator(); it.hasNext();) {
                     System.out.println(it.next());
              }
       }
}
class LenComparator implementsComparator<String> {
       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

思考:

如果按长度从到短该如何排序呢?——只需要将比较器中的s1s2换一下位置即可

1.泛型类:

问:什么时候定义泛型类?

答:当类中需要操作的引用数据类型不确定的时候。

示例:

//定义一个传递指定类型的工具类

class Utils<QQ>{
       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<Student> stu=new Utils<Student>();      
              stu.setObject(newStudent());
              stu.getObject();
              //定义一个存储Worker类型的工具对象
              Utils<Worker> w=new Utils<Worker>();
              w.setObject(newWorker());
              w.getObject();
       }
}

2.泛型方法

泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法中。

示例:

class Demo<T> {
       //定义与类类型一致
       public void show(T t) {
              System.out.println("show:"+ t);
       }
       //定义随意类型,可以与类类型不一致,比如类类型是String,这里可以定义为其他基本类型,例如Integer……
       public <Q> void print(Q q) {
              System.out.println("print:"+ q);
       }
       public static <W> 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<String>  d = new Demo<String>();
              d.show("hah");
              //传递Integer类型
              d.print(5);
              //传递String类型
              d.print("hehe");
              Demo.method(11);
              System.out.println("------");
              //将Demo定义为Integer类型
              Demo<Integer>  d1 = new Demo<Integer>();
              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<T> {
       void show(T t);
}

class InterImpl<T> implements Inter<T> {
       public void show(T t) {
              System.out.println("show:"+ t);
       }
}
class GenericDemo {
       publicstatic void main(String[] args) {
              //定义为String类型
              InterImpl<String>  ii1 = new InterImpl<String>();
              ii1.show("erae");
              System.out.println("----");
              //定义为Integer类型
              InterImpl<Integer> ii2 = new InterImpl<Integer>();
              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<Person>{
       publicint compare(Person p1,Person p2){
              return p1.getName().compareTo(p2.getName());
       }
}

class GenericDemo {
       public static void main(String[] args) {
              TreeSet<Student> ts1=new TreeSet<Student>(new Comp());
              ts1.add(newStudent("student----03"));
              ts1.add(newStudent("student----02"));
              ts1.add(newStudent("student----06"));
              ts1.add(newStudent("student----01"));
              for(Iterator<Student> it=ts1.iterator();it.hasNext();){
                     System.out.println(it.next().getName());
              }
              System.out.println("------");
              TreeSet<Worker> ts2=new TreeSet<Worker>(new Comp());
              ts2.add(newWorker("worker---03"));
              ts2.add(newWorker("worker---02"));
              ts2.add(newWorker("worker---06"));
              ts2.add(newWorker("worker---01"));
              for(Iterator<Worker> 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<Student2> ts1=new TreeSet<Student2>(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<Worker2> ts2=new TreeSet<Worker2>(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<Integer,String> map1 = new HashMap<Integer, String>();
              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<Integer,String> map2 = new HashMap<Integer, String>();
              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<Integer,String> map1 = new HashMap<Integer, String>();
              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<Integer,String> map1 = new HashMap<Integer, String>();
              //判读集合是否为空
              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<V> values()——返回此映射中包含的值的 Collection 视图

       下面两个将单独讲解

    ★Set<K>  keySet()——将map中所有的键存入到Set集合

    ★Set<Map.Entry<K,V>>  entrySet()——将map集合中的映射关系存入到了set集合中

示例:

class MapDemo {
       public static void main(String[] args) {
              Map<Integer,String> map1 = new HashMap<Integer, String>();
              //给集合添加元素
              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<String> a=map1.values();
              for(Iterator<String> it=a.iterator();it.hasNext();){            
                     System.out.println(it.next());
              }
       }
}

运行结果:

c++

null

4

java

c++

c

php

2.Map集合常用的两种取出方式

★Set<K> keySet()——将map中所有的键存入到Set集合

因为Set具备迭代器功能,先通过迭代方式取出所有的键,再根据get方法,获取每一个键对应的值即可。

示例:

class MapDemo {
       public static void main(String[] args) {
              Map<Integer,String> map1 = new HashMap<Integer, String>();
              //给集合添加元素
              map1.put(1,"java");
              map1.put(2,"c++");
              map1.put(4,"php");
              map1.put(3,"c");
              //将map1的键通过keySet方法存到set集合中
              Set<Integer> keySet = map1.keySet();
              //再通过迭代方法获取每一个键,再通过键获取值
              for(Iterator<Integer> 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<Map.Entry<K,V>>  entrySet()——将Map集合中的映射关系通过entrySet方法存入到了Set集合中,再通过Map.Entry中的getKey和getValue方法获取键与值。

 

示例:

class MapDemo3 {

       publicstatic void main(String[] args) {
              Map<Integer,String> map = new HashMap<Integer, String>();
              map.put(1,"java");
              map.put(2,"c++");
              map.put(4,"php");
              map.put(3,"b");
              //将Map的映射关系通过entrySet方法存入到Set集合中
              Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
              for(Iterator<Map.Entry<Integer, String>> it = entrySet.iterator();it.hasNext();) {
                     Map.Entry<Integer,String> 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<String,List<Student>> school = new HashMap<String,List<Student>>();
              //建立班级对象,班级中添加的是学生集合
              List<Student> bj1 = new ArrayList<Student>();
              List<Student> bj2 = new ArrayList<Student>();
              //添加两个班级
              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<String, List<Student>> a) {
              //方法一:
              Set<Map.Entry<String,List<Student>>> entrySet = a.entrySet();
              for(Iterator<Map.Entry<String, List<Student>>> it =entrySet.iterator(); it.hasNext();) {
                     Map.Entry<String,List<Student>> me = it.next();
                     StringroomName = me.getKey();
                     List<Student> room = me.getValue();
                     System.out.println(roomName+ ":");
                     getRoomInfo(room);
              }
              //方法二:
              /*
              Set<String>keySet = a.keySet();
              for(Iterator<String> it = keySet.iterator(); it.hasNext();) {
              StringroomName=it.next();
              List<Student> room=a.get(roomName);
              System.out.println(roomName+":");
              getRoomInfo(room);
              */
              }
       }
       //根据教室获取学生信息
       private static void getRoomInfo(List<Student> room) {
              for(Iterator<Student> 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<Student,String> 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<Student> 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<Map.Entry<Student,String>> entrySet=map.entrySet();
              for(Iterator<Map.Entry<Student,String>> it=entrySet.iterator();it.hasNext();){
                     Map.Entry<Student,String> 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<Student> {
       ……(其余代码不变)
       //覆盖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<Student,String> map=new TreeMap<Student,String>();
              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<Student> keySet=map.keySet();
              for(Iterator<Student> 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<Student>{
       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<Student,String> map=new TreeMap<Student,String>(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<Student> keySet=map.keySet();
              for(Iterator<Student> 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<Character,Integer> map = new TreeMap<Character, Integer>();
              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<Map.Entry<Character,Integer>> entrySet = map.entrySet();
              for(Iterator<Map.Entry<Character, Integer>> it = entrySet.iterator();it.hasNext();){
                     Map.Entry<Character,Integer> 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<String> list = new ArrayList<String>();
              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<String>{
       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<String> list = new ArrayList<String>();
              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<String> {
       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<String> list = new ArrayList<String>();
              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<String> list = new ArrayList<String>();
              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<String> s1=new TreeSet<String>();
              s1.add("abv");
              s1.add("a");
              s1.add("abvdsdf");
              s1.add("abvdfsafasdgfas");
              s1.add("garegasgge");
              System.out.println(s1);
              //这里通过Collections的reverseOrder方法强行逆转了
              Set<String> s2=new TreeSet<String>(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<String> list=new ArrayList<String>();
              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<String> list=new ArrayList<String>();
              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<String> 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<String> list =new ArrayList<String>();
              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<String> al = new ArrayList<String>();
              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<Integer,String> hm = new HashMap<Integer, String>();
              hm.put(1,"as");
              hm.put(2,"bv");
              hm.put(4,"ds");
              hm.put(3,"cs");
              Set<Integer> keySet = hm.keySet();
              //方式一:
              for(Integer i : keySet) {
                     System.out.println(i+ ":" + hm.get(i));
              }
              System.out.println("--------");
              //方式二:
              for(Map.Entry<Integer, String> 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中的所有静态成员

注意:

       当类名重名时,需要指定具体的包名;

       当方法重名时,需要指定具备所属的对象或者类

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值