Java反射和动态代理用法(附10道练习题)

news2024/12/23 7:52:52

目录

  • 一、什么是反射
  • 二、反射的核心接口和类
  • 三、测试代码 Bean 类和目录结构
    • Person 类
    • 代码目录结构
  • 四、反射的用法
    • 1. 获取 Class 对象
    • 2. 获取构造方法 Constructor 并使用
    • 3. 获取成员变量 Field 并使用
    • 4. 获取成员方法 Method 并使用
  • 五、动态代理与反射
    • 1. 动态代理三要素
      • (1)代理接口
      • (2)代理处理器
      • (3)代理对象的创建
    • 2. 动态代理实现步骤
    • 3. 案例:获取函数的执行时间
  • 六、练习
    • 1. 使用反射获取String类的所有公有方法,并把方法名打印出来。
    • 2. 使用反射创建一个对象,并调用其无参构造方法。
    • 3. 使用反射修改一个对象的私有字段值。
    • 4. 使用反射获取一个ArrayList的所有父类(包括间接父类)。
    • 5. 使用反射调用一个类的静态方法。
    • 6. 使用反射获取某个类的所有公有成员变量,并打印出每个成员变量的名称和类型。
    • 7. 使用反射获取某个类的所有成员方法,并打印出每个方法变量的名称和返回值类型。
    • 8. 使用反射调用一个对象的公有方法,并传递参数。
    • 9. 使用Java的动态代理实现一个简单的日志记录功能。
    • 10. 使用Java的动态代理实现一个简单的权限校验功能。

一、什么是反射

解释一:

Java 反射机制是在运行状态中,对于任意一个,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个属性和方法。这种动态获取信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。

解释二:
Java 反射是指在运行时动态检查和操作类的能力。通过反射,(对于一个对象)程序可以在运行时获取关于类、方法、属性、构造函数等的详细信息,并且可以动态地创建对象、调用方法以及访问和修改字段。反射提供了一种灵活的机制,使得程序可以在编译时不知道确切类型的情况下操作这些类型

二、反射的核心接口和类

Java 反射主要涉及以下几个核心类和接口,它们位于包 java.lang.reflect中:

Class:每个类和接口在 JVM 中都表示为一个 Class 对象。通过 Class 对象,程序可以获取类的全限定名、实现的接口、父类、构造函数、方法、字段等信息。
Constructor:表示类的构造函数。通过 Constructor 对象,程序可以创建类的新实例。
Field:表示类的属性。通过 Field 对象,程序可以获取或修改属性的值。
Method:表示类的方法。通过 Method 对象,程序可以调用方法。

三、测试代码 Bean 类和目录结构

Person 类

Person类有nameage属性,无参构造方法有参构造方法gettersettertoString以及自定义的sayHellosayGoodbye方法。

public class Person {
    private String name;
    private int age;

    public Person() {
        this.name = "unknown";
        this.age = 0;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

	// 省略getter()和setter()

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

	// public类型
    public void sayHello() {
        System.out.println("Hello, my name is " + this.name);
    }

	// private类型
    private void sayGoodbye() {
        System.out.println("Goodbye, my name is " + this.name);
    }

}

代码目录结构

在这里插入图片描述

四、反射的用法

1. 获取 Class 对象

Class 对象包含了类的结构信息,是反射的入口点。获取 Class 对象有三种方法,如下所示:

1. 类.class
2. 对象.getClass()
3. Class.forName()

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

        // 方式1: 类.class语法
        Class<?> cls1 = Person.class;
        System.out.println(cls1);               // class Person
        System.out.println(cls1.getName());     // Person

        // 方式2: 对象.getClass()
        Class cls2 = new Person().getClass();
        System.out.println(cls2.getName());     // Person

        // 方式3: 使用静态方法Class.forName(),需要捕获ClassNotFoundException
        try {
            Class<?> cls3 = Class.forName("Person");
            System.out.println(cls3.getName()); // Person
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        
    }
}

2. 获取构造方法 Constructor 并使用

cls.getDeclaredConstructor()获取 Class 对象的所有构造方法
cls.getConstructor()获取 Class 对象的公有构造方法
constructor.newInstance()使用 Class 构造方法创建对象

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) {
        try {
            // 获取Person类的Class对象
            Class cls = Class.forName("Person");
            // Class personClass = Person.class;
            // Class personClass = new Person().getClass();

            // 获取无参构造方法
            Constructor<?> noArgsConstructor = cls.getConstructor();
            // 创建对象
            Object person1 = noArgsConstructor.newInstance();
            // 重写了Person的toString方法直接打印即可
            System.out.println(person1); // Person{name='unknown', age=0}

            // 获取带参数的构造方法
            Constructor<?> paramArgsConstructor = cls.getConstructor(String.class, int.class);
            // 创建对象,并传递参数
            Object person2 = paramArgsConstructor.newInstance("Alice", 30);
            System.out.println(person2); // Person{name='Alice', age=30}

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. 获取成员变量 Field 并使用

cls.getDeclaredField(name)获取 Class 对象的所有成员变量
cls.getField(name)获取 Class 对象的所有公有成员变量
field.setAccessible(true)设置 Class 对象的属性值可访问
field.get()获取 Class 对象的属性值
field.set()设置 Class 对象的属性值

import java.lang.reflect.Field;

public class Main {
    public static void main(String[] args) {
        try {
            // 获取Person类的Class对象
            Class cls = Class.forName("Person");
            // Class personClass = Person.class;
            // Class personClass = new Person().getClass();

            // 创建Person对象
            Person person = new Person("Alice",30);

            // 获取name字段
            Field nameField = cls.getDeclaredField("name");
            // 设置可访问性,因为name是私有的
            nameField.setAccessible(true);
            // 获取name字段的值
            String name = (String) nameField.get(person);
            System.out.println("Name: " + name);        // Name: Alice

            // 获取age字段
            Field ageField = cls.getDeclaredField("age");
            // 设置可访问性,因为age是私有的
            ageField.setAccessible(true);
            // 获取age字段的值
            int age = ageField.getInt(person);
            System.out.println("Age: " + age);          // Age: 30

            // 修改age字段的值
            ageField.setInt(person, 31);
            // 再次获取age字段的值,验证修改是否成功
            age = ageField.getInt(person);
            System.out.println("Updated Age: " + age);  // Updated Age: 31

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4. 获取成员方法 Method 并使用

cls.getDeclaredMethod(name)获取 Class 对象的所有成员方法
cls.getMethod(name)获取 Class 对象的公有成员方法
method.setAccessible(true)设置 Class 对象的方法可访问
method.invoke()调用 Class 对象的成员方法

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) {
        try {
            // 获取Person类的Class对象
            Class<?> cls = Class.forName("Person");

            // 创建Person对象
            Person person = (Person) cls
                    .getDeclaredConstructor(String.class, int.class)
                    .newInstance("Alice", 30);
            //或 Person person =new Person("Alice", 30);

            // 获取sayHello方法
            Method sayHelloMethod = cls.getMethod("sayHello");
            // 调用sayHello方法
            sayHelloMethod.invoke(person);

            // 获取sayGoodbye方法
            Method sayGoodbyeMethod = cls.getDeclaredMethod("sayGoodbye");
            // 设置可访问性,因为sayGoodbye是私有的
            sayGoodbyeMethod.setAccessible(true);
            // 调用sayGoodbye方法
            sayGoodbyeMethod.invoke(person);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

五、动态代理与反射

Java 动态代理是 Java 语言中一种用于在运行时创建代理实例的机制,它允许拦截并处理对任何对象的调用

通过动态代理,可以在不修改原始对象的情况下,对其方法进行增强或添加额外的行为。可以在方法执行前后进行一些操作,比如日志记录、性能监测、事务管理等。

1. 动态代理三要素

在Java中,要实现动态代理,需要满足以下必备条件:

(1)代理接口

必须有一个或多个接口。动态代理只能为接口创建代理实例,不能为类创建代理。

(2)代理处理器

需要实现java.lang.reflect.InvocationHandler接口,该接口包含一个invoke方法,用于处理所有对代理对象的方法调用。

(3)代理对象的创建

使用java.lang.reflect.Proxy类的newProxyInstance方法来创建代理对象。该方法需要以下三个参数:

  • ClassLoader:用于加载代理类的类加载器
  • Class<?>[] interfaces:代理类要实现的接口数组
  • InvocationHandler:处理代理实例上的方法调用的调用处理器

2. 动态代理实现步骤

(1)定义一个或多个接口,声明需要代理的方法。
(2)创建一个实现InvocationHandler接口的类,重写invoke方法以定义如何处理方法调用。
(3)使用Proxy.newProxyInstance方法创建代理对象,传入相应的类加载器接口数组调用处理器实例。

3. 案例:获取函数的执行时间

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义一个简单的接口,其中 sayHello 方法接收一个字符串参数
interface Hello {
    void sayHello(String message);
    void sayGoodBye(String message);
}

// 实现这个接口
class HelloImpl implements Hello {
    // 实现接口中的 sayHello 方法,并设置默认消息
    @Override
    public void sayHello(String message) {
        try {
            // 打印接收到的消息,模拟耗时操作
            System.out.println("Hello " + message);
            Thread.sleep(300);
        } catch (InterruptedException e) {
            // 异常处理
            e.printStackTrace();
        }
    }

    @Override
    public void sayGoodBye(String message) {
        try {
            // 打印接收到的消息,模拟耗时操作
            System.out.println("GoodBye " + message);
            Thread.sleep(300);
        } catch (InterruptedException e) {
            // 异常处理
            e.printStackTrace();
        }
    }

}

// 实现 InvocationHandler 接口
class TimeInvocationHandler implements InvocationHandler {
    private final Object target; // 目标对象

    // 构造函数,接收目标对象
    public TimeInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    // 处理代理实例的所有方法调用
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 判断方法名,只对 sayHello 方法进行时间测量
        if ("sayHello".equals(method.getName())) {
            long startTime = System.currentTimeMillis(); // 记录方法开始执行的时间
            Object result = method.invoke(target, args); // 调用目标对象的方法
            long endTime = System.currentTimeMillis(); // 记录方法结束执行的时间
            System.out.println("成员方法 " + method.getName() + " 花费了 " + (endTime - startTime) + " 毫秒.");
            return result; // 返回方法的执行结果
        } else {
            // 对于 sayGoodBye 方法,直接调用目标对象的方法,不进行时间测量
            return method.invoke(target, args);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建目标对象
        Hello hello = new HelloImpl();

        // 创建调用方法的处理器
        TimeInvocationHandler timeInvocationHandler = new TimeInvocationHandler(hello);

        // 创建一个代理实例
        Hello proxyInstance = (Hello) Proxy.newProxyInstance(
                hello.getClass().getClassLoader(),  // 类加载器
                hello.getClass().getInterfaces(),   // 代理类要实现的接口
                timeInvocationHandler               // 调用方法的处理器
        );

        // 使用代理对象调用方法,实际上会执行处理器的invoke方法
        proxyInstance.sayGoodBye("Python");
        // GoodBye Python

        proxyInstance.sayHello("Java");
        // Hello Java
        // 成员方法 sayHello 花费了 305 毫秒.
    }
}

六、练习

1. 使用反射获取String类的所有公有方法,并把方法名打印出来。

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) {
        Class<String> cls = String.class;
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }
    }
}


2. 使用反射创建一个对象,并调用其无参构造方法。

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) {
        Class<String> cls = String.class;
        try {
            Constructor<String> constructor = cls.getConstructor(String.class);
            // 指定了String就可以不用Object
            String s = constructor.newInstance("Hello world!");
            System.out.println(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. 使用反射修改一个对象的私有字段值。

import java.lang.reflect.Field;

class Employee {
    private int age;

    public Employee() {
    }

    public Employee(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    private void printAge() {
        System.out.println(this.age);
    }
}


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

        Employee employee = new Employee(30);
        Class cls = employee.getClass();
        try {
            Field ageField = cls.getDeclaredField("age");
            ageField.setAccessible(true);
            
            int age = ageField.getInt(employee);
            System.out.println(age);                // 30
            
            ageField.setInt(employee,31);
            System.out.println(employee.getAge());  // 31
            
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

4. 使用反射获取一个ArrayList的所有父类(包括间接父类)。

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        Class cls = ArrayList.class;
        while (cls != null) {
            System.out.println(cls.getName());
            cls = cls.getSuperclass();
        }
    }
}

5. 使用反射调用一个类的静态方法。

import java.lang.reflect.Method;

class MyMath {
    public static <T extends Number> T add(T a, T b) {
        if (a instanceof Integer) {
            return (T) Integer.valueOf(a.intValue() + b.intValue());
        } else if (a instanceof Double) {
            return (T) Double.valueOf(a.doubleValue() + b.doubleValue());
        } else {
            throw new IllegalArgumentException("Unsupported number type");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Class cls = MyMath.class;
        try {
            // 由于泛型擦除,需要指定方法的确切参数类型
            Method method = cls.getDeclaredMethod("add", Number.class, Number.class);
            // 静态方法必须指定null
            Object invoke = method.invoke(null, 1, 2);
            System.out.println(invoke); // 3
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

6. 使用反射获取某个类的所有公有成员变量,并打印出每个成员变量的名称和类型。

import java.lang.reflect.Field;

class People {
    public int id;
    public int age;
    private String name;
}

public class Main {
    public static void main(String[] args) {
        Class<People> cls = People.class;
        Field[] PeopleFields = cls.getFields();
        for (Field peopleField : PeopleFields) {
            System.out.println(peopleField.getName() + " => " + peopleField.getType());
        }
        
        //id => int
        //age => int

    }
}

7. 使用反射获取某个类的所有成员方法,并打印出每个方法变量的名称和返回值类型。

import java.lang.reflect.Method;

class People {
    public void printHello() {
        System.out.println("Hello, Java");
    }

    public String getHello(String Hello) {
        return Hello + ", Java";
    }

    private int getMoney() {
        return 0;
    }

}

public class Main {
    public static void main(String[] args) {
        Class<People> cls = People.class;
        Method[] methods = cls.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + " => " + method.getReturnType());
        }

        //printHello => void
        //getHello => class java.lang.String
        //getMoney => int
    }
}


8. 使用反射调用一个对象的公有方法,并传递参数。

import java.lang.reflect.Method;

class MyMath {
    public int add(int a, int b) {
        return a + b;
    }
}

public class Main {
    public static void main(String[] args) {
        Class<MyMath> myMathClass = MyMath.class;
        try {
            Method addMethod = myMathClass.getMethod("add", int.class, int.class);
            MyMath myMath = new MyMath(); // 创建 MyMath 类的实例
            Object invoke = addMethod.invoke(myMath, 1, 2); // 传递 MyMath 类的实例
            System.out.println(invoke); // 3
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

9. 使用Java的动态代理实现一个简单的日志记录功能。

题目描述:创建一个接口Operation,包含一个方法execute(String message)。实现该接口的类OperationImpl。使用动态代理为OperationImpl添加日志记录功能,即在执行execute方法前后打印日志。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Operation {
    void execute(String message);
}

class OperationImpl implements Operation {
    @Override
    public void execute(String message) {
        System.out.println("执行操作:" + message);
    }
}

class LoggingHandler implements InvocationHandler {
    private Object target;

    public LoggingHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始执行方法:" + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("方法执行结束:" + method.getName());
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        Operation operation = new OperationImpl();
        Operation proxyInstance = (Operation) Proxy.newProxyInstance(
                Operation.class.getClassLoader(),   // operation.getClass().getInterfaces(),
                new Class[]{Operation.class},       // operation.getClass().getInterfaces(),
                new LoggingHandler(operation)
        );

        proxyInstance.execute("Hello, World!");

        //开始执行方法:execute
        //执行操作:Hello, World!
        //方法执行结束:execute
    }
}

10. 使用Java的动态代理实现一个简单的权限校验功能。

题目描述:创建一个接口UserService,包含一个方法login(String username, String password)。实现该接口的类UserServiceImpl。使用动态代理为UserServiceImpl添加权限校验功能,即只有当用户名为"admin"且密码为"123456"时,才允许执行login方法。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface UserService {
    boolean login(String username, String password);
}

class UserServiceImpl implements UserService {
    @Override
    public boolean login(String username, String password) {
        System.out.println(username + " 登录成功!");
        return true;
    }
}

class AuthHandler implements InvocationHandler {
    private Object target;

    public AuthHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("login")) {
            String username = (String) args[0];
            String password = (String) args[1];
            if ("admin".equals(username) && "123456".equals(password)) {
                return method.invoke(target, args);
            } else {
                System.out.println("权限校验失败,用户名或密码错误!");
                return false;
            }
        }
        return method.invoke(target, args);
    }
}

public class Main {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserService proxyInstance = (UserService) Proxy.newProxyInstance(
                UserService.class.getClassLoader(),
                new Class[]{UserService.class},
                new AuthHandler(userService)
        );

        proxyInstance.login("admin", "123456"); // 权限校验通过,执行login方法
        //输出: admin 登录成功!
        
        
        proxyInstance.login("user", "123456"); // 权限校验失败
        //输出: 权限校验失败,用户名或密码错误!
        
    }
}

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

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

相关文章

算法学习笔记:贪心算法

贪心算法&#xff08;又称贪婪算法&#xff09;是指&#xff0c;在对问题求解时&#xff0c;总是做出当前看来是最好的选择&#xff0c;就能得到问题的答案。 虽然贪心算法不是对所有问题都能得到整体最优解&#xff0c;但对范围相当广的许多问题它能产生整体最优解。在一些情况…

电机线电流与转差率曲线[进行中...]

1.电机T型等效电路模型 1.1 Python代码 - 考虑转差率为负 import numpy as np import matplotlib.pyplot as plt # 设置已知参数值 rm 11.421 lm 553.9e-3 r2 7.553 l2 42.90e-3 freq_in 50# 设置频率值范围和步长 s np.linspace(-0.05, 0.05, 1000) im 380/(rm(lml2)…

PyQt弹出式抽屉窗口

代码 from enum import Enum import sys from PyQt5.Qt import *class PopupOrientation(Enum):LEFT 0TOP 1RIGHT 2BOTTOM 3class PopupMaskDialogBase(QDialog):"""带有蒙版的对话框基类"""def __init__(self, parentNone):super().__init…

FedProto:跨异构客户端的联邦原型学习(论文阅读)

题目&#xff1a;FedProto: Federated Prototype Learning across Heterogeneous Clients 网址&#xff1a;http://arxiv.org/abs/2105.00243 摘要 在联邦学习(FL)中&#xff0c;当客户端知识在梯度空间中聚集时&#xff0c;客户端间的异构性通常会影响优化的收敛和泛化性能。…

携手AI人才 共赢智算未来丨誉天人工智能AI大模型首期班火热报名中

在数字化浪潮汹涌澎湃的今天&#xff0c;人工智能已成为推动社会进步与产业升级的关键力量。 回顾人工智能历史&#xff0c;自1956年诞生以来&#xff0c;历经三次发展热潮和两次低谷期。五十年代符号主义和逻辑推理的出现标志着人工智能的诞生&#xff0c;引发第一次发展浪潮&…

自动驾驶AVM环视算法–全景和标定全功能算法实现和exe测试demo

参考&#xff1a;全景和标定全功能算法实现和exe测试demo-金书世界 1、测试环境 opencv310vs2022 2、使用的编程语言 c和c 3、测试的demo的获取 更新&#xff1a;测试的exe程序&#xff0c;无需解压码就可以体验算法测试效果 百度网盘&#xff1a; 链接&#xff1a;http…

开发一个自己的chrom插件

开发一个自己的chrom插件 一、创建一个文件夹 二、配置文件manifest.json 创建名字为&#xff1a;manifest.json的配置文件&#xff0c;模板如下&#xff1a; {"manifest_version": 3,"name": "Hello World Extension","version": …

Go 语言 UUID 库 google/uuid 源码解析:UUID version7 的实现

google/uuid 库地址 建议阅读内容 在阅读此篇文章之前&#xff0c;建议先了解 UUIDv1 的构成、UUIDv4 的 API 以及掌握位运算。 了解 UUIDv1 的构成可以参考Go 语言 UUID 库 google/uuid 源码解析&#xff1a;UUID version1 的实现 或 RFC 9562。 了解 UUIDv4 的 API 可以看…

【数据结构】非线性表----树详解

树是一种非线性结构&#xff0c;它是由**n&#xff08;n>0&#xff09;**个有限结点组成一个具有层次关系的集合。具有层次关系则说明它的结构不再是线性表那样一对一&#xff0c;而是一对多的关系&#xff1b;随着层数的增加&#xff0c;每一层的元素个数也在不断变化&…

算法——双指针(day3)

611.有效三角形的个数 611. 有效三角形的个数 - 力扣&#xff08;LeetCode&#xff09; 题目解析&#xff1a; 三角形的判定很简单&#xff0c;任意两边之和大于第三边即可。按照正常情况&#xff0c;我们得判断3次才可以确认是否构成三角形。 因为c在本来就是最大的情况下与…

安全测试必学神器 --BurpSuite 安装及使用实操

BurpSuite是一款功能强大的集成化安全测试工具&#xff0c;专门用于攻击和测试Web应用程序的安全性。适合安全测试、渗透测试和开发人员使用。本篇文章基于BurpSuite安装及常用实操做详解&#xff0c;如果你是一名安全测试初学者&#xff0c;会大有收获&#xff01; 一、BurpS…

C++ Qt 登录界面 Login

效果: 核心代码: #include "simpleapp.h" #include "ui_simpleapp.h" #include <QMessageBox>SimpleApp::SimpleApp(QWidget *parent): QMainWindow(parent), ui(new Ui::SimpleApp) {ui->setupUi(this); }SimpleApp::~SimpleApp() {delete ui; …

ROS、pix4、gazebo、qgc仿真ubuntu20.04

一、ubuntu、ros安装教程比较多&#xff0c;此文章不做详细讲解。该文章基于ubuntu20.04系统。 pix4参考地址&#xff1a;https://docs.px4.io/main/zh/index.html 二、安装pix4 1. git clone https://github.com/PX4/PX4-Autopilot.git --recursive 2. bash ./PX4-Autopilot…

MQTT服务端EMQX开源版安装和客户端MQTTX介绍

一、EMQX是什么 EMQX 是一款开源的大规模分布式 MQTT 消息服务器&#xff0c;功能丰富&#xff0c;专为物联网和实时通信应用而设计。EMQX 5.0 单集群支持 MQTT 并发连接数高达 1 亿条&#xff0c;单服务器的传输与处理吞吐量可达每秒百万级 MQTT 消息&#xff0c;同时保证毫秒…

C语言函数:编程世界的魔法钥匙(2)

引言 注&#xff1a;由于这部分内容比较抽象&#xff0c;而小编我又是一个刚刚进入编程世界的计算机小白&#xff0c;所以我的介绍可能会有点让人啼笑皆非。希望大家多多包涵&#xff01;万分感谢&#xff01;待到小编我学有所成&#xff0c;一定会把这块知识点重新介绍一遍&a…

Django前后端打通

跨域问题 【 0 】前言 ​ ​ 同源策略&#xff08;Same Origin Policy&#xff09;是浏览器安全策略的重要组成部分&#xff0c;它限制了来自不同源的网页之间的数据交互&#xff0c;以防止恶意攻击。当一个网页尝试执行与它的源&#xff08;即协议、域名和端口&#xff09…

Re:从零开始的C++世界——类和对象(下)

文章目录 前言1.再谈构造函数&#x1f34e;构造函数体赋值&#x1f34e;初始化列表&#x1f34e;特性&#x1f34c;特性一&#x1f34c;特性二&#x1f34c;特性三&#x1f34c;特性四&#x1f34c;特性五 &#x1f34e;explicit 关键字 2.static成员&#x1f34e;概念&#x1…

node.js动漫论坛-计算机毕业设计源码09947

摘 要 随着移动互联网的飞速发展&#xff0c;智能手机和移动互联网已经成为人们日常生活中不可或缺的一部分。在这样的背景下&#xff0c;微信小程序应运而生&#xff0c;凭借其无需下载安装、即用即走的特点&#xff0c;迅速成为连接用户与服务的桥梁。动漫作为一种深受年轻人…

《0基础》学习Python——第十六讲 __文件读写

<文件读写> 一、什么是文件读写 文件读写是指在Python程序中对文件进行读取和写入操作。通过文件读写&#xff0c;可以读取文件中的数据&#xff0c;或者向文件中写入数据。 Python提供了多种文件读写的方式&#xff0c;其中最常用的方式是使用open()函数打开一个文件&a…

ssrf复习(及ctfshow351-360)

1. SSRF 概述 服务器会根据用户提交的URL发送一个HTTP请求。使用用户指定的URL&#xff0c;Web应用可以获取图片或者文件资源等。典型的例子是百度识图功能。 如果没有对用户提交URL和远端服务器所返回的信息做合适的验证或过滤&#xff0c;就有可能存在“请求伪造"的缺陷…