Java反射(reflection)java很多框架的底层都需要用到反射,至于API使用的话,还算简单,主要是类加载过程和反射机制的一个底层机制要了解一下

本文主要是介绍Java反射(reflection)java很多框架的底层都需要用到反射,至于API使用的话,还算简单,主要是类加载过程和反射机制的一个底层机制要了解一下,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

十六、反射(reflection)

反射可以通过外部文件配置,在不修改源码的情况下来控制程序,符合设计模式中的OCP原则(开闭原则:不修改源码,扩容功能)。

1、反射机制

(1)基本介绍
  • 反射机制允许程序在执行期间借助Reflection API 获取任何类的内部信息(比如:成员变量,构造器,成员方法等)。并能操作对象的属性方法。在设计模式和框架地层都会涉及
  • 加载完类之后,在堆中产生一个Class对象(一个类只有一个Class对象),对象包含类的完整结构信息。通过这个对象可以看到类的结构。Class对象就像一面镜子,通过镜子看到类的结构。
(2) 反射机制原理图

在这里插入图片描述

(3)反射可完成功能
  • 运行时判断对象所属类
  • 运行时构造一个任意类的对象
  • 运行时得到一个类所具有的成员变量和方法
  • 运行时调用任意一个对象的成员变量和方法
  • 生产动态代理
(4) 反射相关类
1.java.lang.Class 代表一个类,Class对象表示某个类加载后在堆中的对象
2.java.lang.reflect.Method 代表类的方法,Method对象表示某个类的方法
3.java.lang.reflect.Field 代表类的成员变量,Filed对象表示某个类的成员变量
4.java.lang.reflect.Constructor 代表类的构造方法,Constructor对象表示构造器

举例:

public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {//1、使用Properties类读取配置信息Properties prop = new Properties();prop.load(new FileInputStream("src\\re.properties"));String classfullpath = prop.getProperty("classfullpath");String methodName = prop.getProperty("method");//2、使用反射机制//(1)加载类,返回class类型的对象clsClass cls = Class.forName(classfullpath);//(2)通过getInstance得到加载类的实例对象Object o = cls.newInstance();//(3)通过cls获得得到类的方法对象Method method1 = cls.getMethod(methodName);System.out.println("=====================");//(4)调用方法 传统方法为对象.方法(), 反射机制 方法.invoke(对象)method1.invoke(o);//java.lang.reflect.Field 代表类的成员变量,Field对象表示某个类的成员变量Field nameField = cls.getField("age");      //不能获取到私有的变量System.out.println(nameField.get(o));   //传统写法对象.成员变量, 反射: 成员变量对象.get(对象)//java.lang.constructor 代表类的构造方法,Constructor对象表示构造器Constructor constructor = cls.getConstructor();System.out.println(constructor);Constructor constructor2 = cls.getConstructor(String.class);System.out.println(constructor2);
}
(5)反射的优缺点
  • 优点:可以动态的创建和使用对象(框架底层核心),使用灵活,没有反射机制,框架技术就失去了底层支撑
  • 缺点:使用反射基本是解释执行,对执行速度有影响
  • 改进:关闭访问检查

举例:

public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {m1();       //传统方法m2();       //反射方法m3();       //反射优化}
//传统方法调用hi
public static void m1(){Cat cat = new Cat();long start = System.currentTimeMillis();for (int i = 0; i < 90000000; i++) {cat.hi();}long end = System.currentTimeMillis();System.out.println("传统方法调用hi耗时:"+(end-start));
}
//反射机制调用方法hi
public static void m2() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {Class cls = Class.forName("JavaEE.chapter17.Cat");Object o = cls.newInstance();Method hi = cls.getMethod("hi");long start = System.currentTimeMillis();for (int i = 0; i < 90000000; i++) {hi.invoke(o);}long end = System.currentTimeMillis();System.out.println("反射机制耗时:"+(end-start));
}//反射机制优化
public static void m3() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {Class cls = Class.forName("JavaEE.chapter17.Cat");Object o = cls.newInstance();Method hi = cls.getMethod("hi");hi.setAccessible(true);//在反射调用方法时,取消访问检查long start = System.currentTimeMillis();for (int i = 0; i < 90000000; i++) {hi.invoke(o);}long end = System.currentTimeMillis();System.out.println("反射优化机制耗时:"+(end-start));
}

2、class类

(1)基本介绍
  • class类也是类,因此继承了Object类
  • Class类对象不是new出来的,而是系统创建出来的
  • 对于某个类的class类对象,在内存中只有一份,因为类只加载一次
  • 每个类的实例都会记住自己是由哪个Class实例所生成的
  • 通过Class对象可以完整的得到一个类的完整结构
  • class对象存在堆当中
  • 类的字节码二进制数据,放在方法区当中,也称为类的元数据

举例:

public static void main(String[] args) throws ClassNotFoundException {//1、class也是类,继承了Object类//Class//2、Class对象不是new出来的,而是系统创建的//(1)传统new对象/*ClassLoader 类public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}*/
//        Cat cat = new Cat();//(2)反射方式/*ClassLoader 类, 仍然是通过ClassLoader 类加载Cat 类的Class 对象public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}*///3、对于某个类的class对象,在内存中只有一份,类只加载一次Class cls1 = Class.forName("JavaEE.chapter17.Cat");Class cls2 = Class.forName("JavaEE.chapter17.Cat");System.out.println(cls1.hashCode());System.out.println(cls2.hashCode());}
(2)获取Class类对象的方式
  1. Class.forName()获取

    • 前提:已知一个类的全类名,并且该类在类路径下,可以通过Class的静态方法forName获取,

    • 应用场景:多用于配置文件,读取类的全路径,加载类

    • 举例:

      //1、加载类的情况下,使用getclass,多用于配置文件的时候
      String classAllPath = "JavaEE.chapter17.Cat";       //通过读取文件配置获取
      Class<?> cls1 = Class.forName(classAllPath);
      System.out.println(cls1);
      
  2. 类.Class()获取

    • 前提:已经知道具体的类,通过类的Class进行获取,该方式最为安全可靠,程序性能最高

    • 应用场景:多用于参数的传递,比如通过反射获取到对应的构造器对象

    • 举例:

      //2、类名.Class,加载类的情况下,用于参数传递
      Class<?> cls2 = Cat.class;
      System.out.println(cls2);
      
  3. 对象.getClass()获取

    • 前提:已经知道具体的对象实例

    • 应用场景:有对象实例

    • 举例:

       //3、对象.getClass,运行的情况下,已经有对象实例,通过创建好的对象,获取Class对象
      Cat cat = new Cat();
      Class cls3 = cat.getClass();
      System.out.println(cls3);
      
  4. 类加载ClassLoader的loadClass进行获取

    • 举例:

      //4、通过类加载器【4种】获取类的Class对象
      //(1)先得到类加载器
      ClassLoader classLoader = cat.getClass().getClassLoader();
      //(2)通过类加载器获取到Class对象
      Class cls4 = classLoader.loadClass(classAllPath);
      System.out.println(cls4);
      
  5. 基本数据类型.class进行获取

    • 举例:

      //5、基本数据类型(int,char,boolean,float,double,byte,long,short),可以通过.class方式获取到class类对象
      Class<Integer> intClass = int.class;
      Class<Character> charClass = char.class;
      System.out.println(intClass);
      System.out.println(charClass);
      
  6. 基本数据类型的包装类.TYPE进行获取

    • 举例:

      //6、基本数据类型的包装类,可以通过.TYPE得到Class对象
      Class cls5 = Integer.TYPE;
      System.out.println(cls5);	 
      
(3)哪些类型有Class对象
  1. 外部类、成员内部类、静态内部类、局部内部类、匿名内部类
  2. interface:接口
  3. 数组
  4. enum:枚举
  5. annotation:注解
  6. 基本数据类型
  7. void

举例:

Class<String> cls1 = String.class;//外部类
Class<Serializable> cls2 = Serializable.class;//接口
Class<Integer[]> cls3 = Integer[].class;//数组
Class<float[][]> cls4 = float[][].class;//二维数组
Class<Deprecated> cls5 = Deprecated.class;//注解
//枚举
Class<Thread.State> cls6 = Thread.State.class;
Class<Long> cls7 = long.class;//基本数据类型
Class<Void> cls8 = void.class;//void数据类型
Class<Class> cls9 = Class.class;//class自己

3、类加载

(1)基本介绍

反射机制是Java实现动态语言的关键,也是通过反射实现类的动态加载

  1. 静态加载:**编译的时候加载相关的类,如果没有该类就会报错。**依赖性太强
  2. 动态加载:**运行的时候加载相关的类,如果运行的时候没有使用到这个类,即便不存在这个类,也不会报错。**降低了依赖性
(2)类加载的时机
  1. 当创建对象时(new),进行静态加载
  2. 当子类被加载时,父类也加载,进行静态加载
  3. 调用类的静态成员时,进行静态加载
  4. 通过反射时,进行动态加载
(3)类加载过程图

在这里插入图片描述

(4)类加载各阶段任务

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 加载阶段:

    • JVM在该阶段主要目的是将字节码从不同的数据源(可能是class文件,也可以是jar包,或者是网络等等)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
  • 连接阶段:

    • 验证 verification

      1. 目的是保证Class文件中的字节流包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全
      2. 包括:文件格式验证(是否以魔数 oxcafebabe开头)、元数据验证、字节码验证和符号引用验证
      3. 可以考虑使用-Xverify:none,参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间
    • 准备 preparation

      1. JVM在该阶段为静态变量,分配内存并默认初始化(对应的数据类型的默认初始化值,如0,0L,null,false等)。这些变量使用的内存将在方法区中进行分配

      举例:

      //类加载阶段中连接阶段,属性如何准备
      //1、n1为实例属性,为静态变量,在准备阶段,不会分配内存
      //2、n2为静态变量,分配内存n2是默认初始化为0,而不是20
      //3、n3是static final是常量,与静态变量不一样,一旦赋值不会更改 n3 = 30
      public int n1 = 10;
      public static int n2 = 20;
      public final static int n3 = 30;
      
    • 解析 resolution

      1. 虚拟机将常量池内的符号引用替换为直接引用的过程
  • 初始化阶段: Initialization

    1. 到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行()方法的过程
    2. ()方法是由编译器按照在源文件中出现的顺序,依次自动收集类中的所有的静态变量的赋值动作和静态代码块中的语句进行合并的
    3. 虚拟机会保证一个类的()方法在多线程环境中被正确的加锁、同步,如果多个线程同时初始化一个类,那么只有一个线程回去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()完毕。

    举例:

    public class ClassLoad03 {public static void main(String[] args) {System.out.println(B.num);      //直接使用类的静态属性,也会执行类加载过程/** 1、加载B类,并生产B的class对象* 2、连接 num = 0* 初始化阶段* 依次收集类中的所有静态变量的赋值动作和静态代码块中的语句,并对其进行合并*clinit(){System.out.println("B 静态代码块被执行");num = 300;      //被后面的语句合并,这里不起作用,最后输出100num = 100;}* */new B();//加断点,追溯源码看是否有同步机制/** protected Class<?> loadClass(String name, boolean resolve)*throws ClassNotFoundException{//正因为有这个机制,才能保证某个类在内存中, 只有一份Class 对象synchronized (getClassLoadingLock(name)) {//....}}*** */}
    }class B{static {System.out.println("B 静态代码块被执行");num = 300;}static int num = 100;
    //    public B(){
    //        System.out.println("B 的构造器被执行");
    //    }
    }
    

4、反射获取类的结构信息

(1)java.lang.Class 类
getName:获取全类名
getSimpleNmae:获取简单类名
getFields:获取所有public修饰的属性,包含本类以及父类的
getDeclaredFields:获取本类中的所有属性
getMethods:获取所有public修饰的方法,包含本类以及父类的
getDeclaredMethods:获取本类的所有方法
getConstructors:获取本类所有public修饰的构造器
getDeclaredConstructors:获取本类的所有构造器
getPackage:以Package形式返回包信息
getSuperClass:以Class形式返回父类信息
getInterfaces:以Class[]返回接口信息
getAnnotations:以Annotation[]形式返回注解信息
(2)java.lang.reflect.Field 类
getModifiers:以int形式返回修饰符
【默认修饰符伟0public1private2protected4static8final16】
getType:以Class形式返回类型
getName:返回属性名
(3)java.lang.reflect.Method 类
getModifiers:以int形式返回修饰符
【默认修饰符伟0,public为1,private为2,protected为4,static为8,final为16】
getReturnType:以Class形式获取返回类型
getName:返回方法名
getParameterTypes:以Class[]类型返回参数类型数组
(4)java.lang.reflect.Constructor 类
getModifiers:以int形式返回修饰符
【默认修饰符伟0,public为1,private为2,protected为4,static为8,final为16】
getName:返回构造器名
getParameterTypes:以Class[]类型返回参数类型数组

举例:

public class ReflectionUtils {public static void main(String[] args) {}//第一组API@Testpublic void api_01() throws ClassNotFoundException {//得到Class对象Class<?> personCls = Class.forName("JavaEE.chapter17.Person");//getName:获取全类名System.out.println(personCls.getName());//getSimpleNmae:获取简单类名System.out.println(personCls.getSimpleName());//getFields:获取所有public修饰的属性,包含本类以及父类的Field[] fields = personCls.getFields();for (Field field : fields) {System.out.println("本类与父类的属性"+field.getName());}//getDeclaredFields:获取本类中的所有属性Field[] declaredields = personCls.getDeclaredFields();for (Field field : declaredields) {System.out.println("本类的所有属性"+field.getName());}//getMethods:获取所有public修饰的方法,包含本类以及父类的Method[] methods = personCls.getMethods();for (Method method : methods) {System.out.println("本类与父类的方法"+method.getName());}//getDeclaredMethods:获取本类的所有方法Method[] declaredMethods = personCls.getDeclaredMethods();for (Method method : declaredMethods) {System.out.println("本类的方法"+method.getName());}//getConstructors:获取本类所有public修饰的构造器Constructor<?>[] constructors = personCls.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println("本类所有public构造器"+constructor);}//getDeclaredConstructors:获取本类的所有构造器Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();for (Constructor<?> constructor : declaredConstructors) {System.out.println("本类的所有构造器"+constructor);}//getPackage:以Package形式返回包信息System.out.println(personCls.getPackage());//getSuperClass:以Class形式返回父类信息Class<?> superclass = personCls.getSuperclass();System.out.println("父类的class对象"+superclass);//getInterfaces:以Class[]返回接口信息Class<?>[] interfaces = personCls.getInterfaces();for (Class<?> anInterface : interfaces) {System.out.println("接口信息"+anInterface);}//getAnnotations:以Annotation[]形式返回注解信息Annotation[] annotations = personCls.getAnnotations();for (Annotation annotation : annotations) {System.out.println("注解信息="+annotation);}}@Test//第二组APIpublic void API_02() throws ClassNotFoundException {//得到Class对象Class<?>personCls = Class.forName("JavaEE.chapter17.Person");//getDeclaredFields:获取本类中所有属性//规定说明: 默认修饰符是0 , public 是1 ,private 是2 ,protected 是4 , static 是8 ,final 是16Field[] declaredFields = personCls.getDeclaredFields();for (Field declaredField : declaredFields) {System.out.println("本类中所有属性=" + declaredField.getName()+ " 该属性的修饰符值=" + declaredField.getModifiers()+ " 该属性的类型=" + declaredField.getType());}//getDeclaredMethods:获取本类中所有方法Method[] declaredMethods = personCls.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println("本类中所有方法=" + declaredMethod.getName()+ " 该方法的访问修饰符值=" + declaredMethod.getModifiers()+ " 该方法返回类型" + declaredMethod.getReturnType());//输出当前这个方法的形参数组情况Class<?>[] parameterTypes = declaredMethod.getParameterTypes();for (Class<?> parameterType : parameterTypes) {System.out.println("该方法的形参类型=" + parameterType);}}//getDeclaredConstructors:获取本类中所有构造器Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println("====================");System.out.println("本类中所有构造器=" + declaredConstructor.getName());//只是输出名Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();for (Class<?> parameterType : parameterTypes) {System.out.println("该构造器的形参类型=" + parameterType);}}}
}class A{public String hobby;public A(){}public void hi(){}
}interface IA{}interface IB{}@Deprecated
class Person extends A implements IA,IB{//四种不同类型修饰符的属性public String name;protected int age;String job;private double sal;public Person(){}private Person(String name){}public Person(String name, int age, String job, double sal) {}//四种不同类型修饰符的方法public void m1() {}protected void m2(){}void m3(){}private void m4(){}

5、反射创建对象

  • 方式一:调用类中的public修饰的无参构造器
  • 方式二:调用类中的指定构造器
  • Class类的相关方法
    • newInstance:调用类中的午餐构造器,获取对应的类的信息
    • getConstructor(class...class):根据参数列表获取对应的public构造器对象
    • getDeclaredConstructor(class....class):根据参数列表,获取对应的所有构造器对象
  • Constructor类的相关方法
    • setAccessible:爆破
    • newInstance(object..obj):调用构造器

举例:

public class ReflectCreateInstance {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//1、先得到Class对象Class<?> userCls = Class.forName("JavaEE.chapter17.User");//2、通过public的无参构造器Object o = userCls.getDeclaredConstructor().newInstance();System.out.println(o);//3、通过public的有参构造器//3.1先得到构造器Constructor<?> constructor = userCls.getConstructor(String.class);//3.2然后用构造器创建实例Object user1 = constructor.newInstance("user1");System.out.println(user1);//4、通过非公有的构造器创建实例//4.1先得到构造器Constructor<?> constructor2 = userCls.getDeclaredConstructor(int.class,String.class);//私有构造器,得先爆破,才能使用,暴破【暴力破解】, 使用反射可以访问private 构造器/方法/属性, 反射面前,都是纸老虎constructor2.setAccessible(true);//4.3然后用构造器创建实例Object user2 = constructor2.newInstance(200,"user2");System.out.println(user2);}
}class User { //User 类private int age = 10;private String name = "名字";public User() {//无参public}public User(String name) {//public 的有参构造器this.name = name;}private User(int age, String name) {//private 有参构造器this.age = age;this.name = name;}public String toString() {return "User [age=" + age + ", name=" + name + "]";}
}

6、反射访问类中的成员

(1)访问属性
  1. 根据属性名获取Field对象

    Field f = clazz对象.getDeclaredField(属性名);
    
  2. 爆破

     f.setAccessible(true);
    
  3. 访问

    f.set(o,) //o表示对象
    syso(f.get(o)) //o表示对象
    
  4. 如果是静态属性,则set和get中的参数o,可以写成null

举例:

public class ReflectAccessProprty {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {//1. 得到Student 类对应的Class 对象Class<?> stuClass = Class.forName("JavaEE.chapter17.Student");//2. 创建对象Object o = stuClass.newInstance();//o 的运行类型就是StudentSystem.out.println(o.getClass());//Student//3. 使用反射得到age 属性对象Field age = stuClass.getField("age");age.set(o,88); //反射操作属性System.out.println(age.get(o));//4. 使用反射操作name 属性Field name = stuClass.getDeclaredField("name");//对name 进行暴破, 可以操作private 属性name.setAccessible(true);name.set(o, "小明");System.out.println(name.get(o));name.set(null,"小红");//因为name 是static 属性,因此o 也可以写出nullSystem.out.println(name.get(o));System.out.println(name.get(null));//获取属性值, 要求name 是static}
}
class Student {//类public int age;private static String name;public Student() {//构造器}public String toString() {return "Student [age=" + age + ", name=" + name + "]";}
}
(2)访问方法
  1. 根据方法名和参数列表获取Method方法

    Method m = clazz.getDeclaredMethod(方法名,XX.class)//得到本类的所有方法
    
  2. 获取对象

    Object o = clazz.newInstance();
    
  3. 爆破

     m.setAccessible(true);
    
  4. 访问

    Object returnValue = m.invoke(o,实参列表);
    
  5. 注意:如果是静态放哪发,则invoke的参数o,可以写成null

举例:

public class ReflecAccessMethod {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {//1. 得到Boss 类对应的Class 对象Class<?> bossCls = Class.forName("JavaEE.chapter17.Boss");//2. 创建对象Object o = bossCls.newInstance();//3. 调用public 的hi 方法//Method hi = bossCls.getMethod("hi", String.class);//3.1 得到hi 方法对象Method hi = bossCls.getDeclaredMethod("hi", String.class);//3.2调用方法hi.invoke(o,"大怪物");//4. 调用private static 方法//4.1 得到say 方法对象Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);//4.2 因为say 方法是private, 所以需要暴破,原理和前面讲的构造器和属性一样say.setAccessible(true);System.out.println(say.invoke(o, 100, "张三", '男'));//4.3 因为say 方法是static 的,还可以这样调用,可以传入nullSystem.out.println(say.invoke(null, 200, "李四", '女'));//5. 在反射中,如果方法有返回值,统一返回Object , 但是他运行类型和方法定义的返回类型一致Object reVal = say.invoke(null, 300, "王五", '男');System.out.println("reVal 的运行类型=" + reVal.getClass());//StringSystem.out.println(reVal);//在演示一个返回的案例Method m1 = bossCls.getDeclaredMethod("m1");Object reVal2 = m1.invoke(o);System.out.println("reVal2 的运行类型=" + reVal2.getClass());//Monster}
}
class Monster {}
class Boss {//类public int age;private static String name;public Boss() {//构造器}public Monster m1() {return new Monster();}private static String say(int n, String s, char c) {//静态方法return n + " " + s + " " + c;}public void hi(String s) {//普通public 方法System.out.println("hi " + s);}
}

, 但是他运行类型和方法定义的返回类型一致
Object reVal = say.invoke(null, 300, “王五”, ‘男’);
System.out.println(“reVal 的运行类型=” + reVal.getClass());//String
System.out.println(reVal);

    //在演示一个返回的案例Method m1 = bossCls.getDeclaredMethod("m1");Object reVal2 = m1.invoke(o);System.out.println("reVal2 的运行类型=" + reVal2.getClass());//Monster
}

}
class Monster {}
class Boss {//类
public int age;
private static String name;
public Boss() {//构造器
}
public Monster m1() {
return new Monster();
}
private static String say(int n, String s, char c) {//静态方法
return n + " " + s + " " + c;
}
public void hi(String s) {//普通public 方法
System.out.println("hi " + s);
}
}


这篇关于Java反射(reflection)java很多框架的底层都需要用到反射,至于API使用的话,还算简单,主要是类加载过程和反射机制的一个底层机制要了解一下的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/922586

相关文章

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

JavaWeb-WebSocket浏览器服务器双向通信方式

《JavaWeb-WebSocket浏览器服务器双向通信方式》文章介绍了WebSocket协议的工作原理和应用场景,包括与HTTP的对比,接着,详细介绍了如何在Java中使用WebSocket,包括配... 目录一、概述二、入门2.1 POM依赖2.2 编写配置类2.3 编写WebSocket服务2.4 浏

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

修改若依框架Token的过期时间问题

《修改若依框架Token的过期时间问题》本文介绍了如何修改若依框架中Token的过期时间,通过修改`application.yml`文件中的配置来实现,默认单位为分钟,希望此经验对大家有所帮助,也欢迎... 目录修改若依框架Token的过期时间修改Token的过期时间关闭Token的过期时js间总结修改若依

Java文件与Base64之间的转化方式

《Java文件与Base64之间的转化方式》这篇文章介绍了如何使用Java将文件(如图片、视频)转换为Base64编码,以及如何将Base64编码转换回文件,通过提供具体的工具类实现,作者希望帮助读者... 目录Java文件与Base64之间的转化1、文件转Base64工具类2、Base64转文件工具类3、

java获取图片的大小、宽度、高度方式

《java获取图片的大小、宽度、高度方式》文章介绍了如何将File对象转换为MultipartFile对象的过程,并分享了个人经验,希望能为读者提供参考... 目China编程录Java获取图片的大小、宽度、高度File对象(该对象里面是图片)MultipartFile对象(该对象里面是图片)总结java获取图片

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

Java通过反射获取方法参数名的方式小结

《Java通过反射获取方法参数名的方式小结》这篇文章主要为大家详细介绍了Java如何通过反射获取方法参数名的方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、前言2、解决方式方式2.1: 添加编译参数配置 -parameters方式2.2: 使用Spring的内部工具类 -

Java如何获取视频文件的视频时长

《Java如何获取视频文件的视频时长》文章介绍了如何使用Java获取视频文件的视频时长,包括导入maven依赖和代码案例,同时,也讨论了在运行过程中遇到的SLF4J加载问题,并给出了解决方案... 目录Java获取视频文件的视频时长1、导入maven依赖2、代码案例3、SLF4J: Failed to lo

如何使用Spring boot的@Transactional进行事务管理

《如何使用Springboot的@Transactional进行事务管理》这篇文章介绍了SpringBoot中使用@Transactional注解进行声明式事务管理的详细信息,包括基本用法、核心配置... 目录一、前置条件二、基本用法1. 在方法上添加注解2. 在类上添加注解三、核心配置参数1. 传播行为(