引论
数学公式回顾
几何级数公式
算术级数、调和级数
模运算
最常用的两种证明方法
- 归纳法
- 反证法
递归的四大法则
- 基准情形(边界条件)
- 不断逼近基准情形
- 设计法则(所有的递归调用能运行)
- 合成效益法则(不要在不同的递归调用中做重复的工作)
循环不定:边界条件无法到达或者没有边界条件。用词典的例子来说就是查不到或循环解释。
在pre-Java5中实现泛型构件
泛型机制
在实现功能的过程中,除去对象的类型外,实现的方法是相同的,就用泛型实现来描述这种基本的功能。原先实现的思路主要是Object类、包装类、接口三种
协变、逆变和不变
Java5泛型构件
根本意义在于使用Java泛型后类型兼容出问题时抛出的是编译时异常而非运行时异常。
这里以协变数组类型举例
class Person{
}
class Student extends Person{
}
class Employee extends Person{
}
public class Main {
public static void main(String[] args) {
Person[] persons = new Employee[5]; //编译 arrays are compatible
persons[0] = new Student(); //编译 Student IS-A Person
}
}
//Exception in thread "main" java.lang.ArrayStoreException: Student
// at Main.main(Main.java:17)
这里 persons[0] 引用的是Employee,而Student IS-NOT-A Employee,Person数组其实并不允许内容多种多样,arr[0] 引用的是,但也不能抛出 ClassCastException ,这里并不存在类型转换。最终抛出的是 java.lang.ArrayStoreException。
协变的一致性:原子类型协变能推出结构类型协变。换言之,参数为People 的方法能够接受Student 实参能推出——peoples 参数接受Students形参。
-
数组协变的一致性:Employee IS-A Person可以推出 Employee[] IS-A Person[]
-
泛型集合与泛型的协变则不能一致,泛型集合则不是协变的,这样类型不兼容就会报编译时错误
// 泛型参数自身的协变
ArrayList<Person> people0 = new ArrayList<>();
people0.add(new Student());
//泛型集合是非协变
ArrayList<Student> people = new ArrayList<>();
test(people);
//Required type:
//Collection
//<Person>
//Provided:
//ArrayList
//<Student>
泛型:类型限界
// 注意泛型方法的说明应当在方法修饰符之后,返回类型声明之前
// 这里万一缺少对T实现Comparable接口的说明是肯定不行滴
public static <T> void findMax0(List<T> tC) {
T t = tC.get(0);
for (T i :
tC) {
t = (t.compareTo(i)) > 0 ? t : i;
}
}
// 这里说明泛型实现接口注意是用extends哦
// 这里问题在于没有去限制T实现的compareTo的参数,这个参数正好是Comparable接口的泛型对象
public static <T extends Comparable> T findMax1(List<T> tC) {
T t = tC.get(0);
for (T i :
tC) {
t = (t.compareTo(i)) > 0 ? t : i;
}
return t;
}
// 这样做太过直接粗暴了,只能比自己啊
// let me see see, 还会有啥好比的捏
// 巧啊,如果Comparable是在T的父类这实现的呢
// 这样怎么比. 只能比爹类了不是,我们原来限制比较的类型可没说限制到连自个不能比啊,我们是说要限制到比的是有用的,自己要比,爹类也要比,哪个爹呢,所有爹是不是应该都可以去比一比?对头
public static <T extends Comparable<T>> T findMax2(List<T> tC) {
T t = tC.get(0);
for (T i :
tC) {
t = (t.compareTo(i)) > 0 ? t : i;
}
return t;
}
完美版本
class Shape implements Comparable<Shape> {
int EdgeCount;
public Shape(int edgeCount) {
EdgeCount = edgeCount;
}
public int compareTo(Shape s) {
System.out.println(s.getClass().getName());
return Integer.compare(this.EdgeCount, s.EdgeCount);
}
}
class Square extends Shape{
public Square(int edgeCount) {
super(edgeCount);
}
}
public class Main {
//非常妙,这里?自然是Shape, 也就是说限制到本身或父类实现过就行
public static <T extends Comparable<? super T>> T findMax3(List<T> tC) {
T t = tC.get(0);
for (T i :
tC) {
t = (t.compareTo(i)) > 0 ? t : i;
}
return t;
}
public static void main(String[] args) {
ArrayList<Square> squares = new ArrayList<>();
squares.add(new Square(2));
squares.add(new Square(4));
squares.add(new Square(1));
squares.add(new Square(3));
System.out.println(findMax3(squares).EdgeCount);
}
}
类型擦除
泛型类可以由编译器通过所谓类型擦除过程变为非泛型类,自动地生成原始类。类型变量由它们的类型界限来替代,一般来说由Object 替换,限制了extends 就用最靠近的父类来替换。
函数对象
一个函数通过将其放在一个对象内部进行传递(直接传对象),这样的对象叫函数对象。
class Shape {
int EdgeCount;
public Shape(int edgeCount) {
this.EdgeCount = edgeCount;
}
}
public class Main {
// 对Shape进行比较但可能不知道比什么,直接传接口实现类的对象即可
public static <T> T findMax3(T[] arr, Comparator<? super T> comparator) {
T t = arr[0];
for (int i = 0; i < arr.length; i++) {
if (comparator.compare(t, arr[i]) < 0){
t = arr[i];
}
}
return t;
}
public static void main(String[] args) {
Shape[] shapes = new Shape[]{
new Shape(3),
new Shape(2),
new Shape(4)
};
System.out.println(
findMax3(shapes,
new Comparator<Shape>() {
@Override
public int compare(Shape o1, Shape o2){
return Integer.compare(
o1.EdgeCount * o1.EdgeCount,
o2.EdgeCount * o2.EdgeCount
);
}
}
).EdgeCount
);
}
}