@w460461339
2016-11-16T07:03:07.000000Z
字数 6356
阅读 874
Java基础
今天主要讲的是集合。集合中有很多,比如之前学过的ArrayList,HashMap,HashSet等等,今天主要梳理一下它们之间的关系以及他们之中的方法。从图中可以看到,所有集合的根父类是Collection,它是一个接口,List和Set也都是接口,因此,要实例化它们,需要用它们的子类,诸如ArrayList,HashSet等来创建(其实真实的情况比这个复杂很多,但大体是这么个意思)。学习这样的继承链,我们一般从顶层父类学起。所以此处我们从Collection类学起。
由于Collection是一个接口,所有需要一个子类去实例化它。它的直接子类List和Set都是接口,只能由再下一层的子类实例化。这里我们选择ArrayList类。
public static void main(String args[]){
Collection c=new ArrayList();//导包可以用Ctrl+shift+o来导包。
}
所包含方法如下:
boolean add();void clear();boolean remove(); boolean isEmpty()
boolean addAll(); boolean removeAll(); boolean containAll();
boolean retainAll(); Object[] toArray();Iterator<E> iterator()……
其中的方法体和参数列表全部略去了,到时候直接查API就好。注意其中涉及到对集合进行修改的方法,是哪个对象调用,就对哪个对象进行修改。其实因为这是借口,所以查它的API也没太大意思,更多的还是需要去实现它的子类中去查看是如何实现这些方法的。
大多数方法通过名字就可以明了,这里说三个方法:
它的意思是取交集,返回值是boolean类型,即原集合的元素更改了,返回true,否则返回false。
public static void main(String[] args) {
Collection c=new ArrayList();
Collection d=new ArrayList();
c.add("Hello");
d.add("Hello");
d.add("World");
System.out.println(c.retainAll(d));//返回false,c中的元素没变
System.out.println(c);//打印Hello
System.out.println(d.retainAll(c));//返回true,d中元素更改了
System.out.println(d);//打印Hello
}
它是将集合中的元素转成数组然后返回。这样一来我们可以利用数组的一些特性,比如下标索引,遍历等方法来对其进行操作。
public static void main(String[] args) {
Collection d=new ArrayList();
d.add("Hello");
d.add("Hello");
d.add("World");
Object[] objd=d.toArray();//Object类型数组,每个格子是Object类型的引用,指向一个String类型对象
for(int i=0;i<objd.length;i++){
System.out.println(objd[i]);
//由于引用的类型(静态类型)中的toString方法被实际类型(动态类型)的变量覆盖,所以这里调用String类型中toString方法,打印String类型对象。
}
}
这货是返回一个迭代器类型的对象,所以我们需要由一个迭代器类型的引用来接收它:
public static void main(String[] args) {
Collection d=new ArrayList();
d.add("Hello");
d.add("World");
Iterator it=d.iterator();
}
然而Iterator也是个接口,那么我们就知道,iterator()这个方法,返回的必然是一个可以实例化的Iterator的子类对象。这里我们可以进ArrayList里面看看,发现这里面没有,原来它是在它的抽象父类,AbstractList中,具体描述是这样的:
public Iterator<E> iterator() {
return new Itr();//这货是个内部类,它实现了那个Iterator接口,这里不看了,想看自己去查API。
}
所以,这里我们可以理一下迭代器和集合之间的关系。最先放出来的那张图,就是集合的接口以及子类之间的关系。迭代器的接口以及其子类,也是那样的关系。那是什么将他们连起来的呢?由于迭代器需要依赖于集合存在,单纯定义一个迭代器是没有意义的,所以只能在实例化集合对象之后才能创建迭代器。因此,将迭代器定义为集合类的子类,并且外部不能访问这个类,只能通过它提供的方法来获得一个迭代器的对象。(喵,就是这样)
讲完了大致的原理,我们来看看迭代器的用法(也就是看看方法)。同样,我们从顶向下看,先看看顶层类。顶层类是Iterator,它是一个接口,提供三个方法:next,hasNext 以及remove(当然,这些都是在具体子类中被各自实现了,所以各个子类中有一些细微差异)。
public static void main(String[] args) {
Collection d=new ArrayList();
d.add("Hello");
d.add("Hello");
d.add("World");
Iterator it=d.iterator();
//当然,你用for循环也没问题= -
while(it.hasNext()){//判断是否还有元素,没了就跳出
//这里向下造型,当然你直接打印it.next()也没问题,
//不过万一会用到String类型中的某些方法,这样就比较方便了.
//从第一个元素开始拿,拿完之后自动指向下一个
String s = (String)it.next();
System.out.println(s);
}
it.remove();//移除迭代器曾经指向的最后一个元素。
System.out.println(d);
}
List和Collection一样,也是个接口。但不同的是之前的Collection可以有序储存,也可以无序储存不同,List类是仅有序存储的。有序的意思是和输入的顺序和打印的顺序一样,而不是指排序哦。List类和数组很像,很多操作可以通过整数下标来进行索引。
List的实例化就不说了,和Collection基本一样。由于是个接口,所以它从父类Collection中继承了它所有的方法,并且没有实现。除此之外,它还利用它的类数组特性,对某些函数进行了重载以及增加了新的函数。
这个add函数表示在指定位置index插入同集合中元素相同类型Element的对象element。注意,若原集合中有三个元素,其索引为0,1,2;则插入的指定位置包括集合中的这三个位置,以及之后的一个位置,即4.
public static void main(String args[]){
List list=new ArrayList();
list.add("Hello");
list.add("world");
list.add(1,"the");//储存顺序为:hello the world
list.add(3,"java");//储存顺序为:hello the world java
}
这个很好理解,get是从指定位置拿回元素,set是修改指定位置的元素,只不过会把之前的元素返回。
public static void main(String args[]){
List list=new ArrayList();
list.add("Hello");
list.add("world");
list.add(1,"the");//储存顺序为:hello the world
list.add(3,"java");//储存顺序为:hello the world java
list.get(3)//拿到java
list.set(3,"javaee")//返回java,储存顺序:hello the world javaee
}
这个就是List类的特有迭代器,除了Iterator中的方法,它有一些自己特色的方法。
向前遍历(必须在向后遍历之后)(所以基本不用):
public static void main(String[] args) {
List d=new ArrayList();
d.add("Hello");
d.add("Hello");
d.add("World");
ListIterator it=d.listIterator();
//当然,你用for循环也没问题= -
while(it.hasNext()){//判断是否还有元素,没了就跳出
//这里向下造型,当然你直接打印it.next()也没问题,
//不过万一会用到String类型中的某些方法,这样就比较方便了.
//从第一个元素开始拿,拿完之后自动指向下一个
String s = (String)it.next();
System.out.println(s);
}
//向前遍历,但必须在向后遍历之后才能执行
//可以理解为它们共用一个指针,该指针初始在开头
while(it.hasPrevious()){
String s = (String)it.previous();
System.out.println(s);
}
System.out.println(d);
}
除了利用Collection里面的toArray以及iterator进行遍历外(因为继承了Collection,所以只要Collection能用的,它也能用),它由于自己身的数组特性,还有另外一个遍历方法
public static void main(String[] args) {
List d=new ArrayList();
d.add("Hello");
d.add("Hello");
d.add("World");
for(int i=0;i<d.size();i++){//利用size方法
System.our.println(d.get(i))//利用get方法。
}
}
public static void main(String[] args) {
List d=new ArrayList();
d.add("Hello");
d.add("Hello");
d.add("World");
Iterator it=d.iterator();
while(it.hasNext()){
String s= (String)it.next();
System.our.println(s)
}
}
public static void main(String[] args) {
List d=new ArrayList();
d.add("Hello");
d.add("Hello");
d.add("World");
for(Iterator it=d.iterator();it.hasNext;){
String s= (String)it.next();
System.our.println(s)
}
}
两种方法差不多,都可以遍历,只不过for方法中的it在for执行完了就是垃圾,会被回收,所以效率会高一些。但是while方法会比较明确。
为了不用向下转型,很多人会这么写
class Student{
private int age;
private String name;
public Student(int age, String name){
this.age=age;
this.name=name;
}
public int getage(){
return age;
}
public String getname(){
return name;
}
}
public static void main(String[] args) {
List d=new ArrayList();
d.add(new Student(10,"Hello"));
d.add(new Student(20,"World"));
while(it.hasNext()){
//这下打印的是10和world。
//调用完next之后它会自动指向下一个
//所以不要在一次循环中调用两次
//用向下转型可以避免哦!!!!!
System.our.println(it.next().getage+it.next().getage)
}
}
public static void main(String[] args) {
List d=new ArrayList();
d.add("Hello");
d.add("Hello");
d.add("World");
ListIterator it=d.listIterator();
while(it.hasNext()){
String s= (String)it.next();
System.our.println(s)
d.add("java");//这样会报错
}
}
由于it中存储的是修改前的集合信息,修改后的信息并没有实时更新到it中,这样就会导致it不认识现在的集合,所以报错。
解决办法1:调用ListIterator(注意,Iteratro里面没有!!)迭代器自己的add方法
public static void main(String[] args) {
List d=new ArrayList();
d.add("Hello");
d.add("the");
d.add("World");
ListIterator it=d.listIterator();
while(it.hasNext()){
String s= (String)it.next();
System.our.println(s);
if(s.equals("the")){
it.add("java");
}
}
System.our.println(d)//输出 hello the java world加在当前
}
解决方法2:用List特有的遍历方法,size+get+for循环
public static void main(String[] args) {
List d=new ArrayList();
d.add("Hello");
d.add("the");
d.add("World");
for(int i=0;i<d.size();i++){
String s= d.get(i);
System.our.println(s);
if(s.equals("the")){
it.add("java");
}
}
System.our.println(d)//输出 hello the world java 加在最后
}