黑马程序员————学习日记【10】 【泛型、Map和Collections】

来源:互联网 发布:windows挂载ext4分区 编辑:程序博客网 时间:2024/06/03 17:53

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

 

 

Set:无序,不可以重复
 |--HashSet:数据结构是哈希表,线程是非同步的
    保证元素唯一性的原理:判断元素的hashCode值是否相同。如果相同,还会继续判断元素的equals方法,是否为true。

 |--TreeSet:可以对Set集合中的元素进行排序
    底层数据结构是二叉树
    保证元素唯一性的依据:compareTo方法return 0.
    
    只有HashSet才关联哈希值,TreeSet走的是二叉树。TreeSet是通过compareTo方法来确定元素是否相同。
    如果想TreeSet集合删除元素或者判断元素是否包含,走的都是CompareTo方法return 0.但凡返回0,认为元素是相同的。

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

    TreeSet的第二种排序方式
    当元素自身不具备比较性,或者具备的比较性不是所需要的,此时就需要让集合自身具备比较性。
    在集合一初始化时,就有了比较方式。

 

 

当元素自身不具备比较性,或者具备的比较性不是所需要的。这时需要让容器自身具备比较性。
定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数

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

 

/*练习:按照字符串长度排序字符串本身具备比较性,但是它的比较方式不是所需要的这时就只能使用比较器*/import java.util.*;class TreeSetTest{public static void main(String[] args) {TreeSet ts = new TreeSet(new StrLenComparator());ts.add("abcd");ts.add("cc");ts.add("cba");ts.add("aaa");ts.add("z");ts.add("hahahaha");Iterator it = ts.iterator();while(it.hasNext()){System.out.println(it.next());}}}class StrLenComparator implements Comparator{public int compare(Object o1,Object o2){String s1 = (String)o1;String s2 = (String)o2;/*if(s1.length()>s2.length())return 1;if(s1.length()==s2.length())return 0;*/int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));if(num==0)return s1.compareTo(s2);return num;}}


 

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

好处:
1、将运行时期出现的问题ClassCastException,转移到了编译时期方便于程序员解决问题,让运行时期问题减少,安全。

2、避免了强制转换的麻烦

泛型格式:通过<>来定义要操作的引用数据类型

在使用java提供的对象时,什么时候写泛型呢?

通常在集合框架中很常见,只要见到<>就要定义泛型,其实<>就是用来接收类型的。

当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可

class GenericDemo {public static void main(String[] args) {ArrayList<String> a1 = new ArrayList<String>();a1.add("abc01");a1.add("abc0991");a1.add("abc014");//a1.add(4);//a1.add(new Integer(4));Iterator<String> it = a1.iterator();while(it.hasNext()){String s = it.next();System.out.println(s+":"+s.length());}}}


 

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


特殊之处:
静态方法不可以访问类上定义的泛型。
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上

注意:泛型定义在方法上,需要放到返回值类型的前面,修饰符的后面。

 

 

?通配符,也可以理解为占位符。

泛型的限定:【泛型的高级应用,泛型的复合应用】

? extends E:可以接收E类型或者E的子类型,上限。
? super E:可以接收E类型或者E的父类型,下限。

 

 

 

Map集合:该集合存储键值对,一对一对往里存,而且要保证键的唯一性
 1,添加
  put(K key,V value)
  putAll(Map<? extends K,? extends V> m)

 2,删除
  clear()
  remove(Object key)

 3,判断
  containsValue(Object value)
  containsKey(Object key)
  isEmpty()

 4,获取
  get(Object key)
  size()
  values()

  entrySet()
  keySet()

Map
 |--Hashtable:底层是哈希表数据结构,不可以存入null键null值。
     该集合是线程同步的。【JDK1.0】效率低

 |--HashMap:底层是哈希表数据结构,允许使用null键和null值。
       该集合是不同步的。【JDK1.2】效率高

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

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

import java.util.*;class MapDemo {public static void main(String[] args) {Map<String,String> map = new HashMap<String,String>();//添加元素,当添加时出现相同的键,那么添加后的值会覆盖原有键//对应的值,并put方法会返回被覆盖的值。System.out.println("put:"+map.put("01","zhangsan1"));System.out.println("put:"+map.put("01","wangwu"));map.put("02","zhangsan2");map.put("03","zhangsan3");System.out.println("containsKey:"+map.containsKey("022"));//System.out.println("remove:"+map.remove("02"));System.out.println("get:"+map.get("023"));map.put("04",null);System.out.println("get:"+map.get("04"));//可以通过get方法的返回值来判断一个键是否存在。//通过返回null来判断。//获取map集合中所有的值Collection<String> coll = map.values();System.out.println(coll);System.out.println(map);}}

map集合的两种取出方式
1、Set<k keySet>:将map中所有的键存入到Set集合。因为set具备迭代器。
 所以可以迭代方式取出所有的键,再根据get方法,获取每一个键对应的值。

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

2、Set<Map.Entry<k,v>> entrySet:将map集合中的映射关系存入到了 set集合中,而这个关系的数据类型就是:Map.Entry

 

 

练习:
"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数,
希望打印结果:a(1)c(2)......

通过结构发现,每一个字母都有对应的次数,说明字母和次数之间都有映射关系

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

什么时候使用map集合呢?
当数据之间存在映射关系时,就要先想map集合。

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

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

3,遍历字符数组
 将每一个字母作为键去查map集合
 如果返回null,将该字母和1存入到map集合中
 如返回不是null,说明该字母 在map集合中已经存在并有对应此时
 那么就获取该次数并进行自增,然后将该字母和自增后的次数存入到
 map集合中,覆盖调用原理键所对应的值。

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

import java.util.*;class MapTest3 {public static void main(String[] args) {String s = charCount("aakb+fc-dabcd1ke,fa");System.out.println(s);}public static String charCount(String str){char[] chs = str.toCharArray();TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();int count = 0;for(int x=0; x<chs.length; x++){if(!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))continue;Integer value = tm.get(chs[x]);if(value!=null)count = value;count++;tm.put(chs[x],count);count  = 0;/*if(value==null){tm.put(chs[x],1);}else{value = value + 1;tm.put(chs[x],value);}*/}//System.out.println(tm);StringBuilder sb = new StringBuilder();Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();while(it.hasNext()){Map.Entry<Character,Integer> me = it.next();Character ch = me.getKey();Integer value = me.getValue();sb.append(ch+"("+value+")");}return sb.toString();}}


集合框架的工具类
Collections

比较对象大小要么compare要么compareTo

 

/*Arrays:用于操作数组的工具类里面都是静态方法asList:将数组变成list集合*/import java.util.*;class ArraysDemo {public static void main(String[] args) {//int[] arr = {2,4,5};//System.out.println(Arrays.toString(arr));String[] arr = {"abc","cc","kkkk"};/*问:把数组变成list集合有什么好处? 答:可以使用集合的思想和方法来操作数组中的元素注意:将数组变成集合,不可以使用集合的增删方法。因为数组的长度是固定的。containsgetindexOf()subList()如果增删,那么会发生UnsupportedOperationException*/List<String> list = Arrays.asList(arr);//sop("contains:"+list.contains("cc"));//list.add("qq");//UnsupportedOperationException//sop(list);//int[] nums = {2,4,5}; Integer[] nums = {2,4,5};List<Integer>li = Arrays.asList(nums);/*如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的元素。如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。*/sop(li);}public static void sop(Object obj){System.out.println(obj);}}


 

/*集合变数组Collection接口中的toArray方法*/import java.util.*;class CollectionToArray{public static void main(String[] args) {ArrayList<String> al = new ArrayList<String>();al.add("abc1");al.add("abc2");al.add("abc3");/*1、指定类型的数组到底要定义多长呢?(1)当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组,长度为集合的size;(2)当指定类型的数组长度大于了集合的size,就不会新创建数组,而是使用传递进来的数组,所以创建一个刚刚好的数组最优。2、为什么要将集合变数组?为了限定对元素的操作。不需要进行增删了。*/String[] arr = al.toArray(new String[al.size()]);sop(Arrays.toString(arr));}public static void sop(Object obj){System.out.println(obj);}}


 

高级for循环

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

}
对集合进行遍历
只能获取集合中的元素,但是不能对集合进行操作。

迭代器除了遍历,还可以进行remove集合中元素的动作
如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作

 

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

高级for有一个局限性,必须有被遍历的目标。
建议在遍历数组的时候,还是希望使用传统for,因为传统for可以定义角标。

 

/*JDK1.5版本出现的新特性方法的可变参数在使用时注意:可变参数一定要定义在参数列表最后面*/class ParamMethodDemo {public static void main(String[] args) {/*int[] arr = {3,4};show(arr);int[] arr1 = {2,3,4,5};show(arr1);*///虽然少定义了方法//但是每次都要定义一个数组,作为实际参数。show(2,4,5,6);/*可变参数,其实就是上一种数组参数的简写形式不用每一次都手动的建立数组对象只要将要操作的元素作为参数传递即可隐饰将这些参数封装成了数组*/}public static void show(int... arr){System.out.println(arr.length);}}


 

/*StaticImport 静态导入当类名重名时,需要指定具体的包名当方法重名时,指定具备所属的对象或者类*/import java.util.*;import static  java.util.Arrays.*;//导入的是Arrays这个类中的所有静态成员import static java.lang.System.*;//导入了System类中所有静态成员class StaticImport extends Object{public static void main(String[] args) {out.println("haha");int[] arr = {3,1,5};sort(arr);int index = binarySearch(arr,1);System.out.println(Arrays.toString(arr));System.out.println("Index="+index);}}


 

原创粉丝点击