上篇已经总结了常用集合类的一些基本特征以及他们之间的区别,下面,再对集合类部分进行总结
一、集合类的常用方法
1、remove方法:移除元素操作,下面以ArrayList为例。
import java.util.*; public class Demo_JiHeLei2{ //定义测试方法 public void test_1(){ //remove()方法test,一ArrayList为例 List lis = new ArrayList(); lis.add("a"); lis.add("b"); lis.remove(1);//根据索引移除元素 lis.remove("b");//根据元素移除 } }
总的来说,remove参数可以是索引和具体元素;另外还有可能是两个参数,具体的其他方法可以参看API文档,这里不累赘介绍 了。
2、遍历方法
a、首先,对于最常用的List而言, 遍历的方法主要有一下三种,一ArrayList为例
for()循环遍历,这个方法和普通的数组遍历方法时一样的
for(int i = 0;i<lis.size();i++){ System.out.println(lis.get(i)); }
for each的方法,具体用法请看一下代码
List<String> lis = new Array<String>(); //注意,使用for each 遍历时,需要将集合类定义为泛型,具体泛型的知识将在下面总结。 for(String a : lis){ System.out.println(a); } //当然,如果不将集合类定义为泛型,也可以调用toArray()来获取当前集合类对象对应的Object数组然后再利用for each来遍历的
另外,对于集合类,有一个最通用的方法就是通过迭代器来遍历,请看以下代码理解:
//利用迭代器遍历 Iterator it = lis.iterator();//迭代器中有相应的方法可以用于遍历时游标是否尽头(hasNext())和get相应元素的方法(next()) while(it.hasNext()){ System.out.println(it.next()); } while(it.hasNext()){ System.out.println(it.next()); }
对于同样有游标的Vector遍历方法其实是一样的。
b、由于Set的子类没有对应的游标,只能通过迭代器来获取集合中元素的对应某个排列顺序,然后进行遍历,注意每次遍历的结果不一定,因为每次迭代器获取的元素排列都是随机的,这也说明Set下的元素是无顺序的,请看一下代码:
public void treeSet(){ HashSet hs = new HashSet(); hs.add("a"); hs.add("b"); hs.add("b"); hs.add(null); System.out.println(hs.size()); //遍历方式 Iterator it = hs.iterator(); while(it.hasNext()){ System.out.println(it.next());//由于set下的实现类对应的对象中元素中无序,所以输出值每次不一定相同 } }
d、对于Map下面的常用的一个之类HashMap的遍历方法也是迭代器,其中有两种方法遍历,一种是通过遍历key,然后调用相应的方法获得相应元素的值;另外一种方法是通过entry比遍历。
//1、方法一利用迭代器通过key遍历 Iterator it1 = mh1.keySet().iterator(); int i = 0; while(it1.hasNext()){ i++; System.out.println("key" + i + "=" + it1.next());//遍历顺序从结尾处开始吗?HashMap存储的东西是无顺序的! } //2、方法二利用迭代器通过entry遍历 Iterator it2 = mh1.entrySet().iterator(); while(it2.hasNext()){ Map.Entry entry = (Map.Entry)it2.next(); System.out.println(entry.getKey() + ":" + entry.getValue()); } /*总结:对于iterator而言,用什么类的iterator方法构造出来, 它next方法返回的对象就是构造它的那个对象类型 */
二、泛型的总结
1、什么是泛型,请先看一下例子:
import java.util.*; public class Demo_FanXing{ public void test_FanXing(){ //泛型的定义如下,以ArrayList为例 List<String> lis = new ArrayList<String>();//在<>里面传递一个类型参数String,所以说,泛型其实可以理解为参数在初始化的时候传入的一个类 lis.add("a"); lis.add(new Integer(1));//报错,泛型集合类中只能加同种元素,本例中只能加String类型 } }
由上面代码可知,泛型,其实就是一个类再初始化时传入一个类型参数。在集合类中,一个泛型的集合类只能存储同种元素,其实和普通数组一样,只不过可以相应地变化长度罢了。
2、使用泛型的好处和必要:在集合类中,泛型的使用使得编程变得灵活起来,将类型作为参数传入,既是java多态的典型表现,又大大地增加程序的安全性。具体泛型的使用有诸多要注意的地方,之后还需要进一步学习。
三、equals和==号使用在集合类中的注意事项。
1、equals和==的区别和联系:
首先要知道,java是没有指针的概念的,但是,java当中有一个和指针很像的机制:对象的引用指向内存中的对象,着其实就是提醒我们在思考的时候注意运用内存思维来思考程序的构建以及运行。每个对象的引用其实就相当于c语言里面的指针。
在编程中,很多时候我们需要知道不同引用是否指向同一个对象,这时,我们可以通过==号来进行比较,而Object最初的equals方法的作用和==其实是一样的。但是,在Object的子类中,很多实现类都重载了equals方法以实现更丰富的功能,请先看下面的例子:
public void methotFirst_equals(){ String test1 = "a"; String test2 = "a"; boolean b1 = (test1==test2);//输出结果为true boolean b2 = test1.equals(test2);//输出结果为true System.out.println("==比较指向同一对象的两个引用的结果 = " + b1); System.out.println("equals比较指向同一对象的两个引用的结果 = " + b2); }
显然,在字符串对象中,并没有重载equals和==,使用两者并无明显区别。但是,请看下面例子:
public void methot1(){ Integer test1 = new Integer(1); Integer test2 = new Integer(1); boolean b1 = (test1==test2);//输出结果为false boolean b2 = test1.equals(test2);//输出结果为true System.out.println("==比较指向同一对象的两个引用的结果 = " + b1); System.out.println("equals比较指向同一对象的两个引用的结果 = " + b2); }
通过对比上面两个例子,我们可以发现:==结果为true的两个引用一定指向同一个对象,也就是说==可以比较两个对想的引用是否指向同一个对象;equals有时候和==功能是一样的,但是更多时候,它可以实现更丰富的比较:例如在Integer类中,它可以比较两个Integer对象的内部数据是否一样,而不是是否是同一个对象。
2、了解了==和equals的区别后,我们再讨论下在集合类中两者如何用的问题。
首先,看一下的简单例子:
public void method2(){ List lis_1 = new ArrayList(); lis_1.add("a"); lis_1.add("b"); List lis_2 = new ArrayList(); lis_2.add("a"); lis_2.add("b"); boolean b1 = (lis_1==lis_2);//输出结果为false,因为是不同对象,在内存中的位置不同 boolean b2 = lis_1.equals(lis_2);//输出结果为true,因为ArrayList的equals方法有比较对象之间得内部数据是否相等的功能 System.out.println("==比较有相同元素的不同集合结果 = " + b1); System.out.println("equals比较有相同元素的不同集合结果 = " + b2); }
总结:List实现类的equals方法对Object的方法进行了重载,导致其调用时可以比较对象内部的元素是否一样,所以就算是不同对象,只要内部的元素一样,结果还是true。
下面我们看看Set的实现类equals和==号的区别。
public void method4(){ Set hs_1 = new HashSet(); hs_1.add("a"); hs_1.add("b"); Set hs_2 = new HashSet(); hs_2.add("a"); hs_2.add("b"); boolean b1 = (hs_1==hs_2);//输出结果为false boolean b2 = hs_1.equals(hs_2);//输出结果为true System.out.println("==比较两个具有相同元素的HashSet对象的结果" + b1); System.out.println("equals比较两个具有相同元素的HashSet对象的结果" + b2); }
发现Set下面额子类和List下面的的子类的equals方法具有同样地功能。
总结:在Collection下的所有子类,equals 方法会比较集合中的元素是否相等,进而得出结果。
最后,在Map中的集合类却有不同的情况,请看以下代码:
public void method5(){ Map hm_1 = new HashMap(); hm_1.put("1","a"); hm_1.put("2","b"); Map hm_2 = new HashMap(); hm_2.put("1","a"); hm_2.put("2","b"); boolean b1 = (hm_1==hm_2);//输出结果为false boolean b2 = hm_1.equals(hm_2);//输出结果为true System.out.println("==比较两个具有相同元素的HashMap对象的结果" + b1); System.out.println("equals比较两个具有相同元素的HashMap对象的结果" + b2); }
以上结果表明,当HashMap中的不同对象对应key值和value值一样的时候,返回的是true,这很好理解,但是,对于key不同但是value值一样或者key一样value不同的两个对象会有什么结果呢?请看以下代码
//相同key值,不同value下equals的执行情况 public void method6(){ Map hm_1 = new HashMap(); hm_1.put("1","a"); hm_1.put("2","b"); Map hm_2 = new HashMap(); //相同的key值,不同的value值 hm_2.put("1","c"); hm_2.put("2","d"); boolean b1 = (hm_1==hm_2);//输出结果为false boolean b2 = hm_1.equals(hm_2);//输出结果为false System.out.println("==比较两个具有相同key值不同value值的HashMap对象的结果" + b1); System.out.println("equals比较两个具有相同key值不同value值的HashMap对象的结果" + b2); } //不同key值,相同value下equals的执行情况 public void method7(){ Map hm_1 = new HashMap(); hm_1.put("1","a"); hm_1.put("2","b"); Map hm_2 = new HashMap(); //相同的key值,不同的value值 hm_2.put("0","a"); hm_2.put("1","b"); boolean b1 = (hm_1==hm_2);//输出结果为false boolean b2 = hm_1.equals(hm_2);//输出结果为false System.out.println("==比较两个具有不相同key值相同value值的HashMap对象的结果" + b1); System.out.println("equals比较两个具有不相同key值相同value值的HashMap对象的结果" + b2); }
显然,有以上代码可知:Map类中只要key值和value值有一个不等,返回的结果都是false,这表明我们在继承Map接口时,重载equals 方法时需要同时比较key值和value值是否相等。