首页 > 代码库 > 黑马程序员——【Java基础】——泛型、Utilities工具类、其他对象API
黑马程序员——【Java基础】——泛型、Utilities工具类、其他对象API
一、泛型
(一)泛型概述
1、泛型:JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制。
2、泛型技术是给编译器使用的技术,用于编译时期,确保类型的安全。
3、泛型的擦除:运行时,会将泛型去掉,生成class文件中的是不带泛型的,这个称为“泛型的擦除”。擦除泛型的原因是为了兼容运行时的类加载器。
4、泛型的好处:(1)将运行时期出现的问题ClassCastException,转移到了编译时期。方便于程序员解决问题,让运行时期问题减少、安全。(2)避免了强制转换的麻烦。
5、泛型的格式:通过<>来定义要操作的引用数据类型,例如:ArrayList<String>表示存入ArrayList集合中的元素必须为String类型
6、泛型补偿:在运行时,通过反射通过获取元素的类型(如Class clazz = “aa”.getClass(); clazz.getName();),不用使用再强制转换类型了。
7、在使用Java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,只要见到<>就要定义泛型。其实<>是用来接收引用类型的,但使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
8、关于参数化类型的几点说明:
(1)参数化类型与原始类型的兼容性
* 参数化类型可引用一个原始类型的对象,编译只是报警告。如:Collection<String>coll = new Vector();
* 原始类型可引用一个参数化类型的对象,编译报告警告。如:Collectioncoll = new Vector<String>(); 原来的方法接受一个集合参数,新类型也要能传进去。
(2)参数的类型不考虑类型参数的继承关系:
Vector<String> v = newVector<Objec>();//错误的。不写Object没错,写了就是明知故犯
Vector<Objec> v = newVector<String>();//错误的
(3)编译器不允许创建泛型变量的数组。即在创建数组实例时,数组的元素不能使用参数化的类型。如:Vector<Integer>vectorList[] = new Vector<Integer>[10];//错误的
(二)泛型限定
1、通配符“?”
当传入的类型不确定时,可以使用通配符“?”,也可以理解为占位符。使用通配符可以不用明确传入的类型,这样在使用泛型类或泛型方法时,提高了扩展性。
2、泛型限定
对于一个范围内的一类事物,可以通过泛型限定的方式定义,有两种方式:
(1)? extends E:可接收E类型或E类型的子类型,称为上限界定。如:ArrayList<? extends Number> x = new ArrayList<Integer>();
(2)? super E:可接收E类型或E类型的父类型;称为下限界定。如:ArrayList<? super Integer> x = new ArrayList<Number>();
3、泛型限定代码示例:
1 //人 父类 2 class Person{ 3 private String name; 4 Person(String name){ 5 this.name = name; 6 } 7 public String getName(){ 8 return name; 9 }10 }11 //学生 继承父类12 class Student extends Person{13 Student(String name){14 super(name);15 }16 }17 class Demo{18 public static void main(String[] args){19 ArrayList<Person> al = new ArrayList<Person>();20 al.add(new Person("abc1"));21 al.add(new Person("abc2"));22 al.add(new Person("abc3"));23 printColl(al);//父类对象的元素集合可以调用24 ArrayList<Student> al1 = new ArrayList<Student>();25 al1.add(new Student("abc2"));27 al1.add(new Student("abc--3"));28 printColl(al1); //子类对象的元素集合也可以调用29 }30 //定义一个上限的泛型方法31 public static void printColl(Collection<? extends Person> al){32 Iterator<? extends Person> it = al.iterator();33 while(it.hasNext()){34 System.out.println(it.next().getName());35 }36 }37 }
(三)泛型类
1、什么时候定义泛型类来完成扩展?
当类中要操作的引用数据类型不确定的时候,早期(1.4version)之前定义Object类来完成扩展。现在(version1.5)开始通过定义泛型来完成扩展。
2、泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
3、类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的。
4、泛型类示例代码:
1 //定义工具泛型类Utils 2 class Utils<QQ>{ 3 private QQ q; 4 public void setObject(QQ q){ 5 this.q == q; 6 } 7 Public QQ getObject(){ 8 Return q; 9 }10 }11 public class GenericClassDemo{12 public static void main(String[] args) {13 Utils<Worker> u = new Utils<Worker>();14 u.setObject(new Worker());15 Worker w = u.getObject();16 }17 }18 class Worker extends Person {19 public Worker() {20 super();21 }22 public Worker(String name, int age) {23 super(name, age);24 }25 @Override26 public String toString() {27 return "Worker:"+getName()+":"+getAge();28 }29 }
(四)泛型方法
1、一般泛型方法
(1)为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
(2)方法中上定义的泛型可以不和类泛型相同。
(3)泛型方法示例:
1 class Demo{2 public <T> void show( T t){3 System.out.println(t);4 }5 Public <Q> void print( Q q){6 System.out.println(q);7 }8 }
2、静态方法泛型
(1)特殊之处:Static方法不可以访问类上定义的泛型。
(2)如果静态方法操作的应用数据类型不确定,可以将方法泛型定义在方法上。
(3)如果静态方法使用泛型,只能将泛型定义在方法上。
(4)泛型代码示例:
1 public static <W> void method( W t){ 2 System.out.println( “method” + t ); 3 }
3、泛型方法的特点
(1)位置:用于放置泛型的类型参数的<>应出现在方法的其他所有修饰符之后和在方法的返回类型之前,也就是紧邻返回值之前,按照惯例,类型参数通常用单个大写字母表示。
(2)只有引用类型才能作为泛型方法的实际参数。
(3)除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符。
(4)普通方法、构造函数和静态方法中都可以使用泛型。
(5)可以用类型变量表示异常,称之为参数化的异常,可用于方法的throws列表中,但是不能用于catch子句中。
(6)在泛型中可同时有多个类型参数,在定义它们的<>中用逗号分开。
二、Utilities工具类
(一)概述
Utilites工具类包括:类Collections和类Arrays。它们包含的方法都是静态方法,不要创建对象,直接可以用类名调用。
(二)Collections
1、Collections是用于对“集合”进行操作的工具类。它里边的方法都是静态的,不需要创建对象。
2、Collections常见方法
(1)查找
max(Collection<? extends T> coll):根据集合的自然顺序,获取coll集合中的最大元素
max(Collection<? extends T> coll,Comparator<? super T> comp):根据指定比较器comp的顺序,获取coll集合中的最大元素
int binarySearch(Lsit<? extends Comparable<? super T>> list,Tkey):二分法搜索list集合中的指定对象
(2)替换
void fill(List<? super T> list, T obj):将list集合中的全部元素替换成指定对象obj
boolean replaceAll(List<T> lsit,T oldVal,T newVal):用newVal替换集合中的oldVal值
void swap(Listlist,int i,int j);/在指定列表的指定位置处交换元素
(3)排序:
void shuffle(List<?> list):使用默认随机源对list集合中的元素进行随机排序
void sort(Lsit<T> list):根据自然顺序对list集合中的元素进行排序
void sort(List<T> lsit,Comparator<? super T> c):根据指定比较器c的排序方式对list集合进行排序
(4)反转
reverse(List<?> list):反转list集合中元素的顺序
Comparator reverseOrder():返回一个比较器,强行逆转了实现Comparable接口的对象的自然顺序
Comparator reverseOrder(Comparator<T> cmp):返回一个比较器,强行逆转了指定比较器的顺序
(5)同步的集合
synchronizedList(List<T> list):返回支持的同步(线程安全的)List集合
synchronizedList(Map<K,V> m):返回支持的同步(线程安全的)Map集合
(三)Arrays
1、Arrays是用于操作数组的工具类,它包括的方法也全是静态的,不需要创建对象。
2、Arrays常见方法
(1)数组转成集合
Lsit<T> asList(T... a):将数组转换为集合。
注意:① 将数组转换成集合,不可使用集合的增删方法,因为数组的长度是固定的。如果进行增删操作,则会产生UnsupportedOperationException的编译异常。② 如果数组中的元素都是对象,则转成集合时,直接将数组中的元素作为集合中的元素进行存储。③ 如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素进行存储。
(2)查找、替换和排序
binarySearch():二分查找方法。
fill():替换方法。
sort():排序方法
(3)Arrays.toString():可以接收各种数组类型参数,并返回指定数组内容的字符串表现形式。
3、数组转成集合,代码示例:
1 class ArraysDemo{ 2 public static void main(String[] args){ 3 int[] arr = {2,4,5}; 4 System.out.println(Arrays.toString(arr));//转换为字符串形式 5 String[] arr = {"abc","cc","kkkk"};//字符串数组 6 List<String> list = Arrays.asList(arr); 7 sop("contains:"+list.contains("cc"));//判断是否存在"cc"这个元素 8 Integer[] nums = {2,4,5}; 9 List<Integer> li = Arrays.asList(nums);10 sop("asList--Integer[]转集合:" + li);11 }12 //打印方法13 public static void sop(Object obj) {14 System.out.println(obj);15 }16 }
(四)集合转数组
1、集合转数组:使用的是Cellction接口中的toArray方法。定义格式:<T> T[] toArray(T[] a);
2、集合转数组:可以对集合中的元素操作的方法进行限定,不允许对其进行增删。
3、toArray方法需要传入一个指定类型的数组,长度如何定义呢?
(1)如果数组长度小于了集合的size,方法会创建一个同类型并和集合相同size的数组。
(2)如果数组长度大于了集合的size,那么该方法会使用指定的数组存储集合中的元素,其他默认为null。
4、代码示例:
1 import java.util.ArrayList; 2 import java.util.Arrays; 3 import java.util.List; 4 public class ToArray { 5 public static void main(String[] args) { 6 List<String> list = new ArrayList<String>(); 7 list.add("abc1"); 8 list.add("abc2"); 9 list.add("abc3");10 String[] arr = list.toArray(new String[list.size()]); 11 System.out.println(Arrays.toString(arr));12 }13 }
三、JDK1.5新特性
(一)增强型for循环
1、格式:
for( 数据类型 变量名 : Collection集合或者数组) {
执行语句
}
2、说明
(1)对集合进行遍历。只能获取集合元素。但是不能对集合进行操作。可以看作是迭代器的简写形式。
(2)迭代器除了遍历,还可以进行remove集合中元素的动作。如果使用ListIterator,还可以在遍历过程中对集合进行增、删、改、查的操作。
3、传统for和高级for的区别:
(1)传统for循环可以完成对语句的多次操作,因为可以控制循环增量条件。
(2)高级for循环是一种简化形式,它必须有遍历目标,该目标要么是array或Collection单列集合,不可以直接遍历Map集合,但可以将Map集合转化为单列的Set集合,就可以使用。例如:
1 for( Map.Entry<Integer , String>) me : map.entrySet()){2 Integer key = me.getKey();3 String value =http://www.mamicode.com/ me.getValue();4 System.out.println(key + “::” +value);5 }
(二)函数可变参数
1、在JDK1.5版本后,就提供了一个新特性:可变参数。用来解决一个方法在参数列表中传入多个参数,个数不确定而每次都要复写该方法的问题。
2、可变参数其实就是数组参数的简写形式。只要将要操作的元素作为参数传递,就可以隐式将这些参数封装成了数组。
3、注意:可变参数一定要定义在参数列表的最后面。
4、示例代码如下
1 public static int newAdd(int a , int… arr){2 int sum = 0;3 for( int i = 0 ; i < arr.length ; i ++){4 sum + = arr[i];5 }6 return sum;7 }
(三)静态导入
1、写法示例:import static java.util.Collections.*;
加上static导入的是某一个类中所有的静态成员。这样写在调用该类的静态方法时可以不用再写类名。如Collections.max(list)可以简写为max(list)。
2、注意:
(1)当导入的两个类中有同名成员时,需要在成员前加上相应的类名。
(2)当类名重名时,需要指定具体包名。当方法重名时,指定具体所属的对象或者类。
3、静态导入示例:
1 import java.util.ArrayList; 2 import java.util.Collections; 3 import java.util.List; 4 import static java.util.Collections.*;//静态导入,其实到入的是类中的静态成员。 5 import static java.lang.System.*; 6 public class StaticImportDemo { 7 public static void main(String[] args) { 8 List<String> list = new ArrayList<String>(); 9 list.add("abc3");10 list.add("abc7");11 list.add("abc1");12 out.println(list);13 sort(list); 14 System.out.println(list);15 String max = max(list);16 System.out.println("max="+max); 17 }18 }
三、其他对象API
(一)System类
1、概述:System是描述系统一些信息的类,类中的属性和方法都是static的。
2、字段摘要
out:标准输出流。默认是控制台。
in:标准输入流。默认是键盘。
3、static方法
(1)Properties getProperties():获取系统的属性信息。
(2)String getProperty(String key):获取指定属性信息
(3)String setProperty(String key , String value):在系统内定义特有信息。
(4)Long currentTimeMillis():获取当前时间毫秒值。
(二)Runtime类
1、概述
(1)没有构造函数摘要,说明该类不可以创建对象。
(2)发现还有非静态方法,说明该类应该提供静态的返回该类对象的方法。
(3)只有一个,说明Runtime类是单例设计模式。
2、方法
(1)static Runtime.getRuntime():获取本类对象。
(2)Process exec(String command):在单独的进程中执行指定字符串命令。
3、示例代码:Runtime r = Runtime.getRuntime(); r.exec(“xxx.exe”);
(三)Math类
1、概述:Math 类包含用于执行基本数学运算的方法,该类全为静态方法。
2、常用方法
(1)double ceil(double d):返回大于指定数据的最小整数。
(2)double floor(double d):返回小于指定数据的最大整数。
(3)double pow(doublea , double b):返回a的b次方。
(4)long round(doubleb):返回b四舍五入的值。
(5)double random():返回正号的double值,是一个大于等于0.0且小于1.0的随机数。
3、Random类
此类的实例用于生成伪随机数流,有自身的方法,可以将相应的随机数强转为指定基本数据类型。例如:Random r = new Random(); r.nextInt();
(四)Date类
1、概述:Date类表示特定的瞬间,精确到毫秒。
2、创建日期对象的步骤:
(1)创建Date对象。
(2)创建日期对象格式,将时间模式封装到Simple DateFormat对象中。
(3)调用format方法对指定Date对象进行日期格式化。
(五)Calendar类
1、概述:Calendar是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OF_MONTH等日历字段之间的转换提供了一些方法。可以对年月日等时间进行获取,并提供了相应的子段值。
2、方法:
(1)基本获取时间
① 获取年份:Calendar.YEAR
② 获取月份:Calendar.MONTH
③ 获取日期:Calendar.DAY_OF_MONTH
④ 获取星期:Calendar.DAY_OF_WEEK
⑦ 获取秒数:Calendar.SECOND
(2)设置时间:可以通过YEAR、MONTH和DAY_OF_MONTH设置日历字段的值
① void add(int field , int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。
② int get(int field):获取指定的日历字段对应的时间值。
③ void set(int field , int value):将给定日历字段对应的时间值设置为给定值。
黑马程序员——【Java基础】——泛型、Utilities工具类、其他对象API