数据结构的基本框架以及泛型

目录

集合框架

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里面,并没有写是什么类型的,但是为什么会知道现在是什么类型的呢,因为类型推导

会根据我们类型的传值,来推到此时的类型

相关推荐
morris1313 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
龙哥说跨境19 分钟前
如何利用指纹浏览器爬虫绕过Cloudflare的防护?
服务器·网络·python·网络爬虫
Source.Liu20 分钟前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng20 分钟前
【Rust中的迭代器】
开发语言·后端·rust
余衫马23 分钟前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng26 分钟前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
七星静香27 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员28 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU29 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie632 分钟前
在IDEA中使用Git
java·git