反射、枚举以及Lambda表达式_反射getmethod
liuian 2025-09-04 11:59 8 浏览
一、反射
1.定义
Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法(即使是私有的);对于任意一个对象,都能够调用它的任意方法和属性,那么,我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射(reflection)机制。
2.用途
1、在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法 。
2、反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。
简单来说:反射就是Java中运行时的机制,在运行的时候,可以获取类的信息,包括调用类的属性和方法,包括修改。
3.反射基本信息
Java程序中许多对象在运行时会出现两种类型:运行时类型(RTTI)和编译时类型,例如Person p = new Student();这句代码中p在编译时类型为Person,运行时类型为Student。程序需要在运行时发现对象和类的真实性。而通过使用反射程序就能判断出该对象和类属于哪些类。
4.反射相关的类(重要)
面试会问到与Java反射相关的四个类:
4.1 Class类(反射机制的起源 )
Java文件被编译后,生成了.class文件,JVM此时就要去解读.class文件 ,被编译后的Java文件.class也被JVM解析为一个对象,这个对象就是 java.lang.Class .这样当程序在运行时,每个java文件就最终变成了Class类对象的一个实例。我们通过Java的反射机制应用到这个实例,就可以去获得甚至去添加改变这个类的属性和动作,使得这个类成为一个动态的类 。
4.1.1 Class类中的相关方法(方法的使用方法在后边的示例当中)
(重要)常用获得类相关的方法。
(重要)常用获得类中属性相关的方法。
(重要)获得类中构造器相关的方法。
(重要)获得类中方法相关的方法。
4.2 反射示例
设有Student类:
class Student{
//私有属性name
private String name = "bit";
//公有属性age
public int age = 18;
//不带参数的构造方法
public Student(){
System.out.println("Student()");
}
private Student(String name,int age) {
this.name = name;
this.age = age;
System.out.println("Student(String,name)");
}
private void eat(){
System.out.println("i am eat");
}
public void sleep(){
System.out.println("i am pig");
}
private void function(String str) {
System.out.println(str);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
4.2.1 获得Class对象的三种方式
在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的Class对象,然后通过Class对象的核心方法,达到反射的目的,即:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息。
第一种,使用 Class.forName(“类的全路径名”); 静态方法。
前提:已明确类的全路径名。
注:通过 Class 对象的 forName() 静态方法来获取,用的最多,但可能抛出ClassNotFoundException 异常。
try {
Class c3 = Class.forName("reflect.Student");//括号中要写reflect包底下的Student类
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
第二种,使用 .class 方法。
说明:仅适合在编译前就已经明确要操作的 Class。
注:直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高,这说明任何一个类都有一个隐含的静态成员变量 class。
Class c2 = Student.class;
第三种,使用类对象的 getClass() 方法。
注:通过已知类的getClass方法获取Class对象。
Student s1 = new Student();
Class c1 = s1.getClass();
当我们用equals方法去判断拿到这些Class类的引用是否是相同的引用时,打印的结果都为true。
System.out.println(c1.equals(c2));
System.out.println(c1.equals(c2));
System.out.println(c2.equals(c2));
4.2.2反射的使用
接下来我们开始使用反射,我们依旧反射上面的Student类,把反射的逻辑写到另外的类当中进行理解。
注意:所有和反射相关的包都在 java.lang.reflect 包下面。
创建对象:
public static void reflectNewInstance(){
//获取Class对象
try {
Class<?> c1 = Class.forName("Student");
//创建对象
Student student = (Student)c1.newInstance();//newInstance方法返回的是Object类型
System.out.println(student);//调用toString打印student里面的属性
}catch(Exception e) {
e.printStackTrace();
}
}
反射私有的构造方法 屏蔽内容为获得公有的构造方法。
public static void reflectPrivateConstructor() {
try {
Class<?> c1 = Class.forName("Student");
Constructor<?> constructor = c1.getDeclaredConstructor(String.class,int.class);//调用两个参数并且第一个参数为String类型,第二个参数为int类型的构造方法
constructor.setAccessible(true);//构造方法是私有的,设置访问权限为true
Student student = (Student)constructor.newInstance("zjr",18);//设置完访问权限后直接创建对象,并把参数传入拿到的私有的构造方法。只有这种情况下用构造方法来创造对象,其它都是用的Class类的引用
System.out.println(student);//打印student的属性
}catch(Exception e) {
e.printStackTrace();
}
}
反射私有属性
public static void reflectPrivateField() {
try {
Class<?> c1 = Class.forName("Student");
Field field = c1.getDeclaredField("name");//括号里面的是想要拿到的哪个名字的属性
field.setAccessible(true);//设置访问权限为true
Student student = (Student)c1.newInstance();
field.set(student,"小明");//设置属性改为小明
String name = (String)field.get(student);
System.out.println("反射私有属性修改了name:"+ name);
}catch(Exception e) {
e.printStackTrace();
}
}
反射私有方法
public static void reflectPrivateMethod() {
try {
Class<?> c1= Class.forName("Student");
Method method = c1.getDeclaredMethod("function",String.class);//第一个参数是方法的名字,第二个参数是方法的形参类型
method.setAccessible(true);
Student student = (Student) c1.newInstance();
method.invoke(student,"我是给私有的function函数传的参数");//调用方法用invoke,第一个参数为对象的引用,第二个参数为传入的实参
}catch(Exception e) {
e.printStackTrace();
}
}
5.反射的优点与缺点
优点:
- 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。
- 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力。
- 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。
缺点:
- 使用反射会有效率问题。会导致程序效率降低。对应博客
- 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。
二、枚举
1.枚举的背景及定义
枚举是在JDK1.5以后引入的。主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式:
public static int final RED = 1;
public static int final GREEN = 2;
public static int final BLACK = 3;
但是常量举例有不好的地方,例如:可能碰巧有个数字1,但是他有可能误会为是RED,现在我们可以直接用枚举来进行组织,这样一来,就拥有了类型,枚举类型。而不是普通的整形1 。
public enum TestEnum {
RED,BLACK,GREEN;
}
优点:将常量组织起来统一进行管理。
场景:错误状态码,消息类型,颜色的划分,状态机等等…
本质:是 java.lang.Enum 的子类,也就是说,自己写的枚举类,就算没有显示的继承 Enum ,但是其默认继承了这个类。
2.枚举的使用
2.1 switch方法
因为switch语句的中的参数不能是long,boolean,float,double类型,而没有说不能是枚举类型。
public enum TestEnum {
RED,BLACK,GREEN,WHITE;
public static void main(String[] args) {
TestEnum testEnum2 = TestEnum.BLACK;//靠类名去拿到枚举对象
switch (testEnum2) {
case RED:
System.out.println("red");
break;
case BLACK:
System.out.println("black");
break;
case WHITE:
System.out.println("WHITE");
break;
case GREEN:
System.out.println("green");
break;
default:
break;
}
}
}
2.2 Enum 类的常用方法
示例:
RED,BLACK,GREEN,WHITE;
public static void main(String[] args) {
TestEnum[] testEnums = TestEnum.values();
for (int i = 0; i < testEnums.length; i++) {
System.out.println(testEnums[i]+" " + testEnums[i].ordinal());//索引位置从0开始
}
System.out.println(TestEnum.valueOf("GREEN"));
System.out.println("==============");
System.out.println(GREEN.compareTo(WHITE));
}
打印结果:
RED 0
BLACK 1
GREEN 2
WHITE 3
GREEN
==============
-1
在Java当中枚举实际上就是一个类。所以我们在定义枚举的时候,还可以这样定义和使用枚举:
重要:枚举的构造方法默认是私有的
public enum TestEnum {
//枚举对象
RED("red",1),BLACK("black",2),
GREEN("green",3),WHITE("white",4);
private String name;
private int ordinal;
//枚举的构造方法 默认是私有的
TestEnum(String name,int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
public static TestEnum getEnumKey (int ordinal) {
for (TestEnum t: TestEnum.values()) {
if(t.ordinal == ordinal) {
return t;
}
}
return null;
}
public static void main(String[] args) {
System.out.println(getEnumKey(2));//BLACK
}
}
3. 枚举的优点与缺点
优点:
- 枚举常量更简单安全 。
- 枚举具有内置方法 ,代码更优雅。
缺点:
- 不可继承,无法扩展
三、枚举和反射的联系
在反射中,已知即使一个属性或方法是私有的,通过反射可以获取或修改或者调用它们的属性或方法。那么在枚举中是否也可以运用反射?
public enum TestEnum {
//枚举对象
RED("red", 1), BLACK("black", 2),
GREEN("green", 3), WHITE("white", 4);
private String name;
private int ordinal;
//枚举的构造方法 默认是私有的
TestEnum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
public static void reflectPrivateConstructor() {
try {
//1、获取Class对象
Class<?> c = Class.forName("TestEnum");
//2、获取构造方法
Constructor<?> constructor = c.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
//3、获取对象的实例
TestEnum testEnum = (TestEnum) constructor.newInstance("gaobo", 18);
System.out.println(testEnum);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
reflectPrivateConstructor();
}
}
运行结果:
我们发现调用构造方法的时候传了两个参数并且自定义的枚举类当中也有两个参数的构造方法,那为什么会报错呢?
原因是我们自定义的枚举类它是继承于Enum类的,因此调用自定义枚举类的时候会帮助Enum类构造,点入Enum类的源码当中它只有一个带两个参数的构造方法。因此我们在获得构造方法时要传多两个参数。
此时将Constructor<?> constructor = c.getDeclaredConstructor(String.class, int.class);改为Constructor<?> constructor = c.getDeclaredConstructor(String.class, int.class, String.class, int.class); ;TestEnum testEnum = (TestEnum) constructor.newInstance("zjr", 18, "123", 456);改为TestEnum testEnum = (TestEnum) constructor.newInstance("zjr", 18);
此时再运行,运行结果为:
此时还报错的原因:
点入newInstance的源码,有:如果是枚举类,则抛出异常,枚举在这里被过滤了,不能通过反射获取枚举类的实例。
面试题:为什么枚举实现单例模式是安全的?
四、Lambda表达式
1.背景
Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 **Lambda 表达式(Lambda expression)可以看作是一个匿名函数,**基于数学中的λ演算得名,也可称为闭包(Closure) 。
1.1 Lambda表达式的语法
基本语法: (parameters) -> expression 或 (parameters) ->{ statements;}
Lambda表达式由三部分组成:
- paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
- ->:可理解为“被用于”的意思。
- 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不返回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不返回。
// 1. 不需要参数,返回值为 2
() -> 2
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的和
(x, y) -> x + y
// 4. 接收2个int型整数,返回他们的乘积
(int x, int y) -> x * y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
1.2 函数式接口
要了解Lambda表达式,首先需要了解什么是函数式接口,函数式接口定义:一个接口有且只有一个抽象方法。
注意:
- 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
- 如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的
定义方式:
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
这种方式也是可以的:
@FunctionalInterface
interface NoParameterNoReturn {
void test();
default void test2() {
System.out.println("JDK1.8新特性,default默认方法在接口可以有具体的实现");
}
}
但是我们观察Comparator接口:
它注释的是函数式接口,但是它里面却有两个抽象方法,这个又是什么原因呢?
Comparator接口中有两个抽象方法但还是函数式接口的原因
2.Lambda表达式的使用
2.1 Lambda表达式的语法
- 参数类型可以省略,如果需要省略,每个参数的类型都要省略。
- 参数的小括号里面只有一个参数,那么小括号可以省略。
- 如果方法体当中只有一句代码,那么大括号可以省略。
- 如果方法体中只有一条语句,其是return语句,那么大括号可以省略,且去掉return关键字。
2.2 Lambda表达式的使用
首先,我们实现准备好几个接口:
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
void test(int a);
}
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
void test(int a,int b);
}
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
int test();
}
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
int test(int a);
}
//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
int test(int a,int b);
}
//有返回值参数类型不同
@FunctionalInterface
interface MoreParameterReturn2 {
double test(int a,double b);
}
我们在上面提到过,Lambda表达式本质是一个匿名函数,函数的方法是:返回值、方法名、参数列表、方法体。在Lambda表达式中我们只需要关心:参数列表与方法体。
因此可以将上面的函数式接口都变为Lambda表达式去使用。
class T {
public static void main(String[] args) {
NoParameterReturn noParameterReturn = () -> {
System.out.println("fafsaf");
return 1;
};
int ret = noParameterReturn.test();
System.out.println(ret);
//当lambada表达式 只有一个语句的是 可以省略花括号
NoParameterReturn noParameterReturn2 = () -> 1;
ret = noParameterReturn2.test();
System.out.println(ret);
System.out.println("==================");
// OneParameterReturn oneParameterReturn = (a)->{return a;};
// OneParameterReturn oneParameterReturn = (a)->a;
OneParameterReturn oneParameterReturn = a -> a;
ret = oneParameterReturn.test(10);
System.out.println(ret);
System.out.println("==================");
// MoreParameterReturn moreParameterReturn = (int a,int b)->{return a+b;};
// MoreParameterReturn moreParameterReturn = (a,b)->{return a+b;};
MoreParameterReturn moreParameterReturn = (a, b) -> a + b;
ret = moreParameterReturn.test(10, 20);
System.out.println(ret);
System.out.println("==================");
MoreParameterReturn2 moreParameterReturn2 = (int a, double b) -> {
return a + b;
};
}
}
3.Lambda的变量捕获
Lambda 表达式中存在变量捕获 ,了解了变量捕获之后,我们才能更好的理解Lambda 表达式的作用域 。Java当中的匿名类中,也存在变量捕获。
匿名内部类的变量捕获在之前的博客有写到过,以下以Lambda表达式的变量捕获的例子来演示:
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
public static void main(String[] args) {
int a = 10;
NoParameterNoReturn noParameterNoReturn = ()->{
// a = 99;
error System.out.println("捕获变量:"+a);
};
noParameterNoReturn.test();
}
4.Lambda在集合当中的使用
为了能够让Lambda和Java的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与Lambda表达式对接。 前提是你有足够的了解这些接口。
注意:Collection的forEach()方法是从接口 java.lang.Iterable 拿过来的。
4.1 Collection接口
forEach() 方法演示
在ArrayList中,forEach方法是重写Iterable接口的forEach方法。当我们找到ArrayList中的forEach方法,它的原型如下:
发现传到方法当中的参数是Consumer类型的,点进去发现它是一个函数式接口。并且里面有accept的抽象方法。再往下看,发现上图被红线框住的地方遍历了list,调用了accept方法,因此我们要重写accept方法。
若不用Lambda表达式,则为:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("aello");
list.add("bit");
list.add("lambda");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
}
//打印结果:Hello bit hello lambda
若用Lambda表达式,则为:list.forEach((str)->{System.out.println(str);});或者list.forEach(str-> System.out.println(str));,最终打印的结果都是一样的。
4.2 List接口
sort()方法的演示
sort方法源码:该方法根据c指定的比较规则对容器元素进行排序。
先看看ArrayList当中的sort方法是如何处理的:
我们发现传入的要一个Comarator接口,因此只要重新compare方法即可。
若不用Lambda表达式:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("aello");
list.add("bit");
list.add("lambda");
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
//输出结果:bit, Hello, hello, lambda
若用Lambda表达式:
则改为list.sort(((o1, o2) -> o1.compareTo(o2)));即可。
4.3 Map接口
HashMap 的 forEach()
传入的BiConsumer是一个函数式接口。因为也是遍历list,调用接口的accept方法。所以要重新accept方法。
若不用Lambda表达式:
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "hello");
map.put(2, "bit");
map.put(3, "hello");
map.put(4, "lambda");
map.forEach(new BiConsumer<Integer, String>() {
@Override
public void accept(Integer integer, String s) {
System.out.println("key: "+integer +" val " + s);
}
});
若用Lambda表达式:
改为map.forEach((key,val)-> System.out.println("key: "+key +" val " + val));
5.Lambda表达式的优缺点
Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。
优点:
- 代码简洁,开发迅速
- 方便函数式编程
- 非常容易进行并行计算
- Java 引入 Lambda,改善了集合操作。
缺点:
- 代码可读性变差
- 在非并行计算中,很多计算未必有传统的 for 性能要高
- 不容易进行调试
获取课件资料→腾讯文档
相关推荐
- C语言学习从内存堆栈视角,给这段枚举代码做个 "内存透视"
-
从内存堆栈视角,给这段枚举代码做个"内存透视"#include<stdio.h>enumDAY{MON=1,TUE,WED,THU,FR...
- Python基础:枚举,都有哪些特点和使用场景呢?
-
在Python编程语言中,枚举(Enumeration)是一种特殊的类,用于为一组常量创建一个名称空间。枚举类在Python3.4中被引入,提供了一种更加直观和方便的方式来处理一组相关的常量。枚举类...
- Java枚举你真的会用吗_java枚举怎么使用
-
概述Java中枚举,大家在项目中经常使用吧,主要用来定义一些固定值,在一个有限的集合内,比如在表示一周的某一天,一年中的四季等。那你了解枚举的本质吗?了解枚举的一些常见用法吗?枚举介绍和使用枚举主要用...
- 反射、枚举以及Lambda表达式_反射getmethod
-
一、反射1.定义Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法(即使是私有的);对于任意一个对象,都能够调用它的任意方法和属性,那么,我们就...
- 一个高效使用cursor开发项目的方法,怎么让 AI 写的代码不跑题?
-
最近又用cursor做了一个小应用,番茄时钟,用来管理自己的时间,提高效率。然后使用cursor开发的过程中。有了一些新的感悟。找到了一条可以让Curosr不跑题的办法。生成一份详细的项目资...
- 前端铜九铁十面试必备八股文——工程化
-
常用的git命令gitclone:克隆远程仓库到本地。gitinit:在当前目录初始化一个新的Git仓库。gitadd:将文件添加到暂存区,准备提交。gitcommit-m"co...
- IntelliJ IDEA 2025.2 的主要更新亮点
-
以下是该版本的一些关键改进与功能更新:AI增强体验离线Java代码补全:AI助手现在支持在离线模式下进行Java代码块建议,并允许用户选择本地代码模型使用。AIAssistant新增...
- 一行命令,AI 直接写代码!OpenAI 正式发布 Codex CLI
-
【一句话速读】OpenAI把2021年的Codex品牌复活,推出全新CodexCLI——一个本地运行的轻量级编码代理。只需npmi-g@openai/codex,它就能在终端里帮...
- 如何使用高级TypeScript模式构建可扩展的QA框架
-
TypeScript自动化QA(7部分系列)TypeScript第一步:自动化QA实用路线图如何在TypeScript中使用数组和对象构建强大的QA自动化脚本如何掌握TypeScript基础...
- Bun JS工具包新增MySQL驱动和密钥管理功能
-
Bun团队发布了其JavaScript打包器和运行时的1.2.21版本,该工具使用Zig语言编写,新增了包括MySQL和SQLite内置驱动、YAML解析器以及用于工具和本地开发的密钥管理器等功能。新...
- 编码 10000 个小时后,开发者悟了:“不要急于发布!”
-
【CSDN编者按】在软件开发的道路上,时间是最好的老师。根据“一万小时定律”,要成为某个领域的专家,通常需要大约一万小时的刻意练习。本文作者身为一名程序员,也经历了一万小时的编程,最终悟出了一个道理...
- 一文说明,TypeScript 的装饰器_typescript logo
-
●装饰器(Decorators)●注意:装饰器目前是一项实验性特性,在未来的版本中可能会发生改变●装饰器一般使用在以下几个地方○类○类属性○类方法○类方法的参数○通过这些我们也能看得出来,...
- 前端小哥哥:如何使用typescript开发实战项目?
-
前言笔者上一篇文章:主要写了typescript的用法和核心知识点总结,这篇文章将通过一个实际的前端案例来教大家如何在项目中使用typescript.你将收获如何使用umi快速搭建一个基于React...
- 一篇文章搞懂TypeScript_typescript implements
-
TypeScript是JavaScript的超集,一方面给动态类型的js增加了类型校验,另一方面扩展了js的各种功能。原始数据类型字符串数值布尔nullundefinedSymbolBi...
- TypeScript的any和unknown,用错一个就是线上Bug
-
在TypeScript开发中,类型系统是我们抵御运行时错误的第一道防线。但两个特殊类型——any和unknown,却常常被误用,成为线上故障的隐形推手。本文通过真实案例解析,告诉你为什么unknown...
- 一周热门
-
-
【验证码逆向专栏】vaptcha 手势验证码逆向分析
-
Python实现人事自动打卡,再也不会被批评
-
Psutil + Flask + Pyecharts + Bootstrap 开发动态可视化系统监控
-
一个解决支持HTML/CSS/JS网页转PDF(高质量)的终极解决方案
-
再见Swagger UI 国人开源了一款超好用的 API 文档生成框架,真香
-
网页转成pdf文件的经验分享 网页转成pdf文件的经验分享怎么弄
-
C++ std::vector 简介
-
飞牛OS入门安装遇到问题,如何解决?
-
系统C盘清理:微信PC端文件清理,扩大C盘可用空间步骤
-
10款高性能NAS丨双十一必看,轻松搞定虚拟机、Docker、软路由
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)