昨天晚上7点在长沙出发坐11个小时的火车回家,第一次坐硬卧回家还买到了一张下铺票,到底要比硬座舒服了很多。上午休整了半天下午就这干活,虽然放假但是手中的work哪能说停下就停下呢?毕竟也是自己喜欢的work。2016有很多事情都迫在眉睫,虽说是寒假但已然是1月18号,留给我的时间已经很紧张很紧张啦。回家带了5本书,一本Thinking In Java、一本Data Structures And Algorithm Analysis In Java、还有三本Android进阶,看起来任务还蛮重啊。
第一章,引论,主要介绍这本书的将要用到的一些基础知识,包括数学知识有级数、模运算、证明方法的归纳演绎等;包括Java的递归特性以及函数对象等。
Java中实现泛型的组件主要有四个,一是所有引用类型数据的存储操作方法接收的形参都用Object来表示,Object是所有对象的父类,也就意味着存储方法可以接收任意引用类型的参数,比如我们可以存出一个String类型的字符串,也可以是一个Student[] 类型的对象数组。而在读取方法中由于我们存储的类型Object类型,所以取出时也就必然是Object,那么问题来了,我们怎样还原到我们存储时的原本类型呢?这里就需要类型强制转换!把取出来的Object数据强制转换为原来的String字符串或者Student[]对象。具体看代码如下
package com.demo.datastructure;
/*
* 方法类,封装read()、write()方法
* read()---->return the stored value
* write(Object x)---->x is stored
* */
public class Method {
private Object storedData;
public Object read() {
return storedData;
}
public void write(Object x) {
storedData = x;
}
}
package com.demo.datastructure;
public class StorDataTest {
public static void main(String[] args) {
Method m = new Method();
m.write(45);
// 类型强制转换,或者调用toString()方法也可以
String result = (String) m.read();
System.out.println("result are:" + result);
}
}
二是基本类型的包装类的自动装箱、自动拆箱,在Java中虽然没一个引用类型都和Object类型相容,但是8种基本类型却不能与Object相容,所以就有了8种基本类型各自对应的包装类,比如int—->Integer、boolean—->Boolean。比如上面的m.write(45)
就是自动装箱,把基本类型的int型数据45自动装箱为Integer类型,有自动装箱自然就有自动拆箱,当取出数据时如果int i = m.read()
那么此时就把Integer类型自动拆箱为int类型。
三是使用接口类型表示泛型。我们考虑,通过比较对象数组找出最大项的问题,我们不能直接找出对象数组的最大元素。最简单的思路就是让我们的对象数组类实现Comparable接口,通过调用compareTo()
方法来确定数组元素的顺序,因为compareTo()
对所有的comparable都是现成可用的。看如下代码
package com.demo.findmax;
class FindMaxDemo {
/*
* return max item in arr
* precondition : arr.length > 0
* */
public static Comparable findMax(Comparable[] arr) {
int maxIndex = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i].compareTo(arr[maxIndex]) > 0) {
maxIndex = i;
}
}
return arr[maxIndex];
}
/*
* Test findMax on shape and String objects
* */
public static void main(String[] args) {
String[] st1 = {"Dell", "Jobs", "Bill", "Frank"};
System.out.println(findMax(st1));
}
}
这是我们要注意,第一,只有实现Comparable
接口的那些对象才能作为Comparable
数组的元素被传递,仅有comparaTo()
方法但并未实现Comparable
接口的对象不是Comparable
的,它不具备必须的IS-A关系;第二,如果Comparable
数组有两个不相容的对象,比如一个String
,一个Integer
,那么compareTo()
方法将抛出ClassCastException
异常;第三,一定要注意,基本类型不能作为Comparable
传递,但是他们的包装类可以,因为包装类实现了Comparable
接口;第四,接口究竟是不是标准的库接口倒不是必须的;最后,这个方案不是总能行的通,因为有时宣称一个类实现所需的借口是不可能的,例如一个类可能是标准库中的类,而接口是自定义的接口,这就行不通,再例如一个类是final类,那么我们就不可能再扩展它以创建一个新类。
四是数组类型的兼容性,在Java中数组是类型兼容的,称作covariant araay type
(协变数组类型),每个数组都会指明他所兼容的数据类型,如果把一个不兼容的类型插入到数组中,虚拟机将会抛出ArrayStoredException异常。不过有时为了避免类型混乱的问题发生,就需要特别这些数组不是类型兼容的。
Java5开始提供泛型支持,这些泛型类很容易使用。但是泛型类的api实现却不是那么容易的一件事情,内部编码非常复杂,在这里我们就不涉及。我们主要来看看下面几个方面。
首先是泛型类和接口的概念。泛型类在声明时需要为其指定一个或多个类型参数,这些类型参数放在类名后面的尖括号内,例如public class GenericDemo<String>
。也可以声明接口是泛型的,例如,在Java5以前Comparable接口不是泛型的,而他的compareTo()方法接收一个Object作为参数,于是传递到compareTo()方法的任何引用变量即使不是一个合理的类型也会编译通过,而只是在运行时抛出ClassCastException错误。在Java5中Comparable接口是支持泛型的。例如现在String类实现Comparable接口并有一个compareTo()方法,这个方法以一个String作为其参数。通过是类编程泛型类,以前只有在运行时才能抛出的错误现在编译时就能抛出。大大提高了开发效率。
泛型通配符有两种形式,<? super ZiClass>
?表示占位符,是ZiClass的父类;<? extends FuClass>
?是FuClass的子类。泛型(以及泛型集合)不是协变的(但是有意义),而数组是协变的。 泛型类可以由编译器通过类型擦除过程转变成非泛型类。