• Java注解与反射知识梳理


    Java注解与反射

    注解

    内置注解

    • @Overrice
    • @Deprecated
    • @SupperessWarnings
    package annotation;
    
    import java.util.ArrayList;
    import java.util.List;
    
    // 什么是注解
    public class Test01 extends Object{
        // @Override重写的注解
        @Override
        public String toString() {
            return super.toString();
        }
    
        // Deprecated 不推荐程序员使用,但是可以使用. 或者存在更好的方式
        @Deprecated
        public static void test(){
            System.out.println("Deprecated");
        }
    
        @SuppressWarnings("all")
        public void test02(){
            List list = new ArrayList();
        }
    
        public static void main(String[] args) {
            test();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    元注解

    • 元注解的作用就是负责注解其他注解,4种
    • 在java.lang.annotation中可找到(@Target, @Retetion, @Documente, @Inherited)
      • @Target:用于描述注解的使用范围
      • @Retetion:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE < CLASS < RUNTIME)
      • @Documente: 说明该注解将被包含在javadoc中
      • @Inherited:说明子类可以继承父类的该注解

    自定义注解

    • 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
    • 分析
      • @interface用来声明一个注解,格式:public @interface注解名{定义内容}
      • 其中每一个方法实际上是声明了一个参数配置
      • 方法的名称就是参数的名称
      • 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
      • 可以通过default来声明参数的默认值
      • 如果只有一个参数成员,一般参数名为value
      • 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值
    package annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    // 自定义注解
    public class test03 {
        // 注解可以显示赋值,如果没有默认值,我们就必须给注解赋值
        @MyAnnotation2(name="alex",school = {"snut","sust"})
        public void test(){}
    
        @MyAnnotation3("alex")
        public void test2(){}
    }
    
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation2{
        // 注解的参数:参数类型 + 参数名();
        String name();
        int age() default 0;
        int id() default -1; // 如果默认值是-1,代表不存在
    
        String[] school();
    }
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation3{
        String value();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    反射机制 java.reflection

    静态语言 vs 动态语言

    • 动态语言
      • 是一类在运行时可以改变结构的语言
      • 主要动态语言: Object-C,c#,JavaScript,PHP,Python等
    • 静态语言
      • 运行时结构不可改变的语言就是静态语言。如Java,C,C++
      • Java不是动态语言,由于反射机制,所以Java是“准动态语言”

    Java Reflection

    • Reflection是Java被视为动态语言的关键,反射机制允许程序在执行期间借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
          Class c = Class.forName("java.lang.String")
      
      • 1
    • 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像是一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射
      正常方式:引入需要的包名 -> 通过new实例化 -> 取得实例化对象
      反射方式:实例化对象 -> getClass()方法 -> 得到完整的“包类”名称

    功能

    • 运行时判断任意一个对象所属的类
    • 运行时构造任一个类的对象
    • 运行时判断任意一个类所具有的成员变量和方法
    • 运行时获取泛型信息
    • 运行时调用任一个对象的成员变量和方法
    • 运行时处理注解
    • 生成动态代理

    优点
    可以实现动态创建对象和编译,灵活
    缺点
    对象能有影响。是一种解释操作,jvm满足人,慢于直接执行的相同操作。

    package reflection;
    
    
    // 什么叫反射
    public class test01 {
        // 通过反射机制获取类的Class对象
        public static void main(String[] args) throws ClassNotFoundException {
            Class c1 = Class.forName("reflection.User");
            System.out.println(c1);
    
            Class c2 = Class.forName("reflection.User");
            Class c3 = Class.forName("reflection.User");
    
            // 一个类在内存中只有一个Class对象
            // 一个类被加载后,类的整个结构都会被封装在Class对象中
            System.out.println(c1.hashCode());
            System.out.println(c2.hashCode());
            System.out.println(c3.hashCode());
        }
    }
    
    //实体类
    class User{
        private String name;
        private int id;
        private int age;
    
        public User(){
    
        }
    
        public User(String name, int id, int age){
            this.name = name;
            this.id = id;
            this.age = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    获取Class类的实例

    1. 若已知具体的类,通过类的class属性获取,该方法是最为安全可靠,程序性能最高;
          Class clazz = Person.class;
      
      • 1
    2. 已知某个类的实例,调用该实例的getClass()方法获取Class对象
          Class clazz = person.getClass();
      
      • 1
    3. 已知一个类的全类名,且该类在路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNOtFoundException
          Class clazz = Class.forName("demo01.Student");
      
      • 1
    4. 内置基本数据类型可以直接用类名.Type
    5. 还可以利用Class Loader
    package reflection;
    
    public class Test03 {
        public static void main(String[] args) throws ClassNotFoundException {
            Person p1= new Student();
            System.out.println("这个人是:"+p1.name);
    
            // 方式1: 通过对象获得
            Class c1 = p1.getClass();
            System.out.println(c1.hashCode());
    
            // 方式2:通过forname获得
            Class c2 = Class.forName("reflection.Student");
            System.out.println(c2.hashCode());
    
            // 方式3:通过 类名.class获得
            Class c3 = Student.class;
            System.out.println(c3.hashCode());
    
            // 方式4: 基本内置类型的包装类都有一个Type属性
            Class c4 = Integer.TYPE;
            System.out.println(c4);
    
            // 获取父类类型
            Class c5 = c1.getSuperclass();
            System.out.println(c5);
            System.out.println(c5.hashCode());
        }
    }
    
    class Person{
        String name;
    
        public Person(){
    
        }
    
        public Person(String name){
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    
    class Student extends Person{
        public Student(){
            this.name = "学生";
        }
    }
    
    class Teacher extends Person{
        public Teacher(){
            this.name = "教师";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    按住option键可以复制多列,并给多列赋值

    哪些类可以有Class对象

    package reflection;
    
    import java.lang.annotation.ElementType;
    
    // 所有类型的Class
    public class Test03 {
        public static void main(String[] args) {
            Class c1 = Object.class;  // 类
            Class c2 = Comparable.class;  // 接口
            Class c3 = String[].class;  // 一维数组
            Class c4 = int[][].class;  // 二维数组
            Class c5 = Override.class;  // 注解
            Class c6 = ElementType.class;  // 枚举
            Class c7 = Integer.class;  // 基本数据类型
            Class c8 = void.class;  // void
            Class c9 = Class.class;  // Class
    
            System.out.println(c1);
            System.out.println(c2);
            System.out.println(c3);
            System.out.println(c4);
            System.out.println(c5);
            System.out.println(c6);
            System.out.println(c7);
            System.out.println(c8);
            System.out.println(c9);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    类的加载过程:Load(生成一个代表这个类的java.lang.Class对象) -> Link -> Initialize(执行类构造器)

    package reflection;
    
    public class Test04 {
        public static void main(String[] args) {
            A a = new A();
            System.out.println(a.m);
        }
    
        /*
            1. 加载到内存,会产生一个类对应Class对象
            2. 链接,链接结束后 m = 0
            3. 初始化
                (){
                    System.out.println("A类静态代码块初始化");
                    m = 300;
                    m = 100;
                }
                
             m = 100
         */
    }
    
    class A{
        static {
            System.out.println("A类静态代码初始化");
            m = 300;
        }
    
        static int m = 100;
    
        public A(){
            System.out.println("A类的无参构造初始化");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    主动引用和被动引用

    主动引用

    1. new
    2. 反射

    被动引用

    1. 子类直接调用父类
    2. 数组
    3. 加载常量
    package reflection;
    
    // 测试类什么时候会初始化
    public class Test05 {
        static {
            System.out.println("main类被加载");
        }
    
        public static void main(String[] args) throws ClassNotFoundException {
            // 1. 主动引用
    //         Son son = new Son();
    
            // 2.反射也会产生主动引用
    //        Class.forName("reflection.Son");
    
            // 3. 不会产生类的引用的方法
            // 3.1 子类直接调用父类
    //        System.out.println(Son.b);
    
            // 3.2 数组
    //        Son[] array = new Son[5];
            
            // 3.3 加载常量
            System.out.println(Son.M);
        }
    }
    
    class Father{
        static int b = 2;
        static{
            System.out.println("父类被加载");
        }
    }
    
    class Son extends Father{
        static {
            System.out.println("子类被加载");
            m = 300;
        }
    
        static int m = 100;
        static final int M = 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    通过反射获得类的方法、属性

    package reflection;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    // 获得类的信息
    public class Test07 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
            Class c1 = Class.forName("reflection.User");
    
    //        User user = new User();
    //        c1 = user.getClass();
    
            // 获得类的名字
            System.out.println(c1.getName());  // 获得包名+类名
            System.out.println(c1.getSimpleName());  // 获得类名
    
            // 获得类的属性
            System.out.println("=========================================");
            Field[] fields = c1.getFields();  // 只能找到public属性
            fields = c1.getDeclaredFields();
            for(Field field: fields){
                System.out.println(field);
            }
    
            // 获得指定的属性
            Field name = c1.getDeclaredField("name");
            System.out.println(name);
    
            // 获得类的方法
            System.out.println("==========================================");
            Method[] methods = c1.getMethods();  // 获得本类及其父类的全部public方法
            for(Method method : methods){
                System.out.println("正常的"+method);
            }
            methods = c1.getDeclaredMethods();  // 获取本类的所有方法,包括私有
            for(Method method: methods){
                System.out.println("getDeclaredMethods:"+method);
            }
    
            // 获得指定方法
            Method getName = c1.getMethod("getName", null);
            Method setName = c1.getMethod("setName", String.class);
            System.out.println(getName);
            System.out.println(setName);
    
            // 获得指定的构造器
            System.out.println("===========================================");
            Constructor[] constructors = c1.getConstructors();
            for (Constructor constructor : constructors){
                System.out.println(constructor);
            }
            constructors = c1.getDeclaredConstructors();
            for (Constructor constructor : constructors){
                System.out.println("#"+constructor);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    通过反射动态创建对象

    package reflection;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    // 动态创建对象,通过反射
    public class Test08 {
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
            // 获得Class对象
            Class c1 = Class.forName("reflection.User");
    
            // 1. 构造一个对象
    //        User user = (User) c1.newInstance();  // 本质是调用了类的无参构造器
    //        System.out.println(user);
    
            // 2. 通过构造器创建对象
    //        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
    //        User user2 =  (User)constructor.newInstance("alex", 1, 18);
    //        System.out.println(user2);
    
            // 通过反射调用普通方法
            User user3 = (User)c1.newInstance();
            // 通过反射获取一个方法
            Method setName = c1.getDeclaredMethod("setName", String.class);
            setName.invoke(user3, "alex");
            System.out.println(user3.getName());
    
            // 通过反射操作属性
            System.out.println("==============================================");
            User user4 = (User)c1.newInstance();
            Field name = c1.getDeclaredField("name");
    
            name.setAccessible(true);  // 关掉安全检检测,操作私有属性
            name.set(user4, "alex2");
            System.out.println(user4.getName());
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    性能

    package reflection;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    // 性能比较
    public class Test09 {
        public static void test01(){
            User user = new User();
            long startTime = System.currentTimeMillis();
    
            for (int i = 0; i < 1000000000; i++) {
                user.getName();
            }
            long endTime = System.currentTimeMillis();
            System.out.println("普通方法执行耗时:"+ (endTime-startTime)+"ms");
        }
    
        public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            User user = new User();
            Class c1 = user.getClass();
            Method getName = c1.getDeclaredMethod("getName", null);
    
            long startTime = System.currentTimeMillis();
    
            for (int i = 0; i < 1000000000; i++) {
                getName.invoke(user, null);
            }
            long endTime = System.currentTimeMillis();
            System.out.println("反射方式执行耗时:"+ (endTime-startTime)+"ms");
        }
    
        public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            User user = new User();
            Class c1 = user.getClass();
            Method getName = c1.getDeclaredMethod("getName", null);
            getName.setAccessible(true);
    
            long startTime = System.currentTimeMillis();
    
            for (int i = 0; i < 1000000000; i++) {
                getName.invoke(user, null);
            }
            long endTime = System.currentTimeMillis();
            System.out.println("反射关掉安全校验方式执行耗时:"+ (endTime-startTime)+"ms");
        }
    
        public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
            test01();
            test02();
            test03();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    通过反射获取泛型信息

    package reflection;
    
    import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.List;
    import java.util.Map;
    
    // 通过反射获取泛型
    public class Test10 {
        public void test01(Map map, List list){
            System.out.println("test01");
        }
    
        public Map test02(){
            System.out.println("test02");
            return null;
        }
    
        public static void main(String[] args) throws NoSuchMethodException {
            Method method = Test10.class.getMethod("test01", Map.class, List.class);
    
            Type[] genericParameterTypes = method.getGenericParameterTypes();
            for(Type genericParameterType : genericParameterTypes){
                System.out.println("#"+genericParameterType);
                if(genericParameterType instanceof ParameterizedType){
                    Type[] actualTypeArguments= ((ParameterizedType)genericParameterType).getActualTypeArguments();
                    for(Type actualTypeArgument : actualTypeArguments){
                        System.out.println(actualTypeArgument);
                    }
                }
            }
            System.out.println("=====================================================");
            method= Test10.class.getMethod("test02", null);
            Type genericReturnType = method.getGenericReturnType();
            if (genericReturnType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType)genericReturnType).getActualTypeArguments();
                for(Type actualTypeArgument: actualTypeArguments){
                    System.out.println(actualTypeArgument);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    通过反射获取注解

    package reflection;
    
    import java.lang.annotation.*;
    import java.lang.reflect.Field;
    
    // 反射操作注解
    public class Test11 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
            Class c1 = Class.forName("reflection.Student2");
    
            // 通过反射获得注解
            Annotation[] annotations= c1.getAnnotations();
            for(Annotation annotation : annotations){
                System.out.println(annotation);
            }
            // 获取注解的value的值
            TableAlex tableAlex = (TableAlex)c1.getAnnotation(TableAlex.class);
            String value = tableAlex.value();
            System.out.println(value);
    
    
            // 获得类指定的注解
            Field f = c1.getDeclaredField("id");
            FieldAlex annotation = f.getAnnotation(FieldAlex.class);
            System.out.println(annotation.columnName());
            System.out.println(annotation.type());
            System.out.println(annotation.length());
        }
    
    }
    
    @TableAlex("db_student")
    class Student2{
    
        @FieldAlex(columnName = "db_id", type = "int", length = 10)
        private int id;
        @FieldAlex(columnName = "db_age", type = "int", length = 10)
        private int age;
        @FieldAlex(columnName = "db_name", type = "varchar", length = 3)
        private String name;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Student2{" +
                    "id=" + id +
                    ", age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
    
    // 类名注解
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface TableAlex{
        String value();
    }
    
    
    // 属性的注解
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface FieldAlex{
        String columnName();
        String type();
        int length();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
  • 相关阅读:
    1.8、BGP线路
    只要掌握这2个方法,就能轻松学会如何提取伴奏,快来码住
    Linux下把Tomcat做成服务,并开机自启(方式2-systemctl)
    springboot毕设项目大学校园网络综合服务平台3j37p(java+VUE+Mybatis+Maven+Mysql)
    STM32项目分享:智能家居语音系统
    app小程序手机端Python爬虫实战13-fiddler如何抓取手机端数据包
    Spring 如何使用注解装配Bean呢?
    《计算机网络》考研:2024/3/11:2.1.6-习题精选(5、6题暂未完成)
    psd-tools
    【luogu P3295】萌萌哒(并查集)(倍增)
  • 原文地址:https://blog.csdn.net/baidu_33597755/article/details/128050936