java泛型视频教程_Java泛型快速教程

java泛型视频教程

泛型是Java SE 5.0引入的一种Java功能,在其发布几年后,我发誓那里的每个Java程序员不仅会听说过,而且已经使用过。 关于Java泛型,有很多免费和商业资源,而我使用的最佳资源是:

  • Java教程
  • Java泛型和集合 ,作者Maurice Naftalin和Philip Wadler
  • 有效的Java(第二版) ,作者:约书亚·布洛赫(Joshua Bloch)。

尽管有大量的信息,但在我看来,有时候许多开发人员仍然不了解Java泛型的含义和含义。 这就是为什么我试图以最简单的方式总结开发人员关于泛型所需的基本信息。

泛型的动机

考虑Java泛型的最简单方法是考虑一种语法糖,它可能使您省去一些强制转换操作:

 List<Apple> box = ...;  Apple apple = box.get( 0 ); 

前面的代码是自说的:box是对Apple类型对象列表的引用。 get方法返回一个Apple实例,不需要强制转换。 没有泛型,此代码将是:

 List box = ...;  Apple apple = (Apple) box.get( 0 ); 

不用说,泛型的主要优点是让编译器跟踪类型参数,执行类型检查和强制转换操作:编译器保证强制转换永远不会失败。

编译器现在可以帮助程序员执行更多类型检查并在编译时检测更多故障,而不是依靠程序员来跟踪对象类型并执行强制转换,而这可能导致运行时失败而难以调试和解决。 。

通用设施

泛型工具引入了类型变量的概念。 根据Java语言规范,类型变量是由以下项引入的不合格标识符:

  • 通用类声明
  • 通用接口声明
  • 通用方法声明
  • 通用构造函数声明。

通用类和接口

如果类或接口具有一个或多个类型变量,则它是通用的。 类型变量由尖括号分隔,并遵循类(或接口)的名称:

 public interface List<T> extends Collection<T> {  ...  } 

粗略地说,类型变量充当参数,并提供编译器进行检查所需的信息。

Java库中的许多类(例如整个Collections Framework)都被修改为通用的。 例如,我们在第一个代码段中使用的List接口现在是一个通用类。 在该代码段中,box是对List <Apple>对象的引用,该对象是使用一个类型变量:Apple实现List接口的类的实例。 类型变量是编译器在将get方法的结果自动转换为Apple引用时使用的参数。

实际上,新的通用签名或接口List的get方法是:

 T get( int index); 

方法get确实返回了一个T类型的对象,其中T是List <T>声明中指定的类型变量。

通用方法和构造函数

如果方法和构造函数声明一个或多个类型变量,它们的方式几乎相同。

 public static <t> T getFirst(List<T> list) 

此方法将接受对List <T>的引用,并将返回类型T的对象。

例子

您可以在自己的类或通用Java库类中利用通用类。

书写时输入安全性…

例如,在下面的代码段中,我们创建了一个实例List <String>,其中填充了一些数据:

 List<String> str = new ArrayList<String>();  str.add( "Hello " );  str.add( "World." ); 

如果我们尝试将其他类型的对象放入List <String>,则编译器将引发错误:

 str.add( 1 ); // won't compile 

…以及阅读时

如果我们传递List <String>引用,则始终保证可以从中检索String对象:

 String myString = str.get( 0 ); 

反复进行

库中的许多类(例如Iterator <T>)已得到增强并变得通用。 接口List <T>的iterator()方法现在返回一个Iterator <T>,可以轻松使用它,而无需转换通过其T next()方法返回的对象。

 for (Iterator<String> iter = str.iterator(); iter.hasNext();) {  String s = iter.next();  System.out.print(s);  } 

使用foreach

for每个语法也都利用了泛型。 先前的代码段可以写为:

 for (String s: str) {  System.out.print(s);  } 

更容易阅读和维护。

自动装箱和自动拆箱

处理泛型时,将自动使用Java语言的自动装箱/自动拆箱功能,如以下代码片段所示:

 List<Integer> ints = new ArrayList<Integer>();  ints.add( 0 );  ints.add( 1 );  int sum = 0 ;  for ( int i : ints) {  sum += i;  } 

但是请注意,装箱和拆箱会降低性能,因此,通常会提出警告和警告。

亚型

与其他面向对象的类型化语言一样,在Java中,可以构建类型的层次结构:

Java泛型

在Java中,类型T的子类型可以是扩展T的类型,也可以是直接或间接实现T的类型(如果T是接口)。 由于“成为...的子类型”是传递关系,因此,如果类型A是B的子类型,而B是C的子类型,则A也将是C的子类型。 在上图中:

  • 富士苹果是苹果的一个子类型
  • 苹果是水果的一种
  • FujiApple是Fruit的子类型。

每个Java类型也将是Object的子类型。

类型B的每个子类型A都可以分配给类型B的引用:

 Apple a = ...;  Fruit f = a; 

通用类型的子类型化

如果可以将Apple实例的引用分配给Fruit的引用,如上所示,那么List <Apple>和List <Fruit>之间是什么关系? 哪一个是子类型? 更一般而言,如果类型A是类型B的子类型,则C <A>和C <B>如何相互关联?

出乎意料的是,答案是:绝对没有。 用更正式的词来说,泛型类型之间的子类型关系是不变的。

这意味着以下代码段无效:

 List<Apple> apples = ...;  List<Fruit> fruits = apples; 

以下内容也是如此:

 List<Apple> apples;  List<Fruit> fruits = ...;  apples = fruits; 

但为什么? 是一个苹果是一种水果,一盒苹果(一个清单)也是一盒水果。

从某种意义上讲是这样,但是类型(类)封装了状态和操作。 如果一盒苹果是一盒水果会怎样?

 List<Apple> apples = ...;  List<Fruit> fruits = apples;  fruits.add( new Strawberry()); 

如果是这样,我们可以在列表中添加Fruit的其他不同子类型,并且必须禁止这样做。

相反,更直观:一盒水果不是一盒苹果,因为它可能是其他种类(子类型)水果(水果)(例如草莓)的盒子(列表)。

真的有问题吗?

不应该这样。 Java开发人员感到惊讶的最强烈原因是数组的行为与泛型类型之间的不一致。 后者的子类型关系是不变的,而前者的子类型关系是协变的:如果类型A是类型B的子类型,则A []是B []的子类型:

 Apple[] apples = ...;  Fruit[] fruits = apples; 

可是等等! 如果我们重复上一节中公开的参数,最终可能会在一系列苹果中添加草莓:

 Apple[] apples = new Apple[ 1 ];  Fruit[] fruits = apples;  fruits[ 0 ] = new Strawberry(); 

该代码确实可以编译,但是在运行时会以ArrayStoreException的形式引发错误。 由于数组的这种行为,因此在存储操作期间,Java运行时需要检查类型是否兼容。 显然,该检查还会增加您应该意识到的性能损失。

再有,泛型更易于使用,并且可以“纠正” Java数组的这种类型的安全性弱点。

在这种情况下,您现在想知道为什么数组的子类型关系是协变的,我将为您提供Java Generics和Collections给出的答案:如果它是不变的,则无法将引用传递给对象数组类型未知(无需每次都复制到Object [])的方法,例如:

 void sort(Object[] o); 

随着泛型的出现,数组的这种特性不再是必需的(我们将在本文的下一部分中看到),并且确实应该避免。

通配符

正如我们在本文的上半部分所看到的,泛型类型的子类型关系是不变的。 不过,有时候我们还是希望以与普通类型相同的方式使用通用类型:

  • 缩小参考(协方差)
  • 扩大参考范围(矛盾)

协方差

例如,假设我们有一组盒子,每个盒子都有不同种类的水果。 我们希望能够编写可以接受任何方法的方法。 更正式地说,给定类型B的子类型A,我们想找到一种方法来使用类型C <B>的引用(或方法参数),该引用可以接受C <A>的实例。

要完成此任务,我们可以使用带有扩展名的通配符,例如以下示例:

 List<Apple> apples = new ArrayList<Apple>();  List<? extends Fruit> fruits = apples; 

? 扩展重新引入了泛型类型的协变子类型:Apple是Fruit的子类型,而List <Apple>是List <?的子类型。 延伸水果>。

逆差

现在让我们介绍另一个通配符: 超。 给定类型A的超类型B,则C <B>是C <?的子类型。 超级A>:

 List<Fruit> fruits = new ArrayList<Fruit>();  List<? super Apple> = fruits; 

如何使用通配符?

现在有足够的理论:我们如何利用这些新结构?

延伸

让我们回到第二部分中介绍Java数组协方差时使用的示例:

 Apple[] apples = new Apple[ 1 ];  Fruit[] fruits = apples;  fruits[ 0 ] = new Strawberry(); 

如我们所见,当尝试通过对Fruit数组的引用将Strawberry添加到Apple数组时,此代码可以编译,但会导致运行时异常。

现在,我们可以使用通配符将此代码转换为与之对应的通用代码:由于Apple是Fruit的子类型,因此我们将使用? 扩展通配符,以便能够将List <Apple>的引用分配给List <?的引用 延伸水果>:

 List<Apple> apples = new ArrayList<Apple>();  List<? extends Fruit> fruits = apples;  fruits.add( new Strawberry()); 

这次,代码将无法编译! Java编译器现在阻止我们将草莓添加到水果列表中。 我们将在编译时检测到该错误,甚至不需要任何运行时检查(例如在数组存储的情况下),以确保我们将兼容类型添加到列表中。 即使我们尝试将Fruit实例添加到列表中,代码也不会编译:

 fruits.add( new Fruit()); 

没门。 结果是,实际上,您不能将任何东西放入其类型使用?的结构中。 扩展通配符。

如果考虑一下,原因很简单: 扩展T通配符告诉编译器我们正在处理类型T的子类型,但是我们不知道是哪一个。 由于没有办法说出来,而且我们需要保证类型安全,因此您将不允许在此类结构内放置任何内容。 另一方面,由于我们知道它可能是T的子类型,因此我们可以从结构中获取数据,并保证它是T实例:

 Fruit get = fruits.get( 0 ); 

使用类型的行为是什么? 超级通配符? 让我们从这个开始:

 List<Fruit> fruits = new ArrayList<Fruit>();  List<? super Apple> = fruits; 

我们知道,水果是对Apple超类商品列表的引用。 同样,我们不知道它是哪个超类型,但是我们知道Apple及其任何子类型都将与其赋值兼容。 实际上,由于这种未知类型将同时是Apple和GreenApple超类型,因此我们可以这样写:

 fruits.add( new Apple());  fruits.add( new fruits.add( GreenApple()); 

如果我们尝试添加任何Apple超类型,编译器都会抱怨:

 fruits.add( new Fruit());  fruits.add( new Object()); 

由于我们不知道它是哪个超类型,因此我们不允许添加任何超类型的实例。

如何从这种类型的数据中获取数据呢? 事实证明,您唯一可以摆脱的是对象实例:由于我们无法知道它是哪个超类型,因此编译器只能保证它将是对对象的引用,因为对象是任何对象的超类型。 Java类型。

获取和放置原则或PECS规则

总结一下行为? 扩展和? 超级通配符,我们得出以下结论:

  • 使用 ? 如果需要从数据结构中检索对象,则扩展通配符
  • 使用 ? 如果需要将对象放入数据结构,则使用超级通配符
  • 如果您需要同时做这两个事情,请不要使用任何通配符。

这就是Maurice Naftalin在他的Java泛型和集合中称为“获取和放置原理”,在Joshua Bloch的“ 有效Java ”中称为PECS规则。

Bloch的助记符PECS来自“生产者扩展,超级消费者”,可能更容易记住和使用。

方法签名中的通配符

如本系列第二部分中所见,在Java中(与许多其他类型化语言一样),Substitution原则是这样的:可以将子类型分配给其任何超类型的引用。

这适用于分配任何引用的过程,即,即使将参数传递给函数或存储其结果也是如此。 因此,该原理的优点之一是,在定义类层次结构时,可以编写“通用”方法来处理整个子层次结构,而与要处理特定对象实例的类无关。 到目前为止,在Fruit类的层次结构中,接受Fruit作为参数的函数将接受其任何子类型(例如Apple或Strawberry)。

从上一篇文章中可以看出,通配符可还原通用类型的协变量和逆变量子类型:使用通配符,然后,让开发人员编写可以利用到目前为止所展示的优点的函数。

例如,如果开发人员想要定义一个方法eat,该方法接受任何水果的列表,则可以使用以下签名:

 void eat(List<? extends Fruit> fruits); 

由于水果类的任何子类型的列表都是List <? 扩展Fruit>,先前的方法将接受任何此类列表作为参数。 请注意,如上一节所述,“获取和放置原则”(或PECS规则)将允许您从此类列表中检索对象并将其分配给Fruit引用。

另一方面,如果要将实例放在作为参数传递的列表上,则应使用?。 超级通配符:

 void store(List<? super Fruit> container); 

这样,可以将任何水果超类的列表传递给存储功能,并且可以安全地将任何水果子类型放入其中。

有界类型变量

不过,泛型的灵活性比这更大。 类型变量可以有界,几乎与通配符可以有界(就像我们在第二部分中看到的一样)。 但是,类型变量不能以super为边界,而只能以extends为边界。 查看以下签名:

 public static <T extends I<T>> void name(Collection<T> t); 

它接受类型受限制的对象的集合:它必须满足T扩展I <T>条件。 首先,使用有界类型变量似乎似乎没有通配符更强大,但是稍后我们将详细介绍它们之间的区别。

让我们假设层次结构中的一些(但不是全部)结果可能是多汁的,如下所示:

 public interface Juicy<T> { Juice<T> squeeze();  } 

多汁的水果将实现此接口并发布挤压方法。

现在,您编写一个使用一堆水果并将其全部榨干的库方法。 您可以写的第一个签名可能是:

 <T> List<Juice<T>> squeeze(List<Juicy<T>> fruits); 

使用有界类型变量,您将编写以下内容(实际上,它与以前的方法已删除相同):

 <T extends Juicy<T>> List<Juice<T>> squeeze(List<T> fruits); 

到目前为止,一切都很好。 但有限。 我们可以使用相同帖子中使用的相同参数,然后发现squeeze方法不起作用,例如,在以下情况下使用红色橘子列表:

 class Orange extends Fruit implements Juicy<Orange>;  RedOrange class extends Orange; 

由于我们已经了解了PECS原理,因此我们将通过以下方式更改方法:

 <T extends Juicy<? super T>> List<Juice<? super T>> squeezeSuperExtends(List<? extends T> fruits); 

此方法接受类型扩展为Juicy <?的对象列表。 super T>,也就是说,必须存在类型S,以使T扩展Juicy <S> S superT。

递归界

也许您想放松T延伸多汁<? 超级T>绑定。 这种绑定称为递归绑定,因为类型T必须满足的绑定取决于T。您可以在需要时使用递归绑定,也可以将它们与其他种类的绑定进行混合匹配。

因此,例如,您可以编写具有以下界限的通用方法:

 <A extends B<A,C>, C extends D<T>> 

请记住,这些示例仅用于说明泛型可以做什么。 您将要使用的界限始终取决于要放入类型层次结构中的约束。

使用多个类型变量

假设您想放宽在最后一个squeeze方法上设置的递归范围。 然后,让我们假设类型T可以扩展Juicy <S>,尽管T本身不扩展S。方法签名可以是:

 <T extends Juicy<S>, S> List<Juice<S>> squeezeSuperExtendsWithFruit(List<? extends T> fruits); 

此签名与上一个签名相当(因为我们仅在方法参数中使用T),但有一点优势:由于我们声明了通用类型S,因此该方法可以返回List <Juice <S>而不是List <? 超级T>,在某些情况下很有用,因为编译器将根据您传递的方法参数帮助您确定S类型是哪种。 由于要返回列表,因此您可能希望调用者能够从中获取某些信息,并且如前一部分所述,您只能从列表中获取Object实例,例如List <?。 超级T>。

如果需要,显然可以为S添加更多界限,例如:

 <T extends Juicy<S>, S extends Fruit> List<Juice<S>> squeezeSuperExtendsWithFruit(List<? extends T> fruits); 

多界

如果要对同一类型变量应用多个范围怎么办? 事实证明,您只能为每个泛型类型变量编写一个绑定。 因此,以下界限是非法的:

 <T extends A, T extends B> // illegal 

编译器将失败,并显示以下消息:

T已在…中定义

必须使用不同的语法来表示多个界限,这是一种非常熟悉的表示法:

 <T extends A & B> 

前面的边界意味着T扩展 A和B。请注意,根据Java语言规范 第4.4章的规定,边界是:

  • 类型变量。
  • 一类。
  • 接口类型,然后是其他接口类型。

这意味着只能使用接口类型来表达多个界限。 无法在多重绑定中使用类型变量,并且编译器将失败,并显示以下消息:

类型变量不能跟随其他界限。

在我阅读的文档中,这并不总是很清楚。

参考文献:

  • The Gray Blog的 JCG合作伙伴Gray 撰写的有关Java泛型的系列文章

编码愉快! 不要忘记分享!

拜伦

相关文章:

  • Java泛型示例
  • Java最佳实践系列
  • 正确记录应用程序的10个技巧
  • 每个程序员都应该知道的事情
  • 生存在荒野西部开发过程中的9条提示
  • 软件设计法则
  • Java Fork / Join进行并行编程

翻译自: https://www.javacodegeeks.com/2011/04/java-generics-quick-tutorial.html

java泛型视频教程

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

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

相关文章

Windows上的Oracle Java

我最近为基于Windows 7的笔记本电脑下载了JDK 9的早期访问版本 &#xff08;内部版本68 &#xff09;。 由于这是早期版本&#xff0c;因此当自动安装在笔记本电脑上安装主要Java Runtime Environment&#xff08;JRE&#xff09;引入了一些不太理想的问题时&#xff0c;我并不…

extjs弹出窗口查看文本内容-new Ext.Window

代码样例&#xff1a; function processscan(){ var text时间 用户 操作<br> 时间 用户 操作<br> 时间 用户 操作; var win new Ext.Window({ layout: fit, width: 700, height: 600, closeAction: hide, dra…

Ioc Autofac心得

对于这个容器注入&#xff0c;个人也不是很熟悉&#xff0c;很多还不懂&#xff0c;只会基本的操作&#xff0c;几天把它记录下来&#xff0c;说不定以后帮助就大了呢&#xff0c;这方面跟安卓差距还是挺大的 下面记录下应用的流程 步骤&#xff1a; 1.添加应用 2.重写工厂&…

深入学习Web Service系列----异步开发模式

概述 在本篇随笔中&#xff0c;通过一些简单的示例来说一下Web Service中的异步调用模式。调用Web Service方法有两种方式&#xff0c;同步调用和异步调用。同步调用是程序继续执行前等候调用的完成&#xff0c;而异步调用在后台继续时&#xff0c;程序也继续执行&#xff0c;不…

navicate导出导入表数据问题

1.导出导入json&#xff0c;如下图&#xff0c;右击表点击导出向导&#xff0c;选择json导出类型&#xff0c;根据提示导出即可。 导入时&#xff0c;右击接收的表&#xff0c;点击导入向导&#xff0c;根据提示即可快速导入&#xff08;注&#xff1a;不同系统之间导出导入易…

tongweb通过控制台简单设置确认相关常用参数

1.环境版本 jdk&#xff0c;tongweb版本确认是否正确 2.检查tongweb的 license是不是永久版本&#xff0c;试用期版本到期会停止服务。 3 JVM运行编码配置-根据系统需要配置 3.1-Dfile.encodingUTF-8 编码根据系统需要配置 4. tongweb运行内存大小--根据系统需要配置 4.1一般 …

编译原理--LL(1)分析法实验C++

一、实验项目要求 1.实验目的 根据某一文法编制调试LL&#xff08;1&#xff09;分析程序&#xff0c;以便对任意输入的符号串进行分析。本次实验的目的主要是加深对预测分析LL&#xff08;1&#xff09;分析法的理解。 2.实验要求 对下列文法&#xff0c;用LL&#xff08;…

实际中进行GC调整

调优垃圾回收与任何其他性能调优活动没有什么不同。 您需要确保了解当前的情况和期望的结果&#xff0c;而不是因为对应用程序的随机部分进行调整而产生了诱惑。 通常&#xff0c;只需执行以下过程即可&#xff1a; 陈述您的绩效目标 运行测试 测量 与目标比较 进行更改并…

达梦数据库出现卡慢简单分析点

1.检查是否有锁表 查询锁表&#xff1a;select sess_id,sql_text from v$sessions sess,v$lock lck where sess.trx_idlck.trx_id and lck.blocked1; --查询僵死会话 解锁&#xff1a;根据会话ID&#xff0c;停止会话 sp_close_session(sess_id); 2.根据v$sessions,V$L…

SEL selector (二)

SEL消息机制工作原理是什么 引用下面文章&#xff1a; 我们在之前有提到,一个类就像一个 C 结构.NSObject 声明了一个成员变量: isa. 由于 NSObject 是所有类的根类,所以所有的对象都会有一个 isa 的成员变量[公共继承].而该 isa 变量指向该对象的类(图3.15)[类在Objective-C中…

mobile cpu上禁用alpha test的相关总结

因为&#xff0c;每家芯片的特性不同&#xff0c;根据向framebuffer写法的不同&#xff0c;分为tile-based的mobile cpu&#xff0c;如ImgTec PowerVR&#xff0c;ARM Mali&#xff0c;一部分老版本Qualcomm Adreno。还有标准的direct&#xff08;immediate&#xff09;的mobil…

达梦定时迁移数据

1. 生成迁移源代码 1.1 启动DM迁移工具&#xff08;bin/dts.exe&#xff09; 1.2 右击迁移管理空白处 -> 新建工程 1.3 展开工程 -> 右击迁移&#xff0c;新建迁移 -> 输入迁移名称&#xff0c;确认 1.4 右击迁移名称&#xff0c;打开 -> 输入源数据库连接信息&…

JSP教程–最终指南

编者注&#xff1a; JavaServer Pages&#xff08;JSP&#xff09;技术使您可以轻松创建同时包含静态和动态组件的Web内容。 JSP技术提供了Java Servlet技术的所有动态功能&#xff0c;但提供了一种更自然的方法来创建静态内容。 JSP技术的主要功能包括用于开发JSP页面的语言&…

tongweb6数据源使用中时常报空异常处理方式

1.在tongweb控制台 -> jdbc配置中设置数据源参数 1.1 勾选空闲超时&#xff0c;时间默认 1.2 勾选泄露超时时间 &#xff0c;时间为半天&#xff08;14400&#xff09; 1.3 勾选连接有效性检查、创建连接验证、获取连接验证、归还连接验证 图中设置泄露超时时间为900…

eclipse远程tomcat javaweb debug样例(windows)

1.tomcat配置可被远程debug端口参数 catalina.bat 中添加 set CATALINA_OPTS-Xdebug -agentlib:jdwptransportdt_socket,servery,suspendn,address8000 导出项目war包到tomcat/webapps/目录下 切换到tomcat/bin目录下 双击startup.bat启动运行项目 2.eclipse中启动远程debug…

ASP.NET MVC的ContentResult

ASP.NET MVC的ContentResult返回简单的纯文本内容&#xff0c;可通过ContentType属性指定应答文档类型&#xff0c;通过ContentEncoding属性指定应答文档的字符编码。一个例子来演习&#xff0c;自定义一个RwResult&#xff0c;它继承ContentResult&#xff0c;为视图象ASP.NET…

windows搜索指定目录下包含某个字符串的文件

1.打开cmd窗口 &#xff1a;winr 快捷键-> 输入cmd 回车 2.切换到被搜索的文件夹&#xff08;E:\shgwy文档\日常\更新\20220808&#xff09;下 如输入&#xff1a; cd E:\shgwy文档\日常\更新\20220808 e: 3.输入搜索命令 c:\Windows\System32\findstr.exe /s /i "wa…

IIS7日志文件位置

准备统计下页面访问量 查找IIS日志,发现在以前IIS6日志的位置&#xff0c;竟然木有找到日志... 查看下IIS设置&#xff0c;发现IIS7和6的默认日志位置不一样额... IIS 6 Log files location IIS 6中日志文件的位置 %windir%\System32\LogFiles IIS 7 Log files location IIS的日…

jwt重放攻击_4个点搞懂JWT、JWS、JWE

1.JWT是何物&#xff0c;有哪些常用的场景JWT(json web token)是设计一种简洁&#xff0c;安全&#xff0c;无状态的token的实现规范rfc7519&#xff0c;通常用于网络请求方和网络接收方之间的网络请求认证。jwt的常用场景1.1: restful api接口的无状态认证, 在传统的web应用中…

Verification Mind Games---how to think like a verifier像验证工程师一样思考

1. 有效的验证需要验证工程师使用不同于设计者的思维方式思考问题。具体来说&#xff0c;验证更加关心在严格遵循协议的基础上发现设计里面的bug&#xff0c;搜索corner cases&#xff0c;对设计的不一致要保持零容忍的态度。mindset&#xff1a;一套人们应该持有的确定的态度&…