黑马程序员_集合

android培训java培训、期待与您交流!


集合的作用:

用来存放数据,对象。长度可以变化,类型也可变。




开始ArrayList的两个小点

一、add方法的参数类型是object。以便与接受任意类型对象。

二、集合中存储的都是对象的引用(地址)。

迭代器:  就是在集合中取出元素的方式(和遍历一样)。因为每一个容器中装的对象,都是需要取出然后           再操作。不仅仅是打印。这个操作只有在上课中用到。一次把每一个元素都打印出来,所以局                  限性很大。

Iterator:是一个接口。三种方法:hasNest();nest();

接口型引用只能指向自己的子类对象。通过集合的方法获取出来。

把取出方式定义在集合的内部,这样去除方式就可以直接访问集合内部的元素。

那么取出方式就被定义成了内部类。

而每一个容器的数据结构不同,所以取出的动作细节也就不一样。但是都有共性内容判断和取出。那么可以将写出性抽取。

那么这些内部累都符合一个规则:该规则是Iterator。如何获取集合的取出对象呢?

通过一个对外提供的方法:Iterator();

毕老师的比喻就是:抓娃娃的夹子,就是迭代器。

LIST

Collection

|--List:元素是有序的,元素可以重复,因为该集合体系有索引。

|--Set:元素是无序的,元素不可以重复。


List特有方法就是:对角标的使用。

Add(index,element);(在制定位置添加元素,然后其他的都会往后移动;)

addAll(index,Collection);(在制定的位置添加一个集合)

Remove(index);(删除指定位置的元素;)

Get(index,element);(改变指定位置上的元素;)

Get(index);(获取指定位置的元素;)

subList(from,to);(获取很多元素,开始和结束位置;包头不包尾)(遍历,低效)

迭代器:(使用夹子处理迭代,指针的出现)


listIterator();------列表迭代器。【由于迭代器只有三种方法:hasNext,next,remove。】

在迭代时,不可能通过集合对象的方法操作集合中的元素。

因为会发生ConcurrentModificationExc异常。【集合和迭代都会操作集合中的元素,并发

所以,在迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,

只能对元素进行判断,取出,删除的操作。

如果想要其他的操作如:添加,修改等,就需要使用其自接口,ListIterator。

该接口只能通过List集合的ListIterator方法获取。对集合遍历过程中的增删该查,就使用这个.

List

ArrayList 底层数据结构使用的是数组结构。    特点:查询很快。但是添加删除都是稍慢。

    LinkedList 底层使用的是链表数据结构。            特点:增删很快。但是查询稍慢。

Vector:底层是数组数据结构。线程同步(1.0版本的,那是框架还没有出现【被替代】作为了解)


Vector的特殊:

elements();---->返回此向量的组件的枚举。可以拿到很多的元素。返回值是Enumeration接口...

枚举就是Vector特有的取出方式,(迭代器,遍历,for..)

发现枚举和迭代器很像。

其实枚举和迭代是一样的,因为枚举的名称以及方法的名称都很长,所以被迭代器取代了。

枚举就挂了、、优先考虑:Iterator,而不是Enumeration。。。


LinkedList

连接列表。

特有方法:

addFirst();----倒序

addLast();-----正序

 

removeFiest();----|

|------获取元素,删除元素。为空抛异常。

removeLast();-----|

可以获取全部元素,便是删取。。。


定义功能去除ArrayList中的重复元素

import java.util.ArrayList;

import java.util.Iterator;

import cn.itcast.p.bean.Person;

/*

 * 定义功能去除ArrayList中的重复元素。

 */

public class ArrayListTest2 {

         publicstatic void main(String[] args) {  

//                demo();     

//                singleDemo();    

                  ArrayList al = new ArrayList();

                  al.add(newPerson("lisi1",21));

                  al.add(newPerson("lisi2",22));

                  al.add(newPerson("lisi3",23));

                  al.add(newPerson("lisi4",24));

                  al.add(newPerson("lisi2",22));

                  al.add(newPerson("lisi3",23));

                  System.out.println(al);

                  al = getSingleElement(al);

                  System.out.println(al.remove(newPerson("lisi2",22)));

                  System.out.println(al); 

         }

         publicstatic void singleDemo() {

                  ArrayList al = new ArrayList();

                  al.add("abc1");

                  al.add("abc2");

                  al.add("abc2");

                  al.add("abc1");

                  al.add("abc");

                  System.out.println(al);

                  al = getSingleElement(al);

                  System.out.println(al);

         }

         publicstatic ArrayList getSingleElement(ArrayList al) {

                  //1,定义一个临时容器。

                  ArrayList temp = new ArrayList();

                  //2,迭代al集合。

                  Iterator it = al.iterator();

                  while(it.hasNext()){

                           Objectobj = it.next();

                           //3,判断被迭代到的元素是否在临时容器存在。

                           if(!temp.contains(obj)){

                                    temp.add(obj);

                           }

                  }return temp;

         }

 

         publicstatic void demo() {

//                al.add(5);//al.add(new Integer(5));

         }

}

List集合判断元素是否相同,依据是元素的equals方法。(contains和remove)

不同数据结构中试用的不同。

重写的equals方法:

<按照名字和年龄一致才删除>

Public boolean equals(Object  obj){

If(!(obj  instanceof Person))

return false;

Person  p = (Person)obj;//强转

System.out.println(this.name+”。。。”+p.name);

returnthis.name.equals(p.name)&&this.age==p.age;//精彩所在

}



SET

|---Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。

|----HashSet:底层数据结构是哈希表(里面有顺序,按表里取值,顺序未必和存进去的一致。)

|                           HashSet是如何保证元素唯一性的呢?

是通过两个方法:hashCode和equals来完成。

如果元素的HashCode值相同,才会判断equals是否为true。

如果元素的hashcode值不同,才会调用equals。

【开发一般都复写equalshashcode方法】(容易出现的错误就是复写没有成功。一般编译不会出错。)

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

|----TreeSet:(特点)可以对Set集合中的元素进行排序。

当使用TreeSet时,使用者(类)需要实现Comparable接口-->重写compareTo      方法。意思就是让该类具有比较性。TreeSet可以识别。{return1,0(默认为相 同对象),-1.}【底层调用,符合要求就行】

底层数据结构是二叉树,保证元素的唯一性的依据就是:compareTo方法return 0

TreeSet的第一种排序方式:

让元素自身具备比较性,元素需要实现comparable接口,覆盖compareTo方法,这种  方式也称为元素的自然顺序,或者叫做默认顺序。

TreeSet的第二种排序方式:【很重要的】

当元素自身不具备比较性时,或者具备的比较性不是所需要的。

这时就需要让集合自身具备比较性。<字符串本身具有比较性>

 

--->在集合初始化时,就有了比较方式。(参阅构造方法)【升级】

定义了比较器,将比较器对象作为参数传给TreeSet集合的构造方法。

当两种排序都存在时,以比较器为主。

定义一个类,实现Comparator接口,覆盖compare方法。

Set集合的功能和Collection是一致的。

位置一样之后,还可以在此判断元素是否相同。使用equals。都一样时就会存入失败。

哈希:取出元素的方法就一个:迭代。

Iterator it = hs.iterator();//这个是接口对象,接受一个子类对象。但是这个被封装起来了。

while(it.hasNext()){

System.oout.println(it.next());

}

<按照名字和年龄一致才删除>使用hash写出来,对hash的了解就很好。

Set例题

需求:

往TreeSet集合中存储自定义对象学生。

想按照学生的年龄进行排序。

记住:排序时,当主要条件相同时,一定要判断一下次要条件

【重写的compareTo方法】

public int compareTo(Object obj){

if(!(obj instanceof student))

throw new RuntimeException(“不是学生对象”);

Student s = (Student)obj;

Sop(this.name+”......compareTo.........”+s.name);

if(this.age>s.age)

return 1;

if(this.age==s.ags)

return this.name.compareTo(s.name);///迷人的地方

return -1;

}


MAP

 

接口 Map<K,V>Kkey--->键;Vvalue-->值。

Map集合:该集合存储键值对。一对一对的存储。而且要保证键的唯一。

方法解析:[Map<String,String>map = new HashMap<String,String>();]

1,添加。

put(K key , V value)----将指定的值与此映射中的指定键关联(可选操作)。

Map.put(“04”,”null”);----根据返回值是:返回旧值,植入新值。

putAll(Map<? extends K , ? extends V>m)----从指定映射中将所有映射关系复制到此映射中(可选操作)。

2,删除。

clear()----从此映射中移除所有映射关系(可选操作)。

Remove(Object  key)----如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。

3,判断。

containsValue(Object  value)----如果此映射将一个或多个键映射到指定值,则返回 true。

containsKey(Objedt  key)----如果此映射包含指定键的映射关系,则返回 true。

map.containsKey(“0222”);

isEmpty()----如果此映射未包含键-值映射关系,则返回 true。

4,获取。

get(Object key)----返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。

Map.get(“04”);//可以通过get方法的返回值来判断一个键是否存在。

size()----返回此映射 中的键-值映射关 系数。

values()----返回此映射中包含的值的 Collection 视图。

---Collection<String>coll=map.values();

[重点]

||--Set<Map.Entry<K,V>>  entrySet()    --返回此映射中包含的映射关系Set视图。

将Map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry

Set<Map.Entry<String,String>>entrySet = map.entrySet();

Iterator<Map.Entry<Sstring,String>>it = entrySet.iterator();

While(it.hasnext()){

Map.Entry<String,String> me =it.next();

String key = me.getKey();

String value = me.getValue();SOP(....);

}

Map.Entry 其实Entry也是一个接口,它是Map接口中的一个内部接口。

Interface Map{

Punlic static interface Entry{//

public abstract Object getKey();

public abstract Object getValue();

}

}class HashMap implements Map{

Class Hash Implements Map.Entry{

Public Object getKey(){}

Public Object getValue(){}

}

}---内部规则的原因是:类名使用、、、没有Map就没有映射关系所以它定义在Map          部。内部类,内部接口。

 

||--Set<K>  keySet               --返回此映射中包含的键的Set 视图。

将map中所有的键存入到Set集合,因为set具备迭代器。所有可以迭代方式取出所有的键,      再根据get方法,获取每一个键对应的值。[所有键获取值]                 

Set<String> keySet = map.keySet();//先获取map集合的所有键的Set集合,keySet();

Iterator<String> it =keySet.iterator();//有了Set集合,就可以获取其迭代器。

while(it.hasNext()){

String key = it.next();

String value = map.get(key);//有了键可以通过map集合的get方法获取其对应的                                                  值。

System.out.println(“key:”+key+”,value:”+value);

}

Map集合的取出原理:将map集合转成set集合。再通过迭代器取出。

--------------------------------------------------------------------------------------------------

例题:

每一个学生都有对应的归属地。学生student,地址String。

学生归属:姓名,年龄。

注意:姓名和年龄相同视为同一个学生。

保证学生的唯一。

--->代码体现:1,描述学生;

2,定义map容器,将学生作为键,地址作为值。存入。

3,获取map集合中的所有元素。

---->升级:对学生对象的年龄进行升序排序。考虑使用TreeMap。

--->”sdfgzxcvasddfgcvdf”获取该字符串中的字母出现的次数。:a(1)b(2)..

思路:       1,将字符串转换成字符数组,以为要对每一个字母进行操作。

2,定义一个map集合,因为打印结果的字母有顺序,所以使用TreeMap集合。

3,遍历字符数组。

将每一个字母作为键去查map集合。

如果返回null,将该字母和1存入到map集合中

如果返回不是null,说明该字母在map集合已经存在并有对应次数。

那么就获取该次数并进行自增,然后将该字母和自增后的次数存入到map集合中。覆盖掉原来键所对应的值。

4,将map集合中的数据变成指定的字符窜形式返回。

-----------------------------------------------------------------------------------------------------

import java.util.*;

class Student implementsComparable<Student> {

         /*同时可以创建多个对象需要被用的时候,一定要做实现,覆盖两个方法。【习惯】 */

         privateString name;

         privateint age;

         Student(Stringname ,int age){

                  this.name=name;

                  this.age=age;

         }publicint compareTo(Student s){

                  int num = newInteger(this.age).compareTo(new Integer(s.age));

                  if(num==0)

                           returnthis.name.compareTo(s.name);

                           returnnum;

         }publicint hashCode(){

                  return name.hashCode()+age*34;

         }//hashcode方法。public boolean equals(Objectobj){

                  if(!(obj instanceof Student))

                           thrownew ClassCastException("类型不匹配");

                  Student s = (Student)obj;

                  return this.name.equals(s.name)&&this.age==s.age;

         }//②想到哈希表或者是哈希Code,就需要复写这两个方法:hashcode equals方法。

         publicString getName(){

                  return name;

         }publicint getAge(){

                  return age;

         }publicString toString(){

                  return "姓名:"+name+"年龄:"+age;

         }}

class MapTest{

         publicstatic void main(String[] args){

                  HashMap<Student,String> hm = newHashMap<Student,String>();

                  hm.put(newStudent("lisi1",20),"beijing");

                  hm.put(newStudent("lisi2",23),"shnaghai");

                  hm.put(newStudent("lisi2",23),"shnagai");

                  hm.put(newStudent("lisi3",25),"nanjing");

                  hm.put(newStudent("lisi4",70),"beiing");

                  //第一种取出方式 keySet

                  Set<Student> keySet =hm.keySet();

                  Iterator<Student> it =keySet.iterator();

                  while(it.hasNext()){

                           Studentstu = it.next();

                           Stringaddr = hm.get(stu);

                           System.out.println(stu+"...."+addr);

                  }

                  //第二种取出方式 entrySet

                  Set<Map.Entry<Student,String>>entrySet = hm.entrySet();

                  Iterator<Map.Entry<Student,String>>iter = entrySet.iterator();

                  while(iter.hasNext()){

                           Map.Entry<Student,String>me = iter.next();

                           Studentstu = me.getKey();

                           Stringaddr = me.getValue();

                           System.out.println(stu+"......."+addr);

                  }

         }

}

-------------------------------------------------------------------------------------------------------

注意:

当发现有映射关系时,可以选择map集合。因为map集合中存放就是映射关系。

为什么使用map集合呢?

当数据之间存在着映射关系时,就要先想map集合。

Map集合中存储的都是键值对,打印事就是打印:

Map          :

|---Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步[1.0,低效]

|

|---HashMap:底层是哈希表数据结构,允许使用null键和null值,该集合是不同步的。[1.2,高效]

|

|---TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

 和set很像,其实Set底层就是使用了Map集合。

 

 

Map扩展知识。

Map集合被使用是因为具备映射关系。(循环嵌套)两个while。

 

Collections:集合框架的工具类

 

是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,于Java的Collection框架。

public static <T extendsComparable<?Super T>> void sort(List<T> list)

Public static <T> voidsort(List<T> list){ }//T具有比较性

可以根据元素的自然顺序对指定列表进行排序。

 

方法:Collections,max()

public static <T extendsComparable<?Super T> & Object> void max(Collection<? extends T> coll)

binarySearch(List<?Extends Comparable<? Super T>> list,T key)--需要有序

Fill()----replaceAll(list,”aaa”,”pp”)----reverse(list)反转

reverseOrder()返回的是比较器,反转。

Collections.reverseOrder(newString StrLenComparator())

集合中那么多的对象,特点就是线程不安全,需要被多线程操作时:需要枷锁(枷锁)。

把不安全的集合给它,返回的就是安全的。

staticCollection<T> synchronizedCollection(Collection<T>c)

staticList<T> synchronizedList(List<T> list)返回指定列表支持的同步(线程安全)列表

staticMap<T> synchronizedMap(Map<K,V> map)返回由指定映射支持的同步(线程安全)列表

底层如何实现的:<源码>

SynchronizedList(List<E>list){

Super(list);

This.list =list

}SynchronizedList(List<E>list,Object mutex){

Super(list,mutex);

This.list =list

}//覆盖了equals,hashcode方法。

Public voidadd(int index , E element){

Synchronized(mutex){returnlist.set(index,element);}

}//封装是你传递的list,mutex是同步代码块,使用的是同一个锁。

swap(list,1,2)表示的是把list集合中的角标1的元素和角标2的元素换位置。

shuffle(list)表示随机源的将list排序 [类似洗牌]

Arrays用于操作数组的工具类。

里面都是静态方法。

方法有:查找(二分),对象二分(equals);复制(头尾-->新数组);

比较(比较数组是否一样;比较容器元素是否一样;)fill(替换,头尾);hashcode;

Sort(排序,局部排序);toString(返回指定数组内容的字符串表示形式。);

 

asList将数组变成list集合

String[] arr = {“abc”,”cddd”,”cdsa”};

List<String> list = Array.asList(arr);

sop(list);

----->把集合变成list集合有什么好处?--可以使用集合的思想和方法来操作数组。

注意:将数组变成集合,不可以使用集合的增删方法。因为数组的长度是固定。否则就会  产生UnsupportedOperationException不支持此操作的异常。

---->注意如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的元素。

如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。

int[] nums = {1,43,3};                            Integer[] num = {1,3,46};

List lin = Array.asList(nums);                 Integer<Integer> li =Array.asList(nums);      

集合变数组:(toArray

方法:toArray(T[]  a)返回包含此Collection中所有元素的数组;返回数组的运行时类型与指定数组的                                      运行时的类型相同。

①:指定类型的数组到底要定义多长呢?

当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。长度为集合的size。         当指定类型的数组长度大于了集合的size,就不会新创建数组了,而是使用传递进来的数组。

所以创建一个刚刚好的数组最优。

String[] arr = al.toArray(new String[al.size()]);

②:为什么要将集合变成数组呢?

为了限定对元素的操作,不需要进行增删了。

迭代器升级(高级for循环):

格式:

for(数据类型 变量名 : 被遍历的集合(Collection)或者数组){}

代码:for(String s : al){sop(s);}  遍历al集合,并打印出来。底层原理还是迭代器,优化了书写。

局限:就是只能对集合中的元素进行取出,不能做修改删除等动作。

迭代器:除了遍历,还可以进行remove集合中的元素的动作。

如果使用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。

传统for和高级for有什么区别?

高级for有一个局限性:必须有一个被遍历的目标。

建议,在遍历数组的时候,还是使用传统的for。因为传统for可以定义角标。

HashMap集合的元素取出来,使用高级for(键和值都想取出来)

凡是支持迭代器的集合都可以使用高级for,Map不支持迭代,所以转换成Set。

HashMap<Integer,String>hm = new HashMap<Integer,String>();

hm.put(“1”,”a”);hm.put(“2”,”b”);hm.put(“3”,”c”);

Set<Integer>keySet = hm.keySet();

For(Integer i :keySet){

System.out.println(i+”.......”+hm.get(i));

}Set<Map.Entry<Integer,String>>entrySet = hm.entrySet();

For(Map.Entry<Integer,String>me : entrySet)

For(Map.Entry<Integer,String>me : hm.entrySet()){

System.out.println(me.getKey()+”------------”+me.getValue());

















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值