【Java基础】深入理解反射、反射的应用(工厂模式、代理模式)

news2025/1/12 18:14:00

文章目录

    • 1. Java反射机制是什么?
      • 1.2 Java反射例子
    • 2. Java反射机制中获取Class的三种方式及区别?
    • 3. Java反射机制的应用场景有哪些?
      • 3.1. 优化静态工厂模式(解耦)
        • 3.1.1 优化前(工厂类和产品类耦合)
        • 3.1.2 反射优化后(工厂类和产品类解耦合)
        • 3.1.3 利用反射再优化(配置文件配置全类名映射)
      • 3.2 代理模式中的动态代理实现
      • 3.2.1 静态代理
      • 3.2.2 动态代理
        • 3.2.2.1 JDK动态代理(反射构造代理对象)
        • 3.2.2.2 cglib动态代理(没有用反射)

1. Java反射机制是什么?

Java 反射机制是指在运行时动态地获取和操作类的信息、调用对象的方法和访问对象的属性的能力。通过反射,可以在程序运行时分析和修改类的结构、行为和状态。

Java 反射机制提供了以下功能:

  1. 获取类的信息:可以获取类的名称、修饰符、父类、实现的接口等。
  2. 创建对象:可以通过反射实例化对象,即使不知道具体类名。
  3. 调用方法:可以通过反射获取类的方法,并调用这些方法。
  4. 访问和修改字段:可以通过反射获取和设置类的字段值。
  5. 动态代理:可以使用反射动态生成代理对象,实现 AOP(面向切面编程)等功能。
  6. 操作数组:可以通过反射创建、访问和修改数组对象。
  7. 注解处理:可以通过反射获取类、方法、字段上的注解,并进行相应的处理。

通过反射机制,可以在运行时动态地操作类和对象,解耦了编译时的依赖关系,提供了更大的灵活性和扩展性。但是需要注意,由于反射涉及到动态生成和修改类的结构,可能会影响性能,并且需要额外的权限。

1.2 Java反射例子

正射:
一般情况下,我们使用某个类,都会知道这个类,以及要用它来做什么,可以直接通过new实例化创建对象,然后使用这个对象对类进行操作,这个就属于正射~
Student类

		public class Student {
		    private int id;
		
		    public void setId(int id) {
		        this.id = id;
		    }
		    public int getId() {
		        return this.id;
		    }
		}
		Student student = new Student();
        student.setId(1);
        System.out.println("正射获取ID :"+student.getId());
        
		//输出:正射获取ID :1

正射很好理解,就不多说了,现在来讲讲反射,同样可以创建对象,调用对象的方法,等等正射能做的事,通过反射都能做
反射:
反射则是一开始并不知道要初始化的是什么类无法使用new来实例化创建对象,主要是通过JDK提供的反射API来实现,在运行时才知道要操作的是什么类,并且可以获取到类的完整构造以及调用对应的方法,这就是反射~

		//1、通过 Class.forName 方法获取 Srudent类的 Class 对象
        Class<?> clz = Class.forName("Reflect.Student");  
		//2、通过 getConstructor 方法获取类的无参构造方法
      //  Constructor<?> constructor = clz.getConstructor();//可省略
        //3、通过 newInstance 方法实例化对象
       // Object stu = constructor.newInstance();//可省略
       Student stu = (Student) clz.newInstance();//(代替2-3)直接通过字节码对象Class.newInstance()实例化对象
		//4、通过 getMethod 方法获取类的方法信息("setId", int.class) setId为方法名  int.class为方法参数类型
        Method setId = clz.getMethod("setId", int.class);
        //5、通过 invoke 方法调用该方法
        setId.invoke(stu,3);
       //也可以直接通过对象stu   调用Student类的方法
        Method getId = clz.getMethod("getId");
       
        System.out.println("反射获取ID :"+getId.invoke(stu));
        
		//输出:反射获取ID :3

总结就是:
上述例子反射的调用过程,可以看到获取一个类的反射对象,主要过程为:

  1. 获取类的Class实例对象
  2. 根据Class实例对象获取Constructor对象
  3. 再根据Constructor对象的newInstance方法获取到类的反射对象

获取到类的反射对象后,就可以对类进行操作了~ 例如,上述示例中对类的方法进行调用过程为:

  1. 根据Class实例对象获取到类的Method对象

  2. 再根据Method对象的invoke方法调用到具体类的方法

上面示例反向调用过程中我们是通过Class.forName("类的全局定名")这种方式来获取到类的Class实例对象,除了这种,常用的还有其他两种

2. Java反射机制中获取Class的三种方式及区别?

获取类的java.lang.Class实例对象,常见的三种方式分别为:

  1. 通过MyClass.class获取,这里的MyClass指具体类~~
  2. 通过Class.forName("类的全局定名")获取,全局定名为包名+类名
  3. 通过new MyClass().getClass()获取,这里的MyClass指具体类~
		Class<?> clz = Class.forName("Reflect.Student");		  //全类名获取
        Class<Student> clz = Student.class;                      //类.class获取
        Class<? extends Student> clz = new Student().getClass();//newClass().getClass()获取

区别在于:

  • 通过MyClass.class获取,JVM会使用ClassLoader类加载器将类加载到内存中,但并不会做任何类的初始化工作,返回java.lang.Class对象
  • 通过Class.forName(“类的全局定名”)获取,同样,类会被JVM加载到内存中,并且会进行类的静态初始化工作,返回java.lang.Class对象
  • 通过newMyClass().getClass()获取,这种方式使用了new进行实例化操作,因此静态初始化和非静态初始化工作都会进行,getClass方法属于顶级Object类中的方法,任何子类对象都可以调用,哪个子类调用,就返回那个子类的java.lang.Class对象

具体体现可参考链接:吾日三省贾斯汀----->Java–反射机制原理、几种Class获取方式及应用场景

总结:

  • MyClass.class不会做任何类的初始化工作
  • Class.forName会进行类的静态初始化工作
  • new MyClass().getClass静态初始化非静态初始化工作都会进行
  • 使用这三种方式任意一种最终在JVM加载到内存中都会是内存地址相同的(jvm类加载的双亲委派机制,类只会被加载一次)

3. Java反射机制的应用场景有哪些?

3.1. 优化静态工厂模式(解耦)

3.1.1 优化前(工厂类和产品类耦合)

简单工厂示例:

步骤1:创建抽象产品类

public interface Product {
      void show();
}

步骤2:创建具体产品类:

public class ProductA implements Product {
    @Override
    public void show() {
        System.out.println("生产了产品A");
    }
}
public class ProductB implements Product {
    @Override
    public void show() {
        System.out.println("生产了产品B");
    }
}

public class ProductC implements Product {
    @Override
    public void show() {
        System.out.println("生产了产品C");
    }
}

步骤3:创建简单工厂类

/**
 * 静态工厂
 */
public class Product_factory {
	 /**
     * todo 常规工厂 (工厂和产品耦合)
     */
    public static Product createProduct(String productName) throws Exception {
        Product product = null;
        if ("A".equals(productName)) {
            product = new ProductA();

        }else if("B".equals(productName)){
            product = new ProductB();

        }else if("C".equals(productName)){
            product = new ProductC();

        }else{
            throw new Exception("没有该产品");
        }
        return product;
    }
}

步骤4:调用简单工厂类

    public static void main(String[] args) throws Exception {

        //通过工厂生产对象A
        Product A = Product_factory.createProduct("A");
        //调用A对象的方法
        A.show();

        Product B = Product_factory.createProduct("B");
        B.show();

        Product C = Product_factory.createProduct("C");
        C.show();

    }

输出:

A产品被生产了
B产品被生产了
B产品被生产了

优化前的弊端
每增加一个接口的子类,必须修改工厂类的逻辑

例如我需要加一个产品C,就必须要修改工厂,追加产品C的生产过程

public class ProductD implements Product{
    @Override
    public void show() {
        System.out.println("D产品被生产了");
    }
}

在这里插入图片描述
这样就违背了开闭原则(在追加新产品时,应该不要修改原来已有的代码,而是在原来的基础上扩展)

这个时候反射就可以克服这个弊端(将产品和工厂解耦)

3.1.2 反射优化后(工厂类和产品类解耦合)

优化后

优化工厂类

    /**
     * todo 反射工厂(通过产品全类名来创建产品) (工厂和产品解耦合)
     */
    public static Product createProductReflect(String Full_product_name ) {
        Product product = null;
        try {
      	  //根据产品类的全类名反射生成产品类的class字节对象
            Class<?> aClass = Class.forName(Full_product_name);
            //通过产品类的字节码对象  创建真实对象
            product = (Product) aClass.newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        return product;
    }

测试类:

        //全类名反射通过工厂生产产品
        Product A = Product_factory.createProductReflect("factory.Simple_factory.ProductA");
        A.show();

        Product B = Product_factory.createProductReflect("factory.Simple_factory.ProductB");
        B.show();

        Product C = Product_factory.createProductReflect("factory.Simple_factory.ProductC");
        B.show();

输出:

A产品被生产了
B产品被生产了
B产品被生产了

这样如果要追加产品D,只需要新增产品D,无需修改工厂,只需要在需要D产品时,通过对工厂引入产品的全类名就可以生产产品类对象
新增产品D

public class ProductD implements Product{
    @Override
    public void show() {
        System.out.println("D产品被生产了");
    }
}

通过对工厂引入产品的全类名生产产品类对象

  Product D = Product_factory.createProductReflect("factory.Simple_factory.ProductD");
  D.show();

输出:

D产品被生产了

使用Java反射机制优化简单工厂模式后,可以看到,不论具体产品类更新多频繁,都不需要再修改工厂类,从而解决了普通简单工厂模式操作成本高和系统复杂性高的问题~

3.1.3 利用反射再优化(配置文件配置全类名映射)

简单工厂模式的工厂类采用Java反射机制进行优化后,此时的仍然存在这样一个问题,子类的全局定名(包名+类名)是写死的,但是实际上开发者在写代码时是很难提前预知所有的子类的全局定名(包名+类名)的,因此需要进行二次优化~

优化思路:

通过配置文件方式,统一定义类名对应全局定名(包名+类名),将配置文件存放到资源目录下,程序运行时通过ClassLoader类加载器动态获取到配置文件中定义的子类的全局定名~

再次优化步骤2:配置类名对应全局定名(包名+类名)
创建属性配置文件Product.properties

//产品抽象类Product相关子类的全局定名(包名+类名)定义
//key            value
ProductA = com.justin.java.lang.ProductA
ProductB = com.justin.java.lang.ProductB
ProductC = com.justin.java.lang.ProductC

再次优化步骤3:修改调用工厂类

public class FactoryTest {
    @Test
    public void test() throws IOException {
        ClassLoader classLoader = this.getClass().getClassLoader();
        Properties prop = new Properties();
        prop.load(classLoader.getResourceAsStream("Product.properties"));

        String className = "";
        try {
            className = prop.getProperty("ProductA");
            Product productA = Factory.getInstance(className);
            productA.show();
        } catch (NullPointerException e) {
            System.out.println("没有A这款产品,无法生产~");
        }

        try {
            className = prop.getProperty("ProductB");
            Product productA = Factory.getInstance(className);
            productA.show();
        } catch (NullPointerException e) {
            System.out.println("没有B这款产品,无法生产~");
        }

        try {
            className = prop.getProperty("ProductC");
            Product productA = Factory.getInstance(className);
            productA.show();
        } catch (NullPointerException e) {
            System.out.println("没有C这款产品,无法生产~");
        }
    }
}

输出:

生产了产品A
生产了产品B
生产了产品C

相比较优化前,将产品类对应的全类名,放在了配置文件里面,在生产产品时,根据以下配置将产品类对应的全类名从配置文件里面取到,然后再根据全类名反射构建产品对象:

		ClassLoader classLoader = this.getClass().getClassLoader();
        Properties prop = new Properties();
        prop.load(classLoader.getResourceAsStream("Product.properties"));

classLoader.getResourceAsStream("Product.properties") 是通过类加载器来获取资源文件 “Product.properties” 的输入流。getResourceAsStream() 方法是 java.lang.ClassLoader 类的一个方法,它可以根据给定的路径从类路径中查找并返回对应的资源文件的输入流。

prop.load() 是 java.util.Properties 类的一个方法,用于将输入流中的数据加载到属性对象中。在这行代码中,prop 是一个属性对象,通过调用 prop.load() 方法,并将类加载器获取到的资源文件输入流作为参数,实现将资源文件的内容加载到属性对象中。

综上所述,这行代码的作用是使用类加载器加载名为 "Product.properties" 的资源文件,并将其读取为属性对象。这样可以方便地获取和操作资源文件中定义的属性值。

3.2 代理模式中的动态代理实现

代理模式是什么?
代理(Proxy)模式是一种设计模式,通过代理对象来访问目标对象,还可以在不修改目标对象的情况下,对代理对象进行拓展,增强目标对象的功能~

3.2.1 静态代理

静态代理是在编译时就已经确定代理类和被代理类的关系,代理类和被代理类实现同一个接口或继承同一个父类。代理类持有对被代理对象的引用(代理对象),在调用目标方法之前或之后执行一些额外的逻辑。静态代理的代码在编译时就已经确定,因此代理类需要为每一个被代理类编写一个对应的代理类。这种方式的好处是简单直观,容易理解和掌握,但是当被代理的类较多时,会产生大量的重复代码。

也就是一个被代理类对应着一个代理类,但是当被代理的类较多时,会产生大量的重复代码。
在这里插入图片描述

其实静态代理通俗的来说,就是被代理类和代理类共同实现一个接口,并且实现接口的方法,代理类通过声明被代理类的实例化对象(代理对象)(也就是编译时就已经确定代理类和被代理类的关系),通过调用和被代理类一样的方法(这就是为什么要共同实现一个接口的方法),并且在代理类方法中通过代理对象调用被代理类的方法(可以在被代理类的方法做出增代理类设置的增强),从而达到代理或代理增强的效果

3.2.2 动态代理

动态代理是在运行时生成代理类,不需要对每个被代理类都编写一个对应的代理类。它通过使用 Java 的反射机制,在运行时动态地创建代理类和代理对象代理类实现一个统一的接口或继承一个父类,并持有一个 InvocationHandler 对象作为其调用处理器。在调用目标方法时,代理类会将方法调用转发给 InvocationHandler 处理器,并可以在调用之前或之后添加额外的逻辑,动态代理的优势在于可以更加灵活地动态创建代理对象,减少了重复的代理类编写,适用于代理类较多或需要动态管理代理对象的场景。

3.2.2.1 JDK动态代理(反射构造代理对象)

JDK 原生动态代理,主要利用了JDK API的
java.lang.reflect.Proxyjava.lang.relfect.InnvocationHandler 这两个类来实现~

通过java.lang.reflect.Proxy代理类的newProxyInstance方法,传递3个参数,分别是:

  1. 目标对象的加载器 通过Object.getClass().getClassLoader方式获取
  2. 目标对象的实现接口类型 通过Object.getClass().getInterfaces()方式获取
  3. InnvocationHandler事件处理器 通过new实例化对象并重写invoke方法方式获取

步骤:

  1. 创建被代理类的接口,让被代理类实现接口方法
  2. 创建代理类,通过构造方法将被代理类对象注入到代理类
  3. 通过设置3个参数(1、目标对象的加载器,2、目标对象的实现接口类型,3、InnvocationHandler事件处理器(增强目标对象的方法))
  4. 编写一个返回代理对象的方法:通过Proxy代理类的newProxyInstance方法将三个参数传入,返回生成的代理对象。
  5. 在测试类中将被代理类对象通过代理类有参构造引入,然后生成代理对象,执行增强的方法

举例:
产品类接口Product_interface

/**
 * 被代理类接口
 */
public interface Product_interface {
    void sell();
}

产品类Product

/**
 * @Description TODO 被代理类
 **/
public class Product implements Product_interface{
    @Override
    public void sell() {
        System.out.println("生产了一台iphone 15 pro max");
    }
}

代理类ProductProxy

/**
 * @Description TODO 动态代理类
 **/
public class ProductProxy {
    private  Object  target;//被代理的对象

    public ProductProxy (Object target){//通过构造方法引入被代理对象
        this.target = target;
    }

    /**
     * 利用JDK API获取到代理对象
     * @return
     */
    public Object getProxyInstance(){
        //目标对象的加载器
        ClassLoader classLoader = target.getClass().getClassLoader();//反射

        //目标对象的实现接口类型
        Class<?>[] interfaces = target.getClass().getInterfaces();//反射

        //InvocationHandler事件处理器实例对象
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //前置增强
               System.out.println("提前接到消息的黄牛正在蹲抢中.............");
                // 执行目标对象方法
                Object value = method.invoke(target, args);
                //后置增强
                System.out.println("无货......................");
                return null;//若无返回值  就直接返回   若需要返回一个返回值  就如实返回
            }
        };
        //传入3个参数,创建代理类的实例对象,并返回
        return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
    }
}

测试类ProductBuyTest

    public static void main(String[] args) {

        Product_interface product = new Product();//创建被代理类对象

        ProductProxy productProxy = new ProductProxy(product);//将被代理类的对象交给代理类

        Product_interface proxy = (Product_interface) productProxy.getProxyInstance();//由代理类生成代理对象

        proxy.sell();//通过代理对象执行被代理类的增强方法

    }

输出:

提前接到消息的黄牛正在蹲抢中.............
富士康生产了一台iphone 15 pro max
无货......................

JDK原生动态代理中,获取代理示例对象过程中,获取目标对象的类加载器,通过target.getClass().getClassLoader获取到目标对象的类加载器target.getClass()方式获取目标对象的Class实例对象使用的就是Java反射机制来实现的~

3.2.2.2 cglib动态代理(没有用反射)

CGLIB(Code Generation Library)是一个基于ASM(一个Java字节码操作框架)的代码生成库,它可以在运行时动态地生成目标类的子类,从而实现对目标类的代理

使用时需引入cglib依赖

      <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

产品类Product

/**
 *  被代理类
 */
public class Product {

    public void sell() {
        System.out.println("富士康生产了一台iphone 15 pro max");
    }
}

代理类CglibProxy

/**
 * @Description: 代理类  用来获取代理对象
 */
public class CglibProxy implements MethodInterceptor {

    private  Object  target;//被代理的对象

    public CglibProxy (Object target){//通过构造方法引入被代理对象
        this.target = target;
    }

    /**
     * 用于构造代理对象
     * @return
     */
    public Object getProxyObject() {
        //创建Enhancer对象,类似于JDK代理中的Proxy类
        Enhancer enhancer = new Enhancer();
        //设置父类的字节码对象。指定父类
        enhancer.setSuperclass(target.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建代理对象
        Object proxyObject =  enhancer.create();
        return proxyObject;
    }
    /*
     * 拦截器
     *       	1.目标对象的方法调用
     *       	2.行为增强
     *      参数 o: cglib 动态生成的代理类的实例
     *          method:实体类所调用的都被代理的方法的引用
     *          objects 参数列表
     *          methodProxy:生成的代理类对方法的代理引用
     * */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //前置增强
        System.out.println("提前接到消息的黄牛正在蹲抢中.............");
        //要调用目标对象的方法
        Object obj = method.invoke(target, objects);
        //后置增强
        System.out.println("无货......................");
        return null;
    }
}

输出:

提前接到消息的黄牛正在蹲抢中.............
富士康生产了一台iphone 15 pro max
无货......................

实现步骤:

  1. 引入cglib依赖
  2. 创建被代理类
  3. 创建cglib代理类并且实现MethodInterceptor 接口,重写intercept方法
  4. 通过构造方法注入被代理类对象给代理对象赋值
  5. 编写一个返回代理对象的方法:
    1、创建Enhancer对象,
    2、给Enhancer对象设置父类(被代理类)的字节码对象,
    3、给Enhancer对象设置回调函数,
    4、创建代理对象 返回代理对象
  6. 在intercept方法里面调用目标对象的方法(增强)
  7. 在测试类中将被代理类对象通过代理类有参构造引入,然后生成代理对象,执行增强的方法

参考来自:
Java–反射机制原理、几种Class获取方式及应用场景—作者:吾日三省贾斯汀

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

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

相关文章

【仿写spring之ioc篇】一、预期目标以及项目结构介绍

前言 最近系统的学习了一下spring的源码&#xff0c;准备简单仿写一下spring&#xff0c;目前是仿写ioc篇&#xff0c;在ioc篇中将完成整套的bean的生命周期&#xff0c;当然是简单的实现&#xff0c;不会像spring真正源码那样做非常系统性的校验以及接口设计。 预期目标 将…

关于“VS2022无法打开头文件<graphics.h>” 以及编译时 “没有与参数列表匹配的重载函数实例”俩个问题的解决思路

前言&#xff1a; 今天无聊没什么事干&#xff0c;突然看见一条视频梦回20年前杀马特横行的年代&#xff0c;炫酷而又土嗨的灯光闪烁&#xff0c;我又想了想之前写扫雷小游戏的时候&#xff0c;有的人写的游戏界面非常的炫酷&#xff0c;各种颜色都有&#xff0c;抱着没事没事干…

c#事件(event)

概述&#xff1a; C#中的事件是一种特殊的委托&#xff0c;它用于实现观察者模式&#xff0c;允许对象在特定事件发生时通知其他对象。 以下是使用C#事件的示例&#xff1a; 首先&#xff0c;定义一个包含事件的类&#xff1a; public class EventPublisher {// 声明一个事…

向新NEW · 数智赋能新未来 | 2023TechWorld 绿盟科技智慧安全大会圆满召开

9月1日&#xff0c;以“向新NEW数智赋能新未来”为主题的2023TechWorld绿盟科技智慧安全大会在北京如约启幕。站在新十年开篇之际&#xff0c;TechWorld技术嘉年华正式更名TechWorld智慧安全大会&#xff0c;名字全新升级背后反映着广大用户对绿盟科技始终坚持的技术战略——“…

WEBGL(3):鼠标动态绘制点

1 实现思路 绘制单个点鼠标事件监听点击事件将点推送到数组中绘制数组中所有点 2 实现代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge&…

MySQL 数据库常用命令大全(完整版)

文章目录 1. MySQL命令2. MySQL基础命令3. MySQL命令简介4. MySQL常用命令4.1 MySQL准备篇4.1.1 启动和停止MySQL服务4.1.2 修改MySQL账户密码4.1.3 MySQL的登陆和退出4.1.4 查看MySQL版本 4.2 DDL篇&#xff08;数据定义&#xff09;4.2.1 查询数据库4.2.2 创建数据库4.2.3 使…

手机怎么压缩图片?压缩方法看这些

手机怎么压缩图片&#xff1f;在现代社会中&#xff0c;手机已经成为我们日常生活中不可或缺的一部分。我们使用手机拍照、上传照片和分享照片&#xff0c;但是在分享照片之前&#xff0c;我们经常需要将其压缩&#xff0c;以便在互联网上更轻松地共享。下面这篇文章就给大家介…

下行抢占指示 DCI format 2_1

这部分R17和R15基本内容一样&#xff0c;只是有写细节描述略有区别&#xff0c;这里就以R17版本的协议看下downlinkPreemption&#xff0c;即DCI format 2_1有关内容。 R15支持eMBB和URLLC服务。 由于URLLC业务是优先级较高的业务&#xff0c;当无线资源不足时&#xff0c;已经…

如何把pdf文件合并?分享最新pdf合并方法

在所有文档格式中&#xff0c;pdf应该是最常用的&#xff0c;像产品介绍、商务合同、法律文书等等&#xff0c;这些都是pdf格式的。有时候出于工作需要&#xff0c;我们要把两份或者多份pdf文件合并在一起&#xff0c;那么问题来了&#xff0c;如何把pdf文件合并呢?小编最近发…

【勘误】基于多目标粒子群算法的微电网优化调度【风光、储能、柴油、燃气、电网交互】

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 这是一篇代码勘误&#xff0c;该程序复现文献《基于多目标粒子群算法的微电网优化调度》&#xff0c;代码实现了多目标优化调度模型——考虑微电网系统运行成本和环境保护成本的并网模式下微电网多目标优化调…

【NCRE 二级Java语言程序设计01】全国计算机等级考试初识

目录 前言一、认识全国计算机等级考试1.官方的自我介绍2.省级和全国级的区别3.考试内容 二、NCRE正确入口三、官方重要资源分布1.大纲教材2.相关下载3.试题选登4.常见问题 总结 前言 &#x1f4dc; 本专栏主要是分享自己备考全国计算机二级Java语言程序设计所学心得体会、所搜集…

SpringBoot自定义工具类—基于定时器完成文件清理功能

直接复制粘贴既可&#xff01;&#xff01; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.io.File; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneOff…

【云原生进阶之PaaS中间件】第一章Redis-2.5缓存持久化

1 Redis持久化 1.1 Redis持久化分类 Redis 中的数据都是保存在内存中的&#xff0c;当Redis服务重启后&#xff0c;内存中的数据都会丢失&#xff0c;所以需要将内存中的数据保存到磁盘上&#xff0c;方便系统故障时&#xff0c;从磁盘上的备份数据恢复到内存中。 Redis 中的持…

PMP考试难度大吗?该如何备考?

PMP&#xff08;Project Management Professional)&#xff09;认证考试是全球范围内最重要、最权威的项目管理行业认证之一。但是&#xff0c;很多人对PMP考试的难度心存疑虑。在这篇文章中&#xff0c;我们将讨论PMP考试的难度&#xff0c;并提供一些备考建议。 首先&#x…

python“魂牵”京东商品历史价格数据接口(含代码示例)

要通过京东的API获取商品详情历史价格数据&#xff0c;您可以使用京东开放平台提供的接口来实现。以下是一种使用Java编程语言实现的示例&#xff0c;展示如何通过京东开放平台API获取商品详情历史价格数据&#xff1a; 首先&#xff0c;确保您已注册成为京东开放平台的开发者…

一款windows的终端神奇,类似mac的iTem2

终于找到了一款windows的终端神奇。类似mac的iTem2 来&#xff0c;上神器 cmder cmder是一款windows的命令行工具&#xff0c;就是我们的linux的终端&#xff0c;用起来和linux的命令一样。所以我们今天要做的是安装并配置cmder ![在这里插入图片描述](https://img-blog.csdni…

前端需要学习哪些技术?

前端工程师岗位缺口一直很大&#xff0c;符合岗位要求的人越来越少&#xff0c;所以学习前端的同学要注意&#xff0c;一定要把技能学到扎实&#xff0c;做有含金量的项目&#xff0c;这样在找工作的时候展现更大的优势。 缺人才&#xff0c;又薪资高&#xff0c;那么怎样才能…

赞奇科技参与华为云828 B2B企业节,云工作站入选精选产品解决方案

8月27日&#xff0c;由华为云携手上万家伙伴共同发起的第二届 828 B2B 企业节拉开帷幕&#xff0c;围绕五大系列活动&#xff0c;为万千中小企业带来精细化商机对接。 聚焦行业数字化所需最优产品&#xff0c;举办超1000场供需对接会&#xff0c;遍及20多个省100多个城市&…

企业架构LNMP学习笔记3

服务器基本环境配置&#xff1a; 1、安装虚拟机&#xff0c;centos7.9 操作系统&#xff1b; 2、网络配置&#xff1b; 3、机器名FQDN设置&#xff1b; 4、DNS解析设置&#xff0c;本地hosts设置&#xff1b; 5、配置yum源环境&#xff1b; 6、vim安装配置&#xff1b; …

windows笔记本远程连接如何打开任务管理器?

参考素材&#xff1a; https://jingyan.baidu.com/article/8275fc86a97f5207a03cf6cd.html https://www.anyviewer.cn/how-to/ctrl-alt-delete-remote-desktop-6540.html 网上查了很多方法&#xff0c;都说ctrlaltend可以解决这个问题。 但是笔记本键盘上没有end键。 继续查了一…