黑马程序员——java基础知识之泛型、集合(Map、工具类等)
来源:互联网 发布:js设置button颜色 编辑:程序博客网 时间:2024/06/05 03:59
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
(一)、泛型
1、泛型:
JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。
2、泛型有什么好处?
①将运行时期出现问题ClassCastException,转移到了编译时期。,
方便于程序员解决问题。让运行时问题减少,安全。,
②避免了强制转换麻烦。
3、泛型的格式
泛型格式:通过<>来定义要操作的引用数据类型。
4、在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,
只要见到<>就要定义泛型。
其实<> 就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
例子程序:
class GenericDemo { public static void main(String[] args) { //给集合加泛型 ArrayList<String> al = new ArrayList<String>(); al.add("abc01"); al.add("abc0991"); al.add("abc014"); //al.add(4);//al.add(new Integer(4)); //注意迭代器也要加泛型 Iterator<String> it = al.iterator(); while(it.hasNext()) { String s = it.next(); System.out.println(s+":"+s.length()); } }}
例子程序:
注意比较器的时候使用泛型:
class GenericDemo2 { public static void main(String[] args) { TreeSet<String> ts = new TreeSet<String>(new LenComparator()); ts.add("abcd"); ts.add("cc"); ts.add("cba"); ts.add("aaa"); ts.add("z"); ts.add("hahaha"); Iterator<String> it = ts.iterator(); while(it.hasNext()) { String s = it.next(); System.out.println(s); } }}//给比较器加泛型class LenComparator implements Comparator<String>{ public int compare(String o1,String o2) { int num = new Integer(o2.length()).compareTo(new Integer(o1.length())); if(num==0) return o2.compareTo(o1); return num; }}
5、泛型定义在类上
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,
早期定义Object来完成扩展。
现在定义泛型来完成扩展。
例子程序:
class Worker{}//泛型前做法。class Tool{ private Object obj; public void setObject(Object obj) { this.obj = obj; } public Object getObject() { return obj; }}//泛型后的做法class Utils<QQ>{ private QQ q; public void setObject(QQ q) { this.q = q; } public QQ getObject() { return q; }}class GenericDemo3{ public static void main(String[] args) { //加泛型后 Utils<Worker> u = new Utils<Worker>(); u.setObject(new Student()); Worker w = u.getObject();; //加泛型前 /* Tool t = new Tool(); t.setObject(new Student()); Worker w = (Worker)t.getObject(); */ }}
5、泛型定义在方法上
①泛型类定义的泛型,在整个类中有效。如果被方法使用,
那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
②为了让不同方法可以操作不同类型,而且类型还不确定。
那么可以将泛型定义在方法上。
例子程序:
class Demo{ //把泛型定义在方法上 public <T> void show(T t) { System.out.println("show:"+t); } public <Q> void print(Q q) { System.out.println("print:"+q); } public static <W> void method(W t) { System.out.println("method:"+t); }}class GenericDemo4 { public static void main(String[] args) { Demo d = new Demo(); //调方法时你传什么类型,方法使用什么类型 d.show("haha"); //d.show(4); d.print(5); d.print("hehe"); d.show(new Integer(4)); d.print("hah"); }}
注意:
①泛型定义在类中和定义在方法上,可以一起使用
②静态方法不可以访问类上定义的泛型。静态方法上使用泛型,要把泛型定义在方法上。它的格式是:public static void method(W t)
6、泛型定义在接口中
//接口定义泛型interface Inter<T>{ void show(T t);};//实现类不知道什么类型,也使用泛型,实现Inter接口class InterImpl<T> implements Inter<T>{ public void show(T t) { System.out.println("show :"+t); }}class GenericDemo5 { public static void main(String[] args) { InterImpl<Integer> i = new InterImpl<Integer>(); i.show(4); }}
7、泛型的限定
? 通配符。也可以理解为占位符。
泛型的限定:
? extends E: 可以接收E类型或者E的子类型。上限。
? super E: 可以接收E类型或者E的父类型。下限
例子程序:
//程序的一部分,利用泛型可以接受Person类和Person的子类,也就是上限public static void printColl(Collection<? extends Person> al) { Iterator<? extends Person> it = al.iterator(); while(it.hasNext()) { System.out.println(it.next().getName()); } }
总结:
对泛型的定义:
第一、定义泛型:当又不确定的类型需要传入到集合中,需要定义泛型。
第二、定义泛型类:如果类型确定后,所操作的方法都是属于此类型,则定义泛型类。
第三、定义泛型方法:如果定义的方法确定了,里面所操作的类型不确定,则定义泛型方法。
(二)、集合框架(容器)之Map
Map集合:该集合存储键值对。一对一对往里存。而且要保证键的唯一性。
Map的主要方法:
1,添加。
put(K key, V value)
putAll()
2,删除。
clear()
remove(Object key)
3,判断。
containsValue(Object value)
containsKey(Object key)
isEmpty()
4,获取。
get(Object key)
size()
values()
entrySet()
keySet()
Map的主要子类:
Map
|–Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低。
|–HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。
|–TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。
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","wnagwu")); 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集合的两种取出方式:
①Set keySet:将map中所有的键存入到Set集合。因为set具备迭代器。
所有可以迭代方式取出所有的键,在根据get方法。获取每一个键对应的值。
Map集合的取出原理:将map集合转成set集合。在通过迭代器取出。
②Set<> entrySet:将map集合中的映射关系存入到了set集合中,
而这个关系的数据类型就是:Map.Entry
Entry其实就是Map中的一个static内部接口。
注意:为什么要定义在内部呢?
因为只有有了Map集合,有了键值对,才会有键值的映射关系。
关系属于Map集合中的一个内部事物。而且该事物在直接访问Map集合中的元素。
例子程序:
import java.util.*;class MapDemo2 { public static void main(String[] args) { Map<String,String> map = new HashMap<String,String>(); map.put("02","zhangsan2"); map.put("03","zhangsan3"); map.put("01","zhangsan1"); map.put("04","zhangsan4");//利用第二种方式,entrySet();//将Map集合中的映射关系取出。存入到Set集合中。Set<Map.Entry<String,String>> entrySet = map.entrySet(); Iterator<Map.Entry<String,String>> it = entrySet.iterator(); while(it.hasNext()) { Map.Entry<String,String> me = it.next(); String key = me.getKey(); String value = me.getValue(); System.out.println(key+":"+value); } /*//第一种方法:利用keySet(); //先获取map集合的所有键的Set集合,keySet(); Set<String> keySet = map.keySet(); //有了Set集合。就可以获取其迭代器。 Iterator<String> it = keySet.iterator(); while(it.hasNext()) { String key = it.next(); //有了键可以通过map集合的get方法获取其对应的值。 String value = map.get(key); System.out.println("key:"+key+",value:"+value); } */ }}
Map的练习题:训练两种获取map集合元素的方法
package cn.dhjJH;import java.util.*;/*每一个学生都有对应的归属地。学生Student,地址String。学生属性:姓名,年龄。注意:姓名和年龄相同的视为同一个学生。保证学生的唯一性。步骤:1,描述学生。2,定义map容器。将学生作为键,地址作为值。存入。3,获取map集合中的元素。*/public class Test05 { public static void main (String[] args){ HashMap<Student,String> hm = new HashMap<Student,String>(); hm.put(new Student("zhang1",22), "shanghai"); hm.put(new Student("zhang2",25), "wuhan"); hm.put(new Student("zhang3",26), "changsha"); hm.put(new Student("zhang4",21), "zhuzhou"); //第一种获取map集合中元素的方法,通过keySet方法 Set<Student> keySet = hm.keySet(); Iterator<Student> it = keySet.iterator(); while(it.hasNext()){ Student stu = it.next(); String adr = hm.get(stu); System.out.println(stu.getName()+"..."+stu.getAge()+"..."+adr); } //第二种获取map集合元素的方法,通过entrySet方法 Set<Map.Entry<Student,String>> entrySet = hm.entrySet(); Iterator<Map.Entry<Student,String>> its = entrySet.iterator(); while(its.hasNext()){ //用Map.Entry键值关系来接收,迭代器后的元素 Map.Entry<Student, String> me = its.next(); Student st = me.getKey(); String adrrs = me.getValue(); System.out.println(st.getName()+"..."+st.getAge()+"..."+adrrs); } }}class Student implements Comparable<Student>{ private String name; private int age; public Student(String name, int age) { super(); this.name = name; this.age = age; } //获取name和age的方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //重写了排序的方法,提供treeSet的集合排序方法,使Student类具有比较性 public int compareTo(Student s){ int sum = new Integer(this.age).compareTo(new Integer(s.age)); if(sum==0) return this.getName().compareTo(s.getName()); return sum; } //重写hashCode和equals方法,当使用哈希表的数据结构式,保证元素不会重复。 public int hashCode(){ return name.hashCode()+age*39; } public String toString(){ return name+":"+age; } public boolean equals(Object obj){ if(!(obj instanceof Student)) throw new ClassCastException("类型不匹配"); Student s = (Student)obj; return this.name.equals(s.name)&&this.age==s.age; }}
上一个例子改变:通过treeMap排序:
//Student的外部添加一个比较器class StuNameComparator implements Comparator<Student>{ public int compare(Student s1,Student s2) { int num = s1.getName().compareTo(s2.getName()); if(num==0) return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); return num; }}class MapTest2{ public static void main(String[] args) { //通过TreeMap进行元素的排序 TreeMap<Student,String> tm = new TreeMap<Student,String>(new StuNameComparator()); tm.put(new Student("blisi3",23),"nanjing"); tm.put(new Student("lisi1",21),"beijing"); tm.put(new Student("alisi4",24),"wuhan"); tm.put(new Student("lisi1",21),"tianjin"); tm.put(new Student("lisi2",22),"shanghai"); //使用Map类的entrySet方法获取Map容器中的元素 Set<Map.Entry<Student,String>> entrySet = tm.entrySet(); Iterator<Map.Entry<Student,String>> it = entrySet.iterator(); while(it.hasNext()) { Map.Entry<Student,String> me = it.next(); Student stu = me.getKey(); String addr = me.getValue(); System.out.println(stu+":::"+addr); } }}
练习3:
/*练习:"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("ak+abAf1c,dCkaAbc-defa"); System.out.println(s); } //定义方法 public static String charCount(String str) { //把字符串转为数组 char[] chs = str.toCharArray();//用TreeMap容器来转键值对数据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();//通过entrySet方法,获取TreeMap里面的每一个元素 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(); }}
Map的扩展应用:
在很多项目中,应用比较多的是一对多的映射关系,这就可以通过嵌套的形式将多个映射定义到一个大的集合中,并将大的集合分级处理,形成一个体系。
/*map扩展知识。map集合被使用是因为具备映射关系。"yureban" Student("01" "zhangsan");"yureban" Student("02" "lisi");"jiuyeban" "01" "wangwu";"jiuyeban" "02" "zhaoliu";一个学校有多个教室。每一个教室都有名称。*/import java.util.*;class Student{ private String id; private String name; Student(String id,String name) { this.id = id; this.name = name; } public String toString() { return id+":::"+name; }}class MapDemo3{//第一种方法:是通过czbk的hashMap集合,嵌套List集合。 public static void demo() { HashMap<String,List<Student>> czbk = new HashMap<String,List<Student>>(); List<Student> reyu = new ArrayList<Student>(); List<Student> jiuye = new ArrayList<Student>(); czbk.put("yureban",reyu); czbk.put("jiuyeban",jiuye); reyu.add(new Student("01","zhagnsa")); reyu.add(new Student("04","wangwu")); jiuye.add(new Student("01","zhouqi")); jiuye.add(new Student("02","zhaoli")); Iterator<String> it = czbk.keySet().iterator(); while(it.hasNext()) { String roomName = it.next(); List<Student> room = czbk.get(roomName); System.out.println(roomName); getInfos(room); } } public static void getInfos(List<Student> list) { Iterator<Student> it = list.iterator(); while(it.hasNext()) { Student s = it.next(); System.out.println(s); } } public static void main(String[] args) { demo(); /* //第二种方法是HashMap集合中嵌套HashMap集合。 HashMap<String,List<Student>> czbk = new HashMap<String,List<Student>>(); HashMap<String,String> yure = new HashMap<String,String>(); HashMap<String,String> jiuye = new HashMap<String,String>(); czbk.put("yureban",yure); czbk.put("jiuyeban",jiuye); yure.put("01","zhagnsan"); yure.put("02","lisi"); jiuye.put("01","zhaoliu"); jiuye.put("02","wangwu"); //遍历czbk集合。获取所有的教室。 Iterator<String> it = czbk.keySet().iterator(); while(it.hasNext()) { String roomName = it.next(); HashMap<String,String> room = czbk.get(roomName); System.out.println(roomName); getStudentInfo(room); }// getStudentInfo(jiuye);// getStudentInfo(yure);*/ } public static void getStudentInfo(HashMap<String,String> roomMap) { Iterator<String> it = roomMap.keySet().iterator(); while(it.hasNext()) { String id = it.next(); String name = roomMap.get(id); System.out.println(id+":"+name); } }}
(三)、collections工具类
1、collections有什么作用?
它的出现给集合操作提供了更多的功能。这个类不需要创建对象,内部提供的都是静态方法。 在Collections工具类中大部分方法是用于对List集合进行操作的,如比较,二分查找,随机排序等。
2、collections的方法
1、查找
Tmax(Collection coll);//根据集合的自然顺序,获取coll集合中的最大元素
Tmax(Collection coll,Comparator< T> comp);//根据指定比较器comp的顺序,获取coll集合中的最大元素
intbinarySearch(Lsit< Comparable< T>> list,T key);//二分法搜索list集合中的指定对象
2、替换
voidfill( list,obj);//将list集合中的全部元素替换成指定对象obj
booleanreplaceAll(List lsit,T oldVal,T newVal);//用newVal替换集合中的oldVal值
void swap(Listlist,int i,int j);/在指定列表的指定位置处交换元素
3排序:
void shuffle(List list);//使用默认随机源对list集合中的元素进行随机排序
void sort(Lsit list);//根据自然顺序对list集合中的元素进行排序
voidsort(List lsit,Comparator< T> c);//根据指定比较器c的排序方式对list集合进行排序
4、反转
reverse(List list);//反转list集合中元素的顺序
Comparator reverseOrder();//返回一个比较器,强行逆转了实现Comparable接口的对象的自然顺序
ComparatorreverseOrder(Comparator cmp);//返回一个比较器,强行逆转了指定比较器的顺序
5、同步的集合
ListsynchronizedList(List list);//返回支持的同步(线程安全的)List集合
(四)用于操作数组的工具类Arrays
1、Arrays的特点
Arrays是用于操作数组的工具类。里边的方法也全是静态的。不需要创建对象。
2、Arrays类中的主要方法:
1、Lsit asList(T… a);//将数组转换为集合
注意:
a、将数组转换成集合,不可使用集合的增删方法,因为数组的长度是固定的。如果进行增删操作,则会产生UnsupportedOperationException的编译异常。
b、如果数组中的元素都是对象,则变成集合时,数组中的元素就直接转为集合中的元素。
c、如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
2、binarySearch():二分查找方法,fill():替换方法,sort():排序方法等
特点:可对数组元素进行相应操作,可以接受除boolean之外的其他各种基本数据类型及有序的引用类型数组的参数,且还可以对指定元素的范围,并可根据指定比较器进行相应的操作。
如:sort(T[]a,Comparator< T> c)
fill(int[]a,int from,int to)等
3、String toString();//可以接收各种数组类型参数,并返回指定数组内容的字符串表现形式。
4、sort()排序方法:Arrays.sort();
例子小程序片段:
String[] arr = {"abc","cc","kkkk"};List<String> list = Arrays.asList(arr);sop("contains:"+list.contains("cc"));
(五)集合变数组
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,指定类型的数组到底要定义多长呢? 当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。长度为集合的size。 当指定类型的数组长度大于了集合的size,就不会新创建了数组。而是使用传递进来的数组。 所以创建一个刚刚好的数组最优。 2,为什么要将集合变数组? 为了限定对元素的操作。不需要进行增删了。 */ String[] arr = al.toArray(new String[al.size()]); System.out.println(Arrays.toString(arr)); }}
(六)增强For循环
它的格式是:
for(类型 变量名 : 要遍历的集合或数组){
}
注意:
对集合进行遍历。
只能获取集合元素。但是不能对集合进行操作。
迭代器除了遍历,还可以进行remove集合中元素的动作。
如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。
传统for和高级for有什么区别呢?
高级for有一个局限性。必须有被遍历的目标。
建议在遍历数组的时候,还是希望是用传统for。因为传统for可以定义脚标。
例子程序:
ArrayList<String> al = new ArrayList<String>(); al.add("abc1"); al.add("abc2"); al.add("abc3");for(String s : al) { System.out.println(s); }
(六)、方法的可变参数
①如果一个方法在参数列表中传入多个参数,个数不确定,那么每次都要复写该方法。这时可以用数组作为形式参数。但是在传入时,每次都需要定义一个数组对象,作为实际参数。在JDK1.5版本后,就提供了一个新特性:可变参数。
②可变参数其实就是数组参数的简写形式。不用每一次都手动的建立数组对象。只要将要操作的元素作为参数传递即可。隐式将这些参数封装成了数组。
③在使用时注意:可变参数一定要定义在参数列表的最后面。
例子程序:
public static void main(String[] args) { show("haha",2,3,4,5,6); } public static void show(String str,int... arr)//...就表示可变参数 { System.out.println(arr.length); }
(七)、静态导入
①写法:
import staticjava.util.Arrays.*;//导入的是Arrays这个类中的所以静态成员。
import staticjava.lang.System.*//导入了Ssytem类中所以静态成员。
没加static导入的是类,加上static导入的全是某一个类中所以的静态成员。这样写在调用该类的静态方法时可以不用再写类名。如:Arrays.sort(数组);就可以直接写sort(数组);
②注意:
当导入的两个类中有同名成员时,需要在成员前加上相应的类名。
当类名重名时,需要指定具体的包名。当方法重名时,指定具体所属的对象或者类。
- 黑马程序员——java基础知识之泛型、集合(Map、工具类等)
- 黑马程序员——Java集合框架(三)之Map集合、Collections与Arrays工具类
- 黑马程序员——集合框架-Map、集合工具类
- 黑马程序员——Java语言基础:集合框架(Collection、Map,工具类Collections、Arrays)
- 黑马程序员——JAVA笔记之集合框架(泛型、Map等)
- 黑马程序员——Java基础知识——集合框架、集合工具类、Arrays
- 黑马程序员——java基础知识之集合框架(容器)
- 黑马程序员-java基础之集合Map集合,Collections,Arrays工具类
- 黑马程序员——Java基础之Map集合
- 黑马程序员——JAVA基础之Map集合
- 黑马程序员——Java集合之Map
- 黑马程序员——Java集合之Map
- 黑马程序员——java基础之Map集合
- 黑马程序员——Java学习日志之Map集合
- 黑马程序员————java基础---------集合之Map及Collections集合类
- 黑马程序员——Java基础--Map集合、工具类、其他对象
- 黑马程序员—java基础学习--Map集合、Collections,Arrays工具类
- 黑马程序员——Java Map集合
- Linux中建立新的进程,父进程等待子进程的退出
- Spring工作原理分析
- Win32 LoadLibrary 失败的2种可能原因
- Spring batch笔记
- CSS+DIV 设计的页面,在除了chrome、360浏览器外, 没有滚动条 不能下拉
- 黑马程序员——java基础知识之泛型、集合(Map、工具类等)
- Autoencoder
- UVA - 514 Rails 经典栈使用
- poj1861Network(最小生成树-克鲁斯卡尔算法)
- 用户态内核态通信 (一)
- NVMe设备命令大小限制
- 简单的传球游戏(矩阵)
- 对于校庆网站开发及上线的思考
- 动手实现 数据结构 之 “十字链表”