一. 时间复杂度的定义:在计算机科学中,算法的时间复杂度是⼀个数学函数,它定量描述了该算法的运行时间。⼀个算法所花费的时间与其中语句的执⾏次数成正⽐例,算法中的 基本操作的执⾏次数,为算法的时间复杂度。
计算时间复杂度的函数公式 大O渐进法
1.取最高阶次数,且最高阶次数前的系数取一 如6n^2 + n次,为O(N^2)
2.常数全部用一去取代 如100次运算为0(1)
看几个例题
冒泡排序 取最坏执行的次数则循环运行 n-1,n-2,n-3.......1,0次,相加起来就是(n*(n-1))/2次
即O(N^2)
二分查找法时间复杂度
取最坏情况,一次查找一半的内容,查找x次后才查找到n/2^x=1(n为数组长度,x为次数)
则x=log2 n,底数为2有时直接写成成lgN。
O(lgN)
二.空间复杂度
空间复杂度是对⼀个算法在运⾏过程中临时占⽤存储空间⼤⼩的量度。空间复杂度计算规则基 本跟时间复杂度类似,也使⽤⼤O渐进表⽰法。
还是冒泡排序,因为使⽤了常数个额外空间,所以空间复杂度为O(1)
递归求阶乘,因为递归调⽤了N次,开辟了N个栈帧,每个栈帧使⽤了常数个空间。空间复杂度为O(N)
三.包装类
Java给每个基本 类型都对应了⼀个包装类型。
基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Charcter
boolean Boolean
除了Integer和Character,其余基本类型的包装类都是⾸字⺟⼤写
1.装箱和拆箱 int i = 10; Integer a = new Integer(i); Integer b = Integer.valueOf(i);
这三行代码为装箱操作,装箱操作就是新建⼀个 Integer 类型对象,将 i 的值放⼊对象的某个属性中
接着上行代码
int j = a.intValue();
这为拆箱操作,,将 Integer 对象中的值取出,放到⼀个基本数据类型中
为减少代码量,有自动装箱和自动拆箱
int i = 10; Integer a = i; Integer b = (Integer)i; 这两行为自动装箱 int j = a; int k = (int)a; 这两行为自动拆箱
通过javap-c查看字节码⽂件内容,观察装箱和拆箱的操作
可以看到自动装箱是java底层自动帮你调用了valueof方法
再来看这段代码,运行结果会是什么呢
为什么会出现一个true 一个false呢, 我们来到valueOf原码
valueOf方法Integer返回了一个数组范围,[low,high],其中low =-128,high = 127,我们的值超出这个数组范围就会,引用不同的对象,导致结果不同。
四.泛型
通俗讲,泛型:就是适⽤于许多许多类型。从代码上讲,就是对类 型实现了参数化。泛型的主要⽬的:就是指定当前的容器,要持有 什么类型的对象。让编译器去做检查。此时,就需要把类型,作为参数传递。需要什么类型,就传⼊ 什么类型。
1.语法
class 泛型类名称 < 类型形参列表 >{
..............
}
例:class Add<T>{
}
类名后的T代表占位符,表示当前类是⼀个泛型类,也可以写E
2.泛型类的使⽤
泛型类 < 类型实参 > 变量名 = new 泛型类 < 类型实参 >( 构造⽅法实参 );
例如:Add<String> add = new Add<String>();
注意:泛型只能接受类,所有的基本数据类型必须使⽤包装类
来看具体代码
泛型的编译涉及擦除机制
之前具体代码擦除后
其实就是泛型类型被替换为其Object
3.擦除机制的定义:
在编译时,Java编译器会将泛型类型信息从代码中移除,这个过程就叫做类型擦除。
擦除后,泛型类型会被替换为其边界类型(通常是Object)或者指定的类型。
擦除过程:将泛型参数替换为其边界或Object。
4.桥接方法
泛型类型擦除可能导致⼦类⽅法和⽗类⽅法的签名不⼀致。
为了维护Java的多态性,需要桥接⽅法来确保⼦类⽅法能够正确覆盖⽗类⽅法
来看一段代码
public class Node<T>{
T date;
public void setData<T data> {
this.data = data;
}
public class StringNode extends Node<String>{
public void setData(String data) {
super.setData(data)
}
}
擦除后
此时StringNode 的 setData 方法并没有真正覆盖父类的 setData 因为参数类型不同
此时编译器会在StringNode 中⽣成⼀个桥接方法:
5.泛型的上界
在定义泛型类时,有时需要对传⼊的类型变量做⼀定的约束,可以通过类型边界来约束
语法形式 class 泛型类名称 < 类型形参 extends 类型边界 >
例如public class MyArray<E extends Number>
只接受Number的子类型作为E的类型实参
此时E可传入Integer,因为 Integer 是 Number 的⼦类型
而不可传入String,因为String不是 Number 的⼦类型。