⛳ Java 反射

news2024/12/22 17:01:20

目录

  • ⛳ Java 反射
    • 🎨 一、反射概述
      • **🎃 使用反射的前提条件: **
      • 🎲 类正常加载过程如下图:
      • 反射优缺点:
      • 🧸 Java反射机制提供的功能:
      • **🥅 反射主要API**
    • 🏭 二、反射的使用
      • 🎯 2.1、`class`类概述
      • 🎒 2.2、得到`Class`的实例
      • 📐 2.3、`Java`内置 9 大 `Class`实例
      • 📢 2.4、获取类中的构造器
      • ✨ 2.5、调用构造器创建对象
      • 🚜 2.6、获取类中的成员变量并调用(setAccessible)
      • 批量获取的方法:
      • 获取单个的方法:
      • 设置字段的值:
      • 👣 2.7、获取类中的成员方法并调用
      • 获取单个的方法:
      • 调用方法:
      • 🐾 2.8、反射方法的其他使用之通过反射运行配置文件内容
      • 🎈 2.9、反射方法的其它使用之越过泛型检查
    • 🎁 三、反射面试题

⛳ Java 反射

🎨 一、反射概述

Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助Reflection API获取任何类的内部信息,并直接操作任意对象的内部属性及方法。

image-20230816203125866

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

**🎃 使用反射的前提条件: **

​ 必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码),原因是要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。

🎲 类正常加载过程如下图:

image-20230816203604955

加载完类之后, 在堆内存的方法区中就产生了一个Class类型的对象( 一个类只有一个Class对象) , 这个对象就包含了完整的类的结构信息。 我们可以通过这个对象看到类的结构。 这个对象就像一面镜子, 透过这个镜子看到类的结构, 所以, 我们形象的称之为: 反射。

反射优缺点:

  • 优点
    1. 可以在运行程序的过程中,操作这些对象。
    2. 可以降低耦合度,提高程序的可扩展性。
  • 缺点
    1. 反射很强大,但是消耗性能。主要是为了做工具和框架使用的。

🧸 Java反射机制提供的功能:

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

🥅 反射主要API

    • java.lang.Class:代表一个类
    • java.lang.reflect.Method:代表类的方法
    • java.lang.reflect.Field:代表类的成员变量
    • java.lang.reflect.Constructor:代表类的构造器

🏭 二、反射的使用

🎯 2.1、class类概述

在Object类中定义了以下的方法,此方法将被所有子类继承:public final Class getClass()以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称。

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象(包括基本数据类型)。Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。

🎒 2.2、得到Class的实例

  1. Student stu = new User();Class clz = stu.getClass();:对象.getClass();得到对象的真实类型,因为在Object里,所以每个类都有该方法。
  2. Class<Student> clz = Student.class; : 数据类型.class(就是一份字节码)。
  3. Class.forName(String className); :根据一个类的全限定名来构建Class对象,Class<?> clz = Class.forName("com.gbx.Student");,这里泛型写<?>原因是此时class不知道类,因为传的是字符串。

代码示例:

 package com.gbx;
 public class Demo {
     public static void main(String[] args) {
         //obj.getClass()方式获取Class对象  
         Student stu1 = new Student();//new 产生一个Student对象,一个Class对象。
         Class stuClass = stu1.getClass();//获取Class对象
         
         //类名.class方式获取Class对象
         Class stuClass2 = Student.class;
         
         //Class.forName(String className)方式获取Class对象
         try {
             Class stuClass3 = Class.forName("com.gbx.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         }
 
     }
 }

注:这三种方法获取的都是同一个class对象,因为表示都是JVM中共同的一份字节码。

📐 2.3、Java内置 9 大 Class实例

​ 对于对象来说,可以直接使用obj.getClass()获取Class实例,但是基本数据类型,就没有类的权限定名,也没有getClass方法,那么如何使用Class类来表示基本数据类型的Class实例?

byte,short,int,long,char,float,double,boolean ,void关键字,上述8种类型和void关键字,都有class属性。例子如下:

  • 表示int的Class对象: Class clz = int.class;
  • 表示boolean的Class对象: boolean.class;
  • void: Class clz = void.class;
  • 表示数组的Class实例:String[] sArr1 = {“A”,“C”},Class clz = String[].class;//所有具有相同元素类型和维数的数组才共享同一份字节码(Class对象);

所有的数据类型都有class属性,表示都是Class对象。

注意:

int的包装类是Integer,那么 Integer.class == int.class ?结果是false,说明是两份字节码.

Integer 和 int 不是同一种数据类型,在八大基本数据类型的包装类中都有一个常量:TYPE,TYPE表示的是该包装类对应的基本数据类型的Class实例。例子如下:

  • Integer.TYPE—>int.class
  • Integer.TYPE == int.class;//YES
  • Integer.TYPE == Integer.class;//ERROR

📢 2.4、获取类中的构造器

  1. Class类获取构造器方法:Constructor类:表示类中构造器的类型,Constructor的实例就是某一个类中的某一个构造器。

  2. 批量获取的方法:

    • public Constructor<?>[] getConstructors():该方法只能获取当前Class所表示类的public修饰的构造器。

    • public Constructor<?>[] getDeclaredConstructors():获取当前Class所表示类的所有的构造器,和访问权限无关。

  3. 获取单个的方法:

    • public Constructor<T> getConstructor(Class<?>... parameterTypes) :获取当前Class所表示类中指定的一个public的构造器。
    • public Constructor getDeclaredConstructor(Class<?>... parameterTypes):获取当前Class所表示类的所有构造器中指定的一个构造器(可以是私有、受保护、默认、公有等)。

参数parameterTypes表示:构造器参数的Class类型。如:public Student(String name),Constructor c = clz.getConstructor(String.class)

代码示例:

package com.gbx;

public class Student {
     public Student() {
         System.out.println("---");
      }
      public Student(String name) {
          System.out.println(name);
      }
      public Student(String name, String school) {
          System.out.println(name + " " + school);
     }
 }
package com.gbx;

public class Constructors {
      public static void main(String[] args) throws Exception {
          //1.加载Class对象
          Class clazz = Class.forName("com.gbx.Student");
          //2.获取所有公有构造器
          System.out.println("****所有公有构造器****");
          Constructor[] conArray = clazz.getConstructors();
          for(Constructor c : conArray){
              System.out.println(c);
         }
         //3.获取所有构造器
         System.out.println("****所有的构造器****");
         conArray = clazz.getDeclaredConstructors();
         for(Constructor c : conArray){
             System.out.println(c);
         }
         //3.获取单个公有无参构造器
         System.out.println("****获取单个公有、无参的构造器****");
         Constructor con = clazz.getConstructor(null);
         System.out.println(con);
         //4.获取单个指定公有构造器
         System.out.println("****获取单个指定的公有构造器****");
         con = clazz.getConstructor(String.class);
         System.out.println(con);
         //5.获取单个指定构造器
         System.out.println("****获取单个指定的构造器****");
         con = clz.getDeclaredConstructor(String.class);
         System.out.println(con);
     }
 }

✨ 2.5、调用构造器创建对象

常用方法: public T newInstance(Object... initargs):使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例,参数initargs:表示调用构造器的实际参数,返回:返回创建的实例,T表示Class所表示类的类型。

提示:如果一个类中的构造器可以直接访问,同时没有参数,那么可以直接使用Class类中的newInstance方法创建对象,public Object newInstance():相当于 new 类名()

代码示例:

 public class newInstances {
      public static void main(String[] args) throws Exception {
          //1.加载Class对象
          Class<Student> clz = Student.class;
          //2.获取构造器
          Constructor<Student> c = clz.getConstructor(String.class);
          //3.调用构造器,创建对象
          Student stu1 =  c.newInstance("gbx");

          //直接访问不带参数的构造器可以直接使用Class的newInstance()方法
          Student stu2 =  clz.newInstance();
     }
 }

🚜 2.6、获取类中的成员变量并调用(setAccessible)

  1. 批量获取的方法:

    • Field[] getFields():获取当前Class所表示类的所有"公有字段"。
    • Field[] getDeclaredFields():获取当前Class所表示类的所有字段,包括:私有、受保护、默认、公有。
  2. 获取单个的方法:

    • public Field getField(String fieldName):获取当前Class所表示类的某个"公有的"字段。
    • public Field getDeclaredField(String fieldName):获取当前Class所表示类的某个字段(可以是私有的)。
  3. 设置字段的值:

    • public void set(Object obj,Object value) 参数 obj:要设置的字段所在的对象,value:要为字段设置的值

代码示例:

package com.gbx.field;

public class Student {
    public Student(){}
    //**字段**//
    public String name;
    protected int age;
    char sex;
    private String phoneNum;
}
package com.gbx.field;
import java.lang.reflect.Field;
public class Fields {
    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("com.gbx.field.Student");
        //2.获取字段
        System.out.println("***获取所有公有的字段***");
        Field[] fieldArray = stuClass.getFields();
        for(Field f : fieldArray){
            System.out.println(f);
        }
        System.out.println("***获取所有的字段(包括私有、受保护、默认)***");
        fieldArray = stuClass.getDeclaredFields();
        for(Field f : fieldArray){
            System.out.println(f);
        }
        System.out.println("***获取某个"公有的"字段并设置字段值***");
        Field f = stuClass.getField("name");
        System.out.println(f);
        System.out.println("***获取私有字段并设置字段值***");
        f = stuClass.getDeclaredField("phoneNum");
        System.out.println(f);

        //获取构造器,调用构造器获取一个对象
        Object obj = stuClass.getConstructor().newInstance();//产生Student对象,相当于Student stu = new Student();
        //为字段设置值
        f.set(obj, "张三");//为Student对象中的name属性赋值,相当于stu.name = "张三"
        //检验
        Student stu = (Student)obj;
        System.out.println("姓名:" + stu.name);    
        f.setAccessible(true);//Student类中的成员变量phoneNum为private,故必须解除“phoneNum”私有限定
        f.set(obj, "12345678900");
        System.out.println("电话:" + stu.phoneNum);        
    }
}

输出:

***获取所有公有的字段***
public java.lang.String com.gbx.field.Student.name
***获取所有的字段(包括私有、受保护、默认的)***
public java.lang.String com.gbx.field.Student.name
protected int com.gbx.field.Student.age
char fanshe.com.gbx.Student.sex
private java.lang.String com.gbx.field.Student.phoneNum
***获取某个“公有的”字段并设置字段值***
public java.lang.String com.gbx.field.Student.name
姓名:张三
***获取私有字段并设置字段值***
private java.lang.String com.gbx.field.Student.phoneNum
电话:12345678900

注:Java反射机制提供的setAccessible()方法,传入true可以取消,Java的安全检查。

👣 2.7、获取类中的成员方法并调用

  1. **批量获取的方法: **

    • public Method[] getMethods():获取当前Class所表示类和继承过来的所有"公有"方法(包含了父类的方法也包含Object类)。
    • public Method[] getDeclaredMethods():获取当前Class所表示类的所有成员方法,包括私有的(不包括继承的,和访问权限无关)。
  2. 获取单个的方法:

    • public Method getMethod(String name,Class<?>... parameterTypes):获取当前Class所表示类的某个"公有"方法(包括继承的)。

    • public Method getDeclaredMethod(String methodName,Class<?>... parameterTypes):获取当前Class所表示类的某个成员方法(不包括继承的)。

      参数 methodName:方法名,Class ... parameterTypes:形参的Class类型对象

  3. 调用方法:

    • public Object invoke(Object obj,Object ... args) 参数 obj:要调用方法的对象,args:调用方法时所传递的实参

代码演示:

package com.gbx.method;
 
public class Student {
    //****成员方法****//
    public void show1(String s){
        System.out.println("调用公有的String参数的show1(): s = " + s);
    }
    protected void show2(){
        System.out.println("调用受保护的无参的show2()");
    }
    void show3(){
        System.out.println("调用默认的无参的show3()");
    }
    private String show4(int age){
        System.out.println("调用私有的且有返回值的int参数的show4(): age = " + age);
        return age;
    }
}
package com.gbx.method;
 
import java.lang.reflect.Method;
 
public class MethodClass {
    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("com.gbx.method.Student");
        //2.获取所有公有方法
        System.out.println("****获取所有”公有“方法****");
        Method[] methodArray = stuClass.getMethods();
        for(Method m : methodArray){
            System.out.println(m);
        }
        System.out.println("****获取所有本类方法,包括私有****");
        methodArray = stuClass.getDeclaredMethods();
        for(Method m : methodArray){
            System.out.println(m);
        }
        System.out.println("****获取公有的show1()方法****");
        Method m = stuClass.getMethod("show1", String.class);
        System.out.println(m);
                
        //实例化一个Student对象
        Object obj = stuClass.getConstructor().newInstance();
        //调用方法,相当于stu.show1("张三")
        m.invoke(obj, "张三");
        
        System.out.println("****获取私有的show4()方法****");
        m = stuClass.getDeclaredMethod("show4", int.class);
        System.out.println(m);
        m.setAccessible(true);//解除私有限定
        Object result = m.invoke(obj, 20);
        System.out.println("返回值:" + result);
        
    }
}

输入:

****获取所有”公有“方法****
public void com.gbx.method.Student.show1(java.lang.String)
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
****获取所有本类方法,包括私有****
public void com.gbx.method.Student.show1(java.lang.String)
private java.lang.String com.gbx.method.Student.show4(int)
protected void com.gbx.method.Student.show2()
void com.gbx.method.Student.show3()
****获取公有的show1()方法****
public void com.gbx.method.Student.show1(java.lang.String)
调用公有的String参数的show1(): s = 张三
****获取私有的show4()方法****
private java.lang.String com.gbx.method.Student.show4(int)
调用私有的且有返回值的int参数的show4(): age = 20
返回值:20

🐾 2.8、反射方法的其他使用之通过反射运行配置文件内容

Student类:

public class Student {
    public void show(){
        System.out.println("It is show()");
    }
}

配置文件以txt文件为例子(p.txt):

className = com.gbx.Student
methodName = show

代码示例:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
 
public class Demo {
    public static void main(String[] args) throws Exception {
        //通过反射获取Class对象
        Class stuClass = Class.forName(getValue("className"));//"com.gbx.Student"
        //2获取show()方法
        Method m = stuClass.getMethod(getValue("methodName"));//show
        //3.调用show()方法
        m.invoke(stuClass.getConstructor().newInstance());        
    }

    //此方法接收一个key,在配置文件中获取相应的value
    public static String getValue(String key) throws IOException{
        Properties p = new Properties();//获取配置文件的对象
        FileReader fr = new FileReader("p.txt");//获取字符输入流
        p.load(fr);//将流加载到配置文件对象中
        in.close();
        return p.getProperty(key);//返回根据key获取的value值
    }
}

优点:当我们升级这个系统时,不要Student类,而需要新写其他类时,这时只需要更改p.txt里的文件内容就可以了,代码不用改动。

🎈 2.9、反射方法的其它使用之越过泛型检查

泛型用在编译期,编译过后泛型擦除(消失),所以是可以通过反射越过泛型检查的。

例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?

代码示例:

import java.lang.reflect.Method;
import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) throws Exception{
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        //list.add(100);
        //获取ArrayList的Class对象,反向的调用add()方法,添加数据
        Class listClass = list.getClass(); //得到 list对象的字节码对象
        //获取add()方法
        Method m = listClass.getMethod("add", Object.class);
        //调用add()方法
        m.invoke(list, 100);
        //遍历集合
        for(Object obj : list){
            System.out.println(obj);
        }
    }
}

输出:

aaa
bbb
100

这样说明可以通过反射越过泛型检查,向String泛型的集合中添加一个Integer类型的值。

🎁 三、反射面试题

题目:如何在不改变String内存地址的情况下,改变String的内容

正常创建:

@Test
public void test3() {
    String s = new String("abc"); //堆里面产生s
    String s1 = s; //s1
    s = "123";
    String s2 = s;
    System.out.println(s1.hashCode() + " " + s2.hashCode() );
    System.out.println(s1 == s2);
}
/**
*   结果:
*		96354 48690
*		false
*/

图示:image-20230816211624614

通过反射操作String中的value属性:

@Test
public void test4() throws Exception {
    String s = new String("123"); //堆里面产生s
    String s1 = s; //s1
    Field vf = String.class.getDeclaredField("value");
    vf.setAccessible(true);
    char[] chars = {97, 98, 99};
    vf.set(s, chars);
    String s2 = s;

    System.out.println(s1.hashCode() + " " + s2.hashCode() );
    System.out.println(s1 == s2);
    
    /**
    *	结果:
    *		96354 96354
	*		true
    *
    */
}

图示:image-20230816211924957

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

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

相关文章

01.修改simvision字体大小

修改simvision字体大小 ①cd ~/.simvision ② ls 查看是否有Xdefaults文件 1.如果有&#xff0c;gedit/vim Xdefaults 打开文件&#xff0c;搜索SrcBrowser修改数字&#xff0c;默认12这里修改成25&#xff0c;还有WaveWindow、DesignBrowser等都能改&#xff0c;我全部都修改…

爬虫逆向实战(四)--猿人学第一题

一、数据接口分析 主页地址&#xff1a;猿人学第一题 1、抓包 当我们打开F12时会发现直接debugger了&#xff0c;是一个无限debugger&#xff0c;我们直接右键debugger那一行&#xff0c;然后选择“一律不再此处暂停”就可以了 通过抓包可以发现登录接口是api/match/1 2、…

一条提示词等同于多少个数据点?

数据点&#xff08;data points&#xff09;通常用于描述单个信息单位或观测值&#xff0c;在本文中&#xff0c;它被用来量化“提示词”方法相对于传统方法的效率和效果。文章比较了两种训练&#xff08;微调&#xff09;机器学习模型的方法&#xff1a;一种是使用提示 (promp…

python——案例23:创建一个按钮

案例23&#xff1a;创建一个按钮from tkinter import * def xinlabel():global xinsLabel(xin,text完成)s.pack() xinTk() blButton(xin,text下一步,commandxinlabel) bl.pack() xin.mainloop()

【golang】函数(func)正确使用姿势

函数不但可以用于封装代码、分割功能、解耦逻辑&#xff0c;还可以化身为普通的值&#xff0c;在其他函数间传递、赋予变量、做类型判断和转换等等&#xff0c;就像切片和字典的值那样。 而更深层次的含义就是&#xff1a;函数值可以由此成为能够被随意传播的独立逻辑组件&…

使用PyMuPDF库的PDF合并和分拆程序

PDF工具应用程序是一个使用wxPython和PyMuPDF库编写的简单工具&#xff0c;用于合并和分拆PDF文件。它提供了一个用户友好的图形界面&#xff0c;允许用户选择源文件夹和目标文件夹&#xff0c;并对PDF文件进行操作。 C:\pythoncode\blog\pdfmergandsplit.py 功能特点 选择文…

高速数据采集卡---AD采集FMC子卡模块产品资料下载

FMC152是一款基于VITA57.1标准的&#xff0c;实现2路14-bit、2GSPS/2.6GSPS/3GSPS AD采集FMC子卡模块。该模块可直接与FPGA载卡配合使用&#xff0c;板卡ADC器件采用ADI公司的AD9208芯片&#xff0c;与ADI公司的AD9689可以实现PIN脚兼容。该模块全功率模拟输入带宽&#xff08;…

【FAQ】安防监控视频云存储平台EasyNVR频繁离线的原因排查与解决

有用户反馈&#xff0c;在使用EasyNVR时会出现通道频繁离线的情况。针对该反馈我们立即进行了排查。 安防视频监控汇聚EasyNVR视频集中存储平台&#xff0c;是基于RTSP/Onvif协议的安防视频平台&#xff0c;可支持将接入的视频流进行全平台、全终端分发&#xff0c;分发的视频流…

(二)结构型模式:6、外观模式(Facade Pattern)(C++实例)

目录 1、外观模式&#xff08;Facade Pattern&#xff09;含义 2、外观模式的UML图学习 3、外观模式的应用场景 4、外观模式的优缺点 5、C实现外观模式的简单实例 1、外观模式&#xff08;Facade Pattern&#xff09;含义 外观模式&#xff08;Facade Pattern&#xff09;…

气象监测设备——分类与应用

气象监测设备多种多样&#xff0c;不同的应用场景选择适合的气象监测设备才能事半功倍。 在植保站中&#xff0c;可以 选择农林植保小气候气象站&#xff0c;它可以帮助植保站的工作人员完成气象监测工作&#xff0c;对天气环境进行预报预测&#xff0c;为植物的健康生长提供保…

Windows系统如何查看端口被占用程序和停止占用端口程序

windows系统如何查看端口被占用程序和停止占用端口程序&#xff0c;以及windows常用的网络命令详解 打开命令窗口 电脑右下方&#xff0c;搜索框&#xff0c;输入“cmd”,回车打开dos命令窗口 查看系统所有被占用的端口命令 netstat -ano 查看指定端口是否被占用命令 netst…

CS144 计算机网络 Lab1:Stream Reassembler

前言 上一篇博客中我们完成了 Lab0&#xff0c;使用双端队列实现了一个字节流类 ByteStream&#xff0c;可以向字节流中写入数据并按写入顺序读出数据。由于网络环境的变化&#xff0c;发送端滑动窗口内的数据包到达接收端时可能失序&#xff0c;所以接收端收到数据之后不能直…

Windows Server --- RDP远程桌面服务器激活和RD授权

RDP远程桌面服务器激活和RD授权 一、激活服务器二、设置RD授权 系统&#xff1a;Window server 2008 R2 服务&#xff1a;远程桌面服务 注&#xff1a;该方法适合该远程桌面服务器没网络状态下&#xff08;离线&#xff09;&#xff0c;激活服务器。 一、激活服务器 1.打开远…

Spring学习笔记之Bean的循环依赖问题

文章目录 什么是Bean的循环依赖singleton下的set注入产生的循环依赖prototype下的set注入产生的循环依赖singleton下的构造注入产生的循环依赖Spring解决循环循环的机理&#xff08;面试题&#xff09; 什么是Bean的循环依赖 A对象中有B属性。B对象中有A属性。这就是循环依赖。…

leetcode 1614.括号的最大嵌套深度

⭐️ 题目描述 &#x1f31f;leetcode链接&#xff1a;括号的最大嵌套深度 ps&#xff1a; 使用数据结构栈来存储 ( 在使用 maxDepth 变量记录栈顶 top 的最大值&#xff0c;当遇到 ) 时删除栈顶元素。举个例子 (1)((2))(((3)))&#xff0c;当遇到第一个 ( 时 top 1&#xff…

对dubbo的DubboReference.check的参数进行剖析

背景 在使用dubbo的时候&#xff0c;发现当消费者启动的时候&#xff0c;如果提供者没有启动&#xff0c;即使提供者后来启动了&#xff0c;消费者也调不通提供者提供的接口了。 注册中心使用都是nacos dubbo版本是3.0.4 例子 接口 public interface DemoService {String…

中期国际:外汇交易的利器:善用挂单技巧优化交易策略

在外汇交易中&#xff0c;挂单技巧是提高交易效率和灵活性的重要利器之一。善用限价单和止损单可以帮助交易者有效规避风险、控制入场点和出场点&#xff0c;从而提高交易效果。本文将介绍一些MT4挂单技巧&#xff0c;以帮助交易者优化交易策略&#xff0c;提高交易效率。 1. 了…

猿辅导设立“青少年科学探索基金”,鼓励天才少年投入科学研究

“少年智则国智&#xff0c;少年富则国富&#xff0c;少年强则国强。”国家发展离不开人才的培养。伴随我国进入高质量发展轨道&#xff0c;科学、人才、教育三位一体融合发展已经刻不容缓。我国基础学科人才紧缺成了不争的事实。目前&#xff0c;中国的GDP目前已是世界第二位&…

nginx创建和监听套接字分析

https://cloud.tencent.com/developer/article/1859856 简介 nginx作为一个web服务器&#xff0c;肯定是有listen套接字对外提供服务的&#xff0c;listen套接字是用于接收HTTP请求。 nginx监听套接字的创建是根据配置文件的内容来创建的&#xff0c;在nginx.conf文件中有…

视频音乐如何转换成mp3?教你超简单的转换方法

MP3文件通常比视频文件更小。因此&#xff0c;通过将音乐从视频中提取并转换为MP3格式&#xff0c;您可以更轻松地存储和传输它们。如果计划在手机或其他设备上存储音乐&#xff0c;转换为MP3格式可以帮助我们节省存储空间。而且&#xff0c;如果需要将音乐发送给朋友或上传到互…