java 泛型 万字详解(通俗易懂)

news2025/9/20 5:00:46

目录

一、前言

二、为什么需要泛型?

三、什么是泛型?

        1.泛型的定义 : 

        2.泛型的作用 : 

四、怎么用泛型?

        1.泛型的语法 : 

        2. 泛型的使用 : 

        3.自定义泛型类 : 

                1° 基本语法 : 

                2° 使用细节 : 

        4.自定义泛型接口 : 

                1° 基本语法 : 

                2° 使用细节 : 

        5.自定义泛型方法 : 

                1° 基本语法 : 

                2° 使用细节 : 

五、泛型内容延申

        1.关于继承性 : 

        2.关于通配符 : 

        3.关于JUnit框架 : 

                ①为什么需要JUnit?

                ②什么是JUnit?

                ③怎么使用JUnit?

六、完结撒❀


一、前言

        大家好,本篇博文是对java——集合篇章的内容补充,主要是给大家讲讲泛型。
        注意 : ①代码中的注释也很重要;不要眼高手低,自己跟着动手敲一遍代码;点击文章前面的目录或者侧边栏的目录可以进行跳转。良工不示人以朴,up所有文章都会进行适时改进。感谢阅读!

二、为什么需要泛型?

        1.用传统的方法创建集合,并对集合进行添加元素等操作时,无法对加入到集合中的元素的类型进行约束,导致有可能在类型转换时出现“类型转换异常”的情况,不安全。

        2.用传统方式遍历集合时,如果集合中的数据量较大,频繁的类型转换会降低程序运行的效率。

                eg :
                up以Intro类为演示类,我们设法向集合中添加几个苹果类对象,但是又意外地添加了一个梨类对象,我们假装自己不知道这个意外,仍然抱着“集合中都是苹果对象”的心态对集合中苹果对象的name属性进行遍历代码如下 : 

package csdn.knowledge.api_tools.gather.generic;

import java.util.ArrayList;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class Intro {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList arrayList = new ArrayList();

        //向集合中添加元素
        arrayList.add(new Apple("Green Apple"));
        arrayList.add(new Apple("Banana Apple"));
        arrayList.add(new Apple("Red Apple"));
        //意外发生了
        arrayList.add(new Pear());

        for (Object o : arrayList) {
            Apple apple = (Apple) o;
            System.out.println(apple.getName());
        }
    }
}

class Apple {
    private String name;
    public Apple(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }
}

class Pear {}

                运行结果 : 

                显然,IDEA不是格格巫,想把一个梨对象凭空转换成苹果对象是不现实的,果断给你报出“ClassCastException”(类型转换异常)。

三、什么是泛型?

        1.泛型的定义 : 

        1° 泛型,又称参数化类型(ParameterizedType),是一种可以“表示其他数据类型”的数据类型。泛型是JDK5.0中出现的新特性,解决数据类型的安全性问题,在类声明或实例化时只要指定好具体的类型即可。

        2° java泛型可以保证——如果程序在编译时没有发出警告,运行时就不会产生类型转换异常(ClassCastException),同时使得代码更加简洁和健壮。

        2.泛型的作用 : 

        1° 可以在类声明时通过一个标识来表示类中的某个属性的数据类型;

        2° 可以表示类中某个方法的返回值的数据类型;

        3° 可以表示某个方法或者构造器的形参的数据类型;

        PS : 可以理解为——将来会用指定的类型替换掉源代码中对应的“泛型”。

                eg : 
                up以Intro_2类为演示类,最终要实现——使用String类型“替换掉”Grape类中给出的泛型代码如下 : 

package csdn.knowledge.api_tools.gather.generic;

/**
    利用泛型创建对象时,就比如当前情况下,如果直接传入非String类型,会直接报错;
    而如果仅对编译类型使用了泛型,构造器没有给出泛型,即写成下面这样子——
        Grape<String> grape = new Grape(141);
    这时候就会造成——运行期异常—— “ClasCastException”。
 */
public class Intro_2 {
    public static void main(String[] args) {
        Grape<String> grape = new Grape<String>("grape");
        System.out.println("temp = " + grape.getTemp());
        System.out.println("temp's Class = " + grape.getTemp().getClass());
    }
}

class Grape<E> {
    /*
        1. E可以表示temp变量的数据类型
            该类型在定义Grape类对象时可以指定,即在编译期间确定E是什么类型。
     */
    private E temp;

    /*
        2. E也可以表示形参的数据类型,用法同上。
     */
    public Grape(E temp) {
        this.temp = temp;
    }

    /*
        3. E也可以表示函数的返回值的数据类型,用法同上。
     */
    public E getTemp() {
        return temp;
    }
}

                运行结果 :  

                其实,当我们创建葡萄类对象给出<String>的泛型时, 达到的效果如下——

class Grape<String> {
    private String temp;

    public Grape(String temp) {
        this.temp = temp;
    }

    public String getTemp() {
        return temp;
    }
}

                即,在所有泛型E出现的地方,E都被替换为了String。

四、怎么用泛型?

        1.泛型的语法 : 

        interface 接口名<T> 或者 interface 接口名<K, V>

        class 类名<E> 或者 class 类名<K, V>

        Δ注意 : 

        ①尖括号<>中可以填写任意字母作为泛型的标识符,一般均为大写,常用T,K和V,分别表示Type,Key和Value。

        字母本身不代表任何值,而代表类型,即程序员手动指定的数据类型。

        在指定泛型时,必须要求最终确定的数据类型为引用类型,不可以是基本数据类型。

        ④实际传入的类型可以是泛型指定类型的子类型

        ⑤若在定义类时使用了泛型,实例化该类时却什么都没有传入,默认使用Object类型。

        2. 泛型的使用 : 

        从JDK7开始,等号后边的泛型可以不用写了,称为“菱形泛型”。     

        以上文“泛型的作用”中的代码为例,我们可以将其改写为如下的形式——

                Grape<String> grape = new Grape<>("grape"); //菱形泛型

        在实际开发中,菱形泛型的使用非常广泛,因此,推荐这种写法

                up以Generic_Demo1类为演示类,代码如下 : 

package csdn.knowledge.api_tools.gather.generic;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class Generic_Demo1 {
    public static void main(String[] args) {
        //1.创建集合对象(使用泛型)
        ArrayList<Integer> arrayList = new ArrayList<>();

        //2.向集合中添加元素
        arrayList.add(141);
        arrayList.add(141);
        arrayList.add(5);
        arrayList.add(11);
        arrayList.add(233);
        arrayList.add(233);

        //3.遍历集合
        Iterator<Integer> iterator = arrayList.iterator();
        while (iterator.hasNext())
        {
            System.out.println(iterator.next());
        }   //不再需要进行类型转换
    }
}

                运行结果 : 

        3.自定义泛型类 : 

                其实,我们在上文中举过的例子———
                class Grape<E> {
                }

                ———就是自定义泛型的应用。

                1° 基本语法 : 

        class 类名<T, R, E...> {        //可以同时定义多个泛型

                //类体

        }

                2° 使用细节 : 

        类的非静态成员可以使用泛型(属性,方法,构造器等)。

        ②静态成员不可以使用类的泛型。

           原因也很简单,我们在“代码块”一文中讲过,static修饰的成员的初始化——在类加载时就会执行完毕,而泛型最终代表的数据类型是在创建对象时才确定的,所以,jvm在对静态成员初始化时,无法得知它们的实际类型,也就没法儿初始化了

        ③在自定义泛型类中,使用了泛型的数组只可以定义,不可以被初始化

            因为jvm无法确定数组的实际类型,也就没法在内存中开辟空间

        自定义泛型类中,泛型最后代表的数据类型在创建对象时确定的

        如果在创建泛型类对象时没有给出指定类型,默认以Object替代

                eg : 
                up以Generic_Demo2类为演示类,代码如下 : 

package csdn.knowledge.api_tools.gather.generic;

import java.util.ArrayList;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class Generic_Demo2 {
    public static void main(String[] args) {
        ArrayList<Phone> phones = new ArrayList<>();

        phones.add(new Phone<String, Integer>("Huawei", "mate50", 6000));
        phones.add(new Phone<String, Integer>("Huawei", "mate40", 4000));
        phones.add(new Phone<String, Integer>("Huawei", "mate30", 3500));

        System.out.println("phones = " + phones);

        Phone<String, Integer> apple = new Phone<>("Apple", "iphone 14", 6000);
        /*
            泛型方法中,泛型最终表示的实际的数据类型————即传入的形参的类型。(引用类型)
         */
        apple.charge(Integer.valueOf(100));
        apple.charge(Long.valueOf(2333));
    }
}

class Phone<T, E> {
    //使用了泛型的成员变量
    private T brand;
    private T model;
    private E price;

    //使用了泛型的构造器
    public Phone() {}
    public Phone(T brand, T model, E price) {
        this.brand = brand;
        this.model = model;
        this.price = price;
    }

    //使用了泛型的成员方法
    public T getBrand() {
        return brand;
    }
    public void setBrand(T brand) {
        this.brand = brand;
    }

    public T getModel() {
        return model;
    }
    public void setModel(T model) {
        this.model = model;
    }

    public E getPrice() {
        return price;
    }
    public void setPrice(E price) {
        this.price = price;
    }

    //使用了泛型的成员方法的第二种形式
    public<M> void charge(M m) {
        /*
            getClass()方法可以获取当前类的正名(包名 + 类名);
            而后面再加上getSimpleName()方法就可以直接获取到类的类名。
         */
        System.out.println("传入的引用类型 = " + m.getClass().getSimpleName());
        System.out.println("当前的" + getModel() + "手机已经充电了 " + m + " 分钟。");
    }

    @Override
    public String toString() {
        return "\nPhone{" +
                "brand=" + brand +
                ", model=" + model +
                ", price=" + price +
                '}';
    }
}

                运行结果 :  

                如果我们在静态成员中使用泛型,IDEA会报错,如下图所示 : 

        4.自定义泛型接口 : 

                1° 基本语法 : 

        interface 接口名<T, R, E...> {        //可以同时定义多个泛型

                //body
        }

                2° 使用细节 : 

        同自定义泛型类一个道理,自定义泛型接口的静态成员不能使用泛型

        自定义泛型接口中,泛型最终代表的数据类型是在继承该接口或者实现该接口时确定的。

        若在使用时没有给出具体泛型,默认使用Object类型替代
            PS : 尽管默认以Object类型替换,但是建议——在不指定泛型的情况下,手动添加<Object>泛型标识符。这样在开发中,不管是领导还是你的同事,别人一看你的代码就知道是怎么回事

                eg : 
                up以Generic_Demo3类为演示类,代码如下 : 

package csdn.knowledge.api_tools.gather.generic;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class Generic_Demo3 {
    /*
        PS : 重点不再main方法,请往下看。
     */
    public static void main(String[] args) {
        Ipad_Air ipad_air = new Ipad_Air();
        ipad_air.charge("iPad Air 5", Long.valueOf(100));

        Ipad_Pro ipad_pro = new Ipad_Pro();
        ipad_pro.charge("iPad Pro 2022", Integer.valueOf(40));
    }
}

//定义Usb接口
interface Usb<T, E> {
    //在接口的(公有抽象)方法中使用泛型
    public abstract void charge(T t, E e);
}

//演示1 : 继承接口时确定泛型
interface IPad extends Usb<String, Long> {
}
class Ipad_Air implements IPad {
    /*
        注意!
        当我们利用快捷键重写Usb接口中的charge方法时,IDEA会自动用String和Long替换掉T和E.
     */
    @Override
    public void charge(String s, Long aLong) {
        System.out.println("给" + s + "充电 " + aLong + " 分钟吧!");
    }
}

//演示2 : 实现接口时确定泛型
class Ipad_Pro implements Usb<String, Integer> {
    @Override
    public void charge(String s, Integer integer) {
        System.out.println(s + "设备" + "已充电 " + integer + " 分钟。");
    }
}

                运行结果 : 

        5.自定义泛型方法 : 

                1° 基本语法 : 

        修饰符<T, R...> 返回值类型 方法名(形参列表) {    //形参列表往往会使用定义好的泛型

                //body
        }

                2° 使用细节 : 

        ①自定义泛型方法,既可以定义在普通类中,也可以定义在泛型类中。

        ②泛型最终调用的数据类型是在调用方法时确定的

​​​​​​​        ③每次调用泛型方法,都可以指定不同的泛型类型。

        注意区分自定义泛型方法 和 泛型在方法上的应用。

        eg : 

//以下代码仅作为演示,无实际意义
class<T, U> Watermelon {
    public<K> void taste(T t, U u, K k) {
        System.out.println("T和U代表泛型在方法上的应用;而K则是自定义泛型方法的使用。");
    }
}

五、泛型内容延申

        1.关于继承性 : 

                举个例子,如下图所示 : 

                up在创建ArrayList对象时使用了泛型,但是没有采用“菱形泛型”的形式,而是在编译类型中给出了<Object>的泛型,在运行类型中给出了<Interger>。
                这时,IDEA报错,显示所需的类型和提供的类型不一致这说明什么?
                不会因为Integer类型是Object类型的子类就通过编译,即编译类型的泛型和运行类型的泛型必须统一。泛型本身不存在继承性

        2.关于通配符 : 

                其实up在之前的“反射”一文中已经提到过通配符。通配符是一个问号,有以下三种使用场景——
                <?> : 单独使用,表示支持任意泛型类型
                <? extends A> : 表示支持A类以及A类的子类,规定了泛型的上限
                <? super A> : 表示支持A类以及A类的父类,规定了泛型的下限

                eg : 
                up以Generic_Demo4类为演示类,代码如下 : 

package csdn.knowledge.api_tools.gather.generic;

import java.util.ArrayList;
import java.util.List;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class Generic_Demo4 {
    public static void main(String[] args) {
        nutrition1(new ArrayList<Object>());
        nutrition1(new ArrayList<Fruit>());
        nutrition1(new ArrayList<Banana>());
        nutrition1(new ArrayList<GreenBanana>());
        /*
            不报错,因为没有进行类型约束。
         */
        System.out.println("=====================================s");


        //nutrition2(new ArrayList<Object>());
        /*
            报错,因为Object不属于“Fruit类及其子类”的范畴。
         */
        nutrition2(new ArrayList<Fruit>());
        nutrition2(new ArrayList<Banana>());
        nutrition2(new ArrayList<GreenBanana>());
        System.out.println("=====================================s");

        nutrition3(new ArrayList<Object>());
        nutrition3(new ArrayList<Fruit>());
        //nutrition3(new ArrayList<Banana>());
        /*
            报错,因为Banana类不属于“Fruit类及其父类”的范畴。
         */
        //nutrition3(new ArrayList<GreenBanana>());
        /*
            同样报错,因为GreenBanana类不属于“Fruit类及其父类”的范畴。
         */
    }

    //通配符使用情况一 :
    public static void nutrition1(List<?> fruit) {
        System.out.println("水果营养丰富,富含维生素!");
    }
    //通配符使用情况二 :
    public static void nutrition2(List<? extends Fruit> fruit) {
        System.out.println("水果营养丰富,富含维生素!");
    }
    //通配符使用情况三 :
    public static void nutrition3(List<? super Fruit> fruit) {
        System.out.println("水果营养丰富,富含维生素!");
    }
}

class Fruit {
}

class Banana extends Fruit {
}

class GreenBanana extends Banana {
}

                注意看上面代码中的注释,大家也可以把代码复制下来自己去试试。 

        3.关于JUnit框架 : 

                ①为什么需要JUnit?

                平时我们在写程序时,往往一个main方法中会测试很多功能代码(比如说很多方法),所以我们经常会注释掉某部分已经测试完毕的功能代码,以便于测试其他的功能代码。但是,假如一个类中有很多功能代码要测试,我们就不得不频繁地注释与反注释,非常麻烦

                ②什么是JUnit?

                JUnit是一个java语言提供的单元测试框架,目前多数的java开发环境中,都已集成了JUnit作为单元测试的工具

                ③怎么使用JUnit?

                up以Generic_Demo5类为演示类,代码如下 : 

package csdn.knowledge.api_tools.gather.generic;

public class Generic_Demo5 {
    public static void main(String[] args) {

    }

    public void f1() {
        System.out.println("f1方法被调用");
    }
    public void f2() {
        System.out.println("f2方法被调用");
    }
    public void f3() {
        System.out.println("f3方法被调用");
    }
}

                我们先在要测试的方法前输入@Test,如下图所示 : 

                这时候IDEA是会报错的,因为我们需要引入相应的组件,使用Alt + Enter快捷键,如下图所示 : 

                选择导入'JUnit5.8'(一般都使用5.8,而不是4的版本)。进入以后点击OK,首次导入会等待一段时间,如下图所示 : 

                大概几十秒后,就会显示导入成功了,如下图所示 : 

                导入成功后,我们会发现——在原先@Test标注的方法上,出现了一个绿色的小箭头的标志,如下图所示 : 

                点击绿色小箭头我们就可以实现对该方法进行单独地运行或者Debug,如下图所示 : 

                运行结果 : 

                并且,当我们已经导入JUnit后,为下一个方法标注“@Test”时就不需要重新导入和等待了,直接就可以标注,如下GIF图演示 : 

                发现没有,在JUnit框架的帮助下,我们既不是通过设置静态方法来调用,也没有通过创建对象来调用,而是直接指定的可以运行或者Debug某个方法,并且一个方法的调用不会影响其他的方法。这么一来就可以轻松解决我们上文中提出的问题。 

六、完结撒❀

        🆗,以上就是java——泛型的全部内容了。泛型与集合配合使用的频率非常高,所以up将泛型作为了集合篇章的内容补充。而至此,整个集合篇章的内容已全部讲完。之后,up会单独为集合篇章出一篇总结性质的博文,为大家整理一下集合框架中涉及到的up分享过的知识。感谢阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/411756.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++-继承

继承继承的基本概念继承的概念继承的定义继承的格式继承的方式继承基类成员访问方式的变化基类与派生类的对象赋值转换继承中的作用域派生类中的默认成员函数继承与友元继承中的静态成员菱形继承菱形虚拟继承继承的总结继承的基本概念 继承的概念 继承机制是面向对象程序设计中…

【Spring源码】 BeanFactory和FactoryBean是什么?

1、前言 面试官&#xff1a;“看过Spring源码吧&#xff0c;简单说说Spring中BeanFactory和FactoryBean的区别是什么&#xff1f;” 大神仙&#xff1a;“BeanFactory是bean工厂&#xff0c;FactoryBean是工厂bean”。 这么回答&#xff0c;等于面试官问你Spring是什么&…

如何免费使用ChatGPT 4?

自从ChatGPT发布以来&#xff0c;它就取得了巨大的成功。无论是常春藤法学考试还是商学院作业&#xff0c;ChatGPT都被用于各种试验。统计数据显示&#xff0c;ChatGPT每月吸引约9600万用户。随着ChatGPT的巨大成功&#xff0c;Open AI最近推出了它的最新版本&#xff0c;名为“…

Learning to Detect Human-Object Interactions 文章解读

Learning to Detect Human-Object Interactions&#xff0c;WACV&#xff0c;2018 论文下载 code&#xff1a;http://www.umich.edu/∼ywchao/hico/ 摘要 主要研究领域&#xff1a;定义了HOI detection任务&#xff1a;在静态图像中检测人-对象交互&#xff08;HOI&#xff…

Vue路由模式为history的项目部署到Nginx

前言 对于前端工程师而言&#xff0c;多多少少会碰到按需加载的需求。 比如一个系统&#xff0c;需要用户登陆以后才能使用&#xff0c;对于传统的前后端未分离的情况&#xff0c;我们一般的处理方式是&#xff0c;当检测到用户未登录的时候&#xff0c;一般会重定向到登录页面…

JVM运行时数据区的必备知识:Java程序员不容错过

1、JVM运行时数据区概念 JVM运行时数据区是Java虚拟机在执行Java程序时所使用的内存区域。这些区域包括了以下几个部分&#xff1a; 程序计数器&#xff08;Program Counter Register&#xff09;&#xff1a;程序计数器是一块较小的内存区域&#xff0c;它可以看作是当前线程…

测试1号位的自我修养

作者&#xff1a;京东零售 吴聪 引言 目前京东实行BigBoss机制以及积木型组织&#xff0c;同时现阶段再次强调了“经营”理念&#xff0c;以上均是比较大的组织层面的纲领和引导&#xff0c;核心是为了激发大家owner意识可以更好更快为公司产出价值和贡献。落到具体执行层面&…

国内大模型领域进入乱战时代

国内大模型领域进入乱战时代 2023.4.12版权声明&#xff1a;本文为博主chszs的原创文章&#xff0c;未经博主允许不得转载。 什么是大模型 大模型&#xff0c;又称为预训练模型、基础模型等&#xff0c;是指模型参数数量很大&#xff0c;需要大量计算资源才能训练的深度学习…

RHCE-Web服务器

请给openlab搭建web网站​ 网站需求&#xff1a;​ 1.基于域名[www.openlab.com](http://www.openlab.com)可以访问网站内容为 welcome to openlab!!! 首先创建一个名为openlab的网站&#xff1a; &#xff08;1&#xff09;在www目录下创建一个openlab文件夹&#xff1a;mk…

Android UI

什么是 UI 用户界面&#xff08;User Interface&#xff0c;简称 UI&#xff0c;亦称使用者界面&#xff09;是系统和用户之间进行交互和信息交换的媒介&#xff0c;它实现信息的内部形式与人类可以接受形式之间的转换。软件设计可分为两个部分&#xff1a;编码设计与UI设计。A…

JavaScript编程实现tab选项卡切换的效果+1

之前在“圳品”信息系统使用了tab选项卡来显示信息&#xff0c;详见&#xff1a; JavaScript编程实现tab选项卡切换的效果 在tab选项卡中使用其它<div>来显示信息就出现了问题&#xff0c;乱套了&#xff0c;比如下面的这段代码&#xff1a; <!DOCTYPE html> &l…

c/c++:for循环语句,分号不可省略,表达式可以省略,猜数字游戏,跳转语句continue,break,避免写goto

c/c:for循环语句&#xff0c;分号不可省略&#xff0c;表达式可以省略&#xff0c;猜数字游戏&#xff0c;跳转语句continue&#xff0c;break&#xff0c;避免写goto 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学…

树莓派 QT项目开机自启动

我自己用qt设置了一个界面&#xff0c;如何让他开机自启动呢&#xff1f; 目录 1.生成qt项目的可执行文件 2. 编写一个自启动脚本 3.重启树莓派 1.生成qt项目的可执行文件 QT项目的可执行文件就是.exe文件。首先在qt中打开&#xff0c;点击红色方框图标&#xff0c;选择Re…

vue+springboot 上传文件、图片、视频,回显到前端。

效果图 预览&#xff1a; 视频&#xff1a; 设计逻辑 数据库表 前端vue html <div class"right-pannel"><div class"data-box"><!--上传的作业--><div style"display: block" id""><div class"tit…

C++编程法则365条一天一条(359)认识各种初始化术语

文章目录Default initialization默认初始化Copy initialization拷贝初始化Aggregate initialization聚合初始化Direct initialization直接初始化list_initialization列表初始化value_initialization值初始化参考&#xff1a; https://en.cppreference.com/w/cpp/language/copy_…

【unity learn】【Ruby 2D】角色发射飞弹

前面制作了敌人的随机运动以及动画控制&#xff0c;接下来就是Ruby和Robot之间的对决了&#xff01; 世界观背景下&#xff0c;小镇上的机器人出了故障&#xff0c;致使全镇陷入了危机&#xff0c;而Ruby肩负着拯救小镇的职责&#xff0c;于是她踏上了修复机器人的旅途。 之前…

同步I/O实现Reactor和Proactor的差异

有两种高效的事件处理模式&#xff1a;Reactor模式和Proactor模式 Reactor模式 主线程只负责监听socket上是否有事件发生&#xff0c;当有事件发生时&#xff0c;主线程就将该事件放进请求队列&#xff0c;通知工作线程进程处理&#xff1b;主线程不做实质性的工作&#xff0c…

使用颜色检测有向图中的循环

给定一个有向图,检查该图是否包含循环。如果给定的图形至少包含一个循环,您的函数应返回 true,否则返回 false。 例子: 输入: n = 4, e = 6 0 -> 1, 0 -> 2, 1 -> 2, 2 -> 0, 2 -> 3, 3 -> 3 输出:是 解释: <

计网之HTTP协议和Fiddler的使用

文章目录一. HTTP概述和fidder的使用1. 什么是HTTP2. 抓包工具fidder的使用2.1 注意事项2.2 fidder的使用二. HTTP协议格式1. HTTP请求格式1.1 基本格式1.2 认识URL1.3 方法2. 请求报头关键字段3. HTTP响应格式3.1 基本格式3.2 状态码一. HTTP概述和fidder的使用 1. 什么是HTT…

VueRouter路由模式解析

VueRouter路由模式解析 前端路由的实现方式主要有两种&#xff1a;hash模式和history模式。 hash模式 在window.location对象中有一个hash字段&#xff0c;可以获取地址栏中#字符及后边的所有字符。 hash也称作锚点&#xff0c;本身是用来做页面定位的&#xff0c;可以使对…