------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
前面我们对单个对象的操作,如果有多个对象的时候,我们需要介绍集合类,集合就是用来存储多个对象的,数据多了则是用对象来存储 ,因为多数据的属性所属。数组用来存储对象,缺陷是固定长度,类型要统一。集合则是可变长度,对象即可。
下面我们通过两个图来了解一下集合类
上面这个图来说明了集合类的划分,根据功能的抽取继承关系。
我们来看看三个子类Map,Set,List的区别特点:
我们可以看出set集合是在对元素处理的过程中,没有顺序的。这样就需要所添加的元素是不能相同的,否则无法访问。List则是有顺序,可以重复的,如同数组一样,在访问这里的元素的时候,根据索引来。Map的元素是由两部分组成的(key,value),我们可以通过key来访问value的值。
对于数据的处理有四种基本的方式,“增删改查”。add() 添加元素。addAl(Collection<? extends E>),将指定collection中的所有元素都添加到该集合中。获取集合长度 size();
add方法的参数类型是object,以便接受任意类型对象。集合中存储的都是对象的引用。remove()即为删除元素。contains()是否包含某个元素,isEmpty()是否为空。retainAll(),将两个集合进行比较,求交集,调用的集合里只保留交集部分。removeAll(),也是可以这样用的。
元素的取出则是需要使用iterator()接口。因为数据结构不同,那么取出的方式不同,为此java抽取取出方式共性的东西形成迭代器便于取出数据。
Iterator it=al.iterator();
whhile(it.hasNext) //注意:hasNext返回的对象是Object,我们在使用的时候可能需要转型
{
}
for(Iterator<E> it=al.iterator();it.hasNext())
{
} //较为优化的取数据
每一个容器对数据的储存方式不同,这个存储方式称之为数据结构。
List集合共性的方法:增删改查,add(int index ,E element)指定位置添加元素,元素位置为泛型的时候添加一堆元素。get(int index )获取某一个位置的元素。indexOf()获取角标。listIterator()该List集合特有的迭代器,带有角标的方法都是List集合特有方法,只有List才有的方法就是修改一个位置上的元素,set(index,element),subList(from,to);获取所有的元素,因为是list集合,所以我们可以使用遍历的算法,也可以使用listIterator迭代器。
listIterator迭代器:之所以会有专门的迭代器是因为我们在实践中需要带迭代的过程对数据进行处理。那么,list集合专有的迭代器解决了这个问题。listIterator作为迭代器的子接口,需要实现,列表特有的迭代器具有了基本的功能(增删改查),listIterator具备hasPrevious(),逆向判断前面有没有元素。
list集合的特点。Arraylist的底层数据结构是数组,查询速度快,增删地慢,线程不同步。Linklist底层使用的是链表数据结构,查询慢,增删地快。Vector的底层是数组结构,线程同步,是Arraylist取代。
Vector集合具有特有的方法,就是带有Element的处理方法。elements枚举方法:hasMoreElements(),nextElement();枚举是迭代器之前的使用方法。
Linklist集合特点。特有方法:addFfirst(),addLast().remove get都具有这样的方法,那就是对第一个,最后一个的处理。removeFirst可以取出元素并删除元素,
link.removeFirst();
link.removeFirst();
我们再删除了第一元素后,第二会自动成为第一个元素。如果link集合是空的,那么在获取,删除的时候会抛出没有该元素的异常。1.6版本后有Remove变成poll,get变成了peak,add变成了offer,poll会返回null而不是异常。
我们使用ArrayList集合来去除集合中的重复元素,下面的代码是关键的代码。我们在使用remove的时候其实是要调用比较的比较的代码。
ArrayList newAl=new ArrayList();
Iterator it=al.iterator();
while(it.hasNext())
{
Object obj=it.next();
if(!newAl.contains(obj)) //注意使用的思想,是否包含。
newAl.add(obj);
}
HashSet底层数据结构是哈希表,线程非同步。set方法和collection是一样的。HashSet里保证的元素唯一的依据是调用了equals与hashcode来进行两个判断。我们进行自定义存储对象的时候,我们需要复写hashcode 与equals 方法来进行比较的。先进行hashcode的判断,然后再进行equals的判断。
public int hashCode() //ArrayList的判断时,仅依靠equals方法,但是,hashset则是要先哈希值来比较
{
return name.hashCode();
}
public boolean equals(Object obj) //进行判断是调用的equals方法
{
if(!(obj instanceof person))
return false;
Person p=(Person) obj;
}
TreeSet具有set的特点,独有的特点是可以对set集合中的元素进行排序。进行排序先介绍比较的方式,这里就需要介绍Comparable接口。接口里具有compareTo方法,返回的是int,大于则返回大于0,相同返回0,小于返回小于0的数值。treeset集合中存储是二叉树的类型。保证数据的唯一性依据:compareTo方法return 0。treeset比较的方式是让元素自身具备比较性,另一种方式是需要集合具备比较性。两种都存在的时候,以比较器为主。实现comparable接口,覆盖compareTo方法。
public int compareTo(Object obj)
{
Person p=(Person) obj;
if(this.age>s.age)
return 1;
if(this.age<s.age)
return -1;
return 0;
}
自定义一个比较器,将比较器对象作为参数传递给Treeset集合的构造函数。 需要注意的地方是主要的比较完后,记得次要比较条件。
class compare implements Comparator
{
public int compare(Object obj1,Object obj2)
{
Person p1=(Person) obj1;
Person p2=(Person) obj2;
return p1.getAge().compareTo(s2.getName());
}
}
泛型:用于解决类型的问题,属于一种安全机制,比如 ArrayList<String> al=new ArrayList<String>();优点:将运行期的问题暴露在编译期,便于解决问题。避免了强转的麻烦。只要见到<>就要定义泛型,通常在集合框架中很常见。那么,延伸出了泛型类。当类中要操作的引用数据类型不确定的时候,现在就需要定义泛型类。
class kk<T>
{
public void show(T t)
{
}
}
为了让不同的方法操作不同类型,而且类型不确定,那么可以将泛型定义在方法上。
class kk
{
public <T> void show(T t)
{
}
}
静态 方法不可以访问类上定义的类型,如果静态方法操作的应用类型不确定,可以将类型定义在方法上。
public static <T> void method(W w)
{
}
<?> ?为占位符,不可进行操作。泛型的限定<? extends 类>类的子类及本身,这是限定了上限。<? super E >可接受E及本类,下限。用于泛型的扩展。
接口Map<k,v>,k表示键的类型,v表示值。该集合存储键值对,保证数据的唯一性。常见的功能 删:clear()containsKey(),containsValue(),获取 get(object key) put(k,v), remove( key ),size(),value()。包含了 Hashtable:底层是哈希表数据结构,不可以存入null键null值,线程同步,效率低。
HashMap:底层是哈希表数据结构,允许使用null键null值,不同步,效率高。
Treemap底层是二叉树数据结构,线程不同步,可以给map集合进行排序。set集合底层调用的是map集合。为了保证数据的唯一性,我们要使用的是equals方法与hashcode方法。put(),方法会返回覆盖之前的值,如果出现相同的键。
Map集合取出的两种方式,keySet():将map中所有的键存入到set集合,因为set具备迭代器。所有可以迭代方式取出所有的键,再根据get方法,获取每一个键对应的值。
Set<String> keySet=map.keySet();
Iterator<String> it=keySet.iterator();
while()
{ } // 使用get方法
entrySet作为map集合的取出方式之一,将map集合中的映射关系存入到set集合中,这个关系的数据 类型就是Map.Entry。
Set<Map.Entry<String,String>> entry=map.entrySet();
当数据之间存在映射关系时,使用Map集合。
Map扩展,其实是集合的嵌套,那么,我们在取出的时候只不过需要循环嵌套而已。
Collections作为工具类,其中的方法都是静态的。我们在list里并没有排序方法,那么,collections中就有sort方法来对list集合进行排序。comparable接口的实现与前面相同的。需要注意的是传入的对象要具有可比较性。其中max方法是获取比较的最大值。
binarrySearch的方法是带有角标的list集合,因为涉及到角标的问题并且要是有序的集合。获取的角标为插入点—1。fill方式则是替换,可以全部也可以是部分。replace替换某一个。reverse反转。
Arrays用于操作数据的工具类。里面都是静态方法。aslist的方法是将数组变成llist集合,好处在于有很多方法可以使用list集合里的。但是不不能使用增删的方法,因为数组的长度是固定的。
Integer[] nums={};
List<Integer> li=Arrays.aslist<nums>;
如果数组中元素都是对象,那么变成集合的时候,数组中的元素就直接转成集合中的元素。如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。以上代码要声明的问题。
集合变数组,需要使用collection接口中的toArray。
String[] arr=al.toArray(new String[5]);
指定类型的数组长度小于集合的list,该方法内部会创建一个新的数组,长度为size,大于了不会创建。为了限定对元素的操作,不需要再增删了。
高级for循环, for(数据类型 变量名:被遍历的集合或者数组, JDK 1.5版本后取代迭代器。仅取出,不能增删,迭代可以删。高级for有一个局限性,必须有被遍历的目标。
for(Map.Entry<Integer,String> me:hm.entrySet())
{
}
JDK1.5版本后,出现的新特性,可变参数:不用每一次都建立数组对象,主要讲要操作的元素作为参数传递即可,隐式将这些参数封装成了数组。
将此可变参数放在参数列表最后。
public static void show(int... arr) //三个.号就是可变参数的格式
{
}
静态导入,StaticImport。导入类中的静态方法,调用方法更方便,类名重名时,指定更具体的包名。方法重名时,指定具备所属的对象或者类。