目录
集合框架
Java的集合框架,Java Collection Framework 又被称为容器container, 定义在java.util包下的一组 interfaces 和其实现类 classes
interface: 接口
abstracb class: 抽象类
class: 类
这一张图片里面.,描述了Java里面,比较重要的类与类, 类与接口之间的关系.
在这两个图里面,最重要的接口有4个,分别是list, queue,set 以及 map,其他的类都是实现这些接口的
复杂度
在我们写代码的时候,我们是会讲究一个效率问题的,被用复杂度来表示,其中也分为时间复杂度以及空间复杂度,这两个复杂度都是用: 大O的渐进表示法来表示的
复杂度肯定也是有分为最好情况,最坏情况以及平均情况的 ,但是我们一般在讨论的时候,我们都是要默认说最坏的情况.
大O的渐进表示法
1>用常数 1 取代时间中的所有加法常数
2>在修改后的运行次数函数中,只保留最高阶项
3>如果最高阶存在且不是 1 ,则去除与这个项目相乘的常数,得到的结果是大O阶
例如:
例如代码之中有这样一块循环,复杂度是按照最坏的情况考虑的,
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
count++;
}
}
首先里面第一部分是这样一块代码,两个for循环套在一起,最坏的情况就是每个for会循环N次,所以这一块的复杂度就是N^2次
for (int i = 0; i < 2 * N; i++) {
count++;
}
第二部分里面,循环会有2N次,所以他的复杂度就是2N次
int m = 10;
while ((m--) > 0){
count++;
}
第三部分就是一个while循环,可以看见m是10,所以这个循环最多进行10次,复杂度为10
最后的话我们就可以知道这个复杂度是O(N) = N^2 + 2 * N + 10
我们再根据大O的渐进法进行化简,O(N) = N^2就是代码的复杂度了
装包(箱)或者拆包(箱)
装包
Integer a =10;
int i = 5;
Integer b =i;
上面的代码是两种装包的写法
但是我们有两种装包的方式,一种是显式,一种是隐式装包
Integer a =10;
Integer aa = Integer.valueOf(10);
上面这两个就是不用的装包方式,a是一种隐式装包,在写的时候把valueof给隐藏起来了,没有显式出来
aa的话就是显式装包,在这个过程中,把valuof这个过程给写了出来
拆包
同样的,拆包也分为隐式的和显式的
Integer a =10;
int i = a;
想这个就是隐式的拆包
int aa = a.intValue();
double d = a.doubleValue();
像上面这两个就是显式的拆包,
从上面可以看出,对于拆包来说,隐式和显式的差别也就是在于value的差别
在这个截图上面,我们可以看出,定义了两组不同的包装类.但是有一组返回的是true,有一组返回的是false,这是为什么呢?
通过上面两个截图,调用valueof的底层源码可以看到,它的取值范围是在-128到127之间的,那也就是说我们的aa,以及bb是超出了这个范围的.
所以当aa,bb都取值200时候,他们都是创建了新的地址,所以地址是不同的
泛型
泛型的概念: 实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据.也可以根据成员方法数组中某个下标的值
class MyArray<T>{
public Object[] array = new Object[10];
public void setvalue(int pos,T val){
array[pos] = val;
}
public T getvalue(int pos){
return (T)array[pos];
}
}
public class Test {
public static void main(String[] args) {
MyArray<Integer> myArray = new MyArray<Integer>();
myArray.setvalue(0,10);
myArray.setvalue(1,100);
int a = myArray.getvalue(1);
System.out.println(a);
MyArray<String> myArray1 = new MyArray<String>();
myArray1.setvalue(0,"hello");
myArray1.setvalue(1,"ko");
String b = myArray1.getvalue(0);
System.out.println(b);
像在上面就是个泛型的代码,在上面这个代码里面,我们可以发现,我们在输出的时候可以输出整数,也可以输出字符串,我们想输出其他的类型,只要创建一个新的对象就可以了
我们可以正常的输出a和b,就像泛型的概念说的"类中包含一个数组成员,使得数组中可以存放任何类型的数据"
像在泛型里面还要一点要注意
像我们在泛型里面创建对象的时候,我们不可以new一个泛型类型的数据,必须是Object类型的,因为泛型是在编译时期的一个概念,当程序运行起来到了JVM以后,就没有了泛型的概念
泛型在编译时期是如何编译的?
是采用了擦除机制,把T擦除成了Object!!!
泛型的上界
模板: class 泛型类名称 <类型形参 extends 类型边界> {
...
}
class TestGeneric<T extends Number>{
}
public class Test {
public static void main(String[] args) {
TestGeneric<Number> testGeneric = new TestGeneric<>();
}
}
这上面就是泛型的一个使用模板
这上面的话是一个泛型取最大值的方法,但是我们可以看到在if的那个地方,会报错.
这是因为T一定是引用数据类型,最终被擦除为了Object类型,因为我们是要求最大值,所以这个T的类型一定是可比较的,所以我们要继承自Comparable接口,然后可以调用CompareTo进行比较
所以正确的我们if里面要像上图这样写才可以
class Alg<T extends Comparable<T>> {
public T findMaxValue(T[] array) {
T max = array[0];
for (int i = 0; i < array.length; i++) {
if (max.compareTo(array[i]) < 0) {
max = array[i];
}
}
return max;
}
}
public class Test {
public static void main(String[] args) {
Alg<Integer> alg = new Alg<>();
Integer[] integers = {1, 2, 3, 4, 5, 6, 7};
Integer ret = alg.findMaxValue(integers);
System.out.println(ret);
}
}
完整的代码就是上面这样的,最大值也就是7
泛型方法求最大值
class Alg2{
public static <T extends Comparable<T>> T findMaxValue(T[] array){
T max = array[0];
for (int i = 0; i < array.length; i++) {
if (max.compareTo(array[i]) < 0){
max = array[i];
}
}
return max;
}
}
public class Test {
public static void main(String[] args) {
Alg2 alg2 = new Alg2();
Integer[] integers1 = {1,2,3,4,5,6,7};
Integer ret1 = alg2.findMaxValue(integers1);
System.out.println(ret1);
}
}
像上面这个方法的话,我们的Alg2里面,并没有写是什么类型的,但是为什么会知道现在是什么类型的呢,因为类型推导
会根据我们类型的传值,来推到此时的类型