【Java进阶篇】第八章 反射与注解

news2024/9/25 9:37:23

文章目录

  • 一、反射机制概述
    • 1、作用
    • 2、相关类
  • 二、反射
    • 1、获取Class的三种方式
    • 2、通过反射机制实例化对象
    • 3、forName方法的另一个应用
    • 4、获取类路径下文件的绝对路径
    • 5、资源绑定器ResourceBundle
    • 6、类加载器
  • 三、反射与反编译
    • 1、获取Field
    • 2、反编译Field
    • 3、通过反射机制访问对象的属性
    • 4、可变长参数☀☀☀
    • 5、反射与反编译Method
    • 6、用反射机制调用对象的方法
    • 7、反射与反编译Constructor
    • 8、用反射机制调用构造方法
    • 9、获取某类的父类以及实现了哪些接口
  • 四、注解
    • 1、概述
    • 2、JDK的内置注解
    • 3、注解中定义属性
    • 4、反射注解

一、反射机制概述

1、作用

通过Java中的反射机制,可以操作字节码文件,即读和修改字节码文件.class

2、相关类

java.lang.reflect.*

细分为:

  • java.lang.Class 代表字节码文件
  • java.lang.reflect.Method 代表字节码文件中的方法字节码
  • java.lang.reflect.Constructor 代表字节码文件中的构造方法字节码
  • java.lang.reflect.Field 代表字节码文件中的属性字节码

举例

二、反射

1、获取Class的三种方式

☀获取Class的第一种方式:

java.lang.Class类中的静态方法forName(),方法的参数是一个字符串,字符串需要的是一个完整的类名,即必须包含包名,如java.lang.String

try{
    Class c1 = Class.forName("java.lang.String");
    Class c = Class.forName("java.util.Date")
}catch(ClassNotFoundException e){
    e.printStackTrace();
}

c1代表String.class文件=,另外ClassNotFoundException异常的父类是ReflectOperationException,再父就是Exception

☀获取Class的第二种方式:

Java中任何一个对象都有一个方法getClass()(即Object中的方法)

String s = "abc";
Class c2 = s.getClass();
//和第一中方式做对比
//true,即对象内存地址一样
System.out.println(c1 == c2);

内存图
字节码装载到JVM的时候,只装载一份

☀获取Class的第三种方式:

Java中任何一种类型,包括基本数据类型,都有.class属性

Class c3 = String.class;
Class d = Date.class;
Class i = int.class;
//true
System.out.println(c2 == c3);

2、通过反射机制实例化对象

Class c = Class.forName("java.util.Date");
Object obj = c.newInstance();

newInstance()方法已过时,会调用对应类的无参构造,完成对象的创建。若这时手写了有参而未加无参构造,则这时异常:java.lang.InstantiationException

以上单独看有些鸡肋,搭配properties配置文件则很灵活:

反射机制的灵活性

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;
import java.util.Properties;

public class ReflectTest {
    public static void main(String[] args) {
        try {
            FileReader reader = new FileReader("thread/classInfo.properties");
            Properties pro = new Properties();
            pro.load(reader);
            String className = pro.getProperty("className");
            Class c = Class.forName(className);
            Object o = c.newInstance();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

    }
}

注意:IDEA中的当前目录是项目的根目录

以上代码的核心部分是:
code
如此,创建、批量创建Java对象的时候,就不用改代码,只需修改配置文件就能实例化不同的对象。符合OCP原则,即对扩展开放,对修改关闭。

3、forName方法的另一个应用

若只希望某个类的静态代码块执行,不希望其他程序执行,则可用forName(“完整类名”),这个方法的执行会导致类加载,而类加载的时候,静态代码块执行。

public class MyClass{

...
static{
	System.out.println("静态代码块执行");
}

}

------
Class.forName("com.java.reflectMyclass");

4、获取类路径下文件的绝对路径

以上下代码使用相对路径(IDEA当前路径为project根路径),可移植性差。

FileReader reader = new FileReader("thread/classInfo.properties");

由此:

类路径:凡是在src下的都是类路径下,src是类的根路径

String path = Thread.currentThread().getContextClassLoader().getResource("classInfo.properties").getPath();


  • getContextClassLoader()是线程对象的方法,获取当前线程的类加载器对象
  • getResource()方法是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源,故该方法传参为src下的文件名字符串

由此,拿到了一个文件的绝对路径,最重要的是这是一个随移植环境而变得绝对路径

还可以直接以流得形式返回:

InputStream  reader2  = Thread.currentThread().getContextClassLoader().getResourceAsStream("classInfo.properties");

5、资源绑定器ResourceBundle

资源绑定器用于获取属性配置文件中的内容,此时属性配置文件xx.properties必须放在类路径下。

ResourceBundle bundle = ResourceBundle.getBundle("classInfo");

String className = bundle.getString("className");

注意点:

  • 资源绑定器只能绑定xx.properties文件,注意文件扩展名
  • 这个文件必须在类路径下
  • getBundle方法传参不写文件后缀名properties

6、类加载器

ClassLoader,专门负责加载类的一个命令/工具,JDK中自带了三个类加载器:

  • 启动类加载器:专门加载…jdk\jre\lib\rt.jar
  • 扩展类加载器:专门加载…jdk\lib\ext*.jar
  • 应用类加载器:专门加载classpath中的jar包(class文件)

代码执行前,会将需要的类全部加载到JVM中,先通过启动类加载器,有没加载到,通过扩展类加载器,还没直到,到应用类加载器。

Java中,为了保证类加载的安全,使用了双亲委派机制,优先从启动类加载器中加载(父),父无法加载,再从扩展加载器中加载(母)。否则,若应用类加载器中也植入了一个String类,则出现了安全问题。

三、反射与反编译

1、获取Field

import java.lang.reflect.*;

public class ReflectTest2 {
    public static void main(String[] args) {
        try {
            Class studentClass = Class.forName("Student");
            Field[] fields  = studentClass.getFields(); //获取类中的Field
            System.out.println(fields.length);
            System.out.println(fields[0]); //1
            String fieldName = fields[0].getName(); //只有一个public修饰的no

            Field[] fields1 = studentClass.getDeclaredFields(); //获取所有Field
            for(Field field:fields1){
                System.out.println("属性名:" + field.getName());
                Class fieldType = field.getType(); //获取属性的类型
                String typeStr = fieldType.getName();
                //获取属性的修饰符,返回int,每个数字为修饰符的代号。修饰符可能有多个,如private finally
                int i = field.getModifiers();
                //类Modifier中有静态方法static String toString(int mod)可返回修饰符字符串
                String modifiersStr = Modifier.toString(i);
                System.out.println("修饰符为:" + modifiersStr);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class Student{
    /**
     * 定义4个Field,用不同的访问控制权限修饰符
     */
    public int no;
    private String name;
    protected int age;
    boolean sex;
}

运行结果:
run
另外,类Class中也有getName方法:

Class studentClass = Class.forName("Student");
//come.java.Student
String className = studentClass.getName();

//Student
String simpleName = studentClass.getSimpleName();

2、反编译Field

import java.lang.reflect.*;
import java.lang.reflect.Modifier;

public class ReflectTest3 {
    public static void main(String[] args) {
        try {
            //创建StringBuilder用来拼接字符串
            StringBuilder s = new StringBuilder();
            Class studentClass = Class.forName("Student");
            //下面就是从上往下边一点点拼接Student类的源码
            s.append(Modifier.toString(studentClass.getModifiers()) + "class" + " " + studentClass.getSimpleName() + "{ \n");
            
            Field[] fields = studentClass.getDeclaredFields();
            
            //拿到每一个Field的修饰符、类型、变量名,再拼起来
            for(Field field:fields){
                s.append("\t");
                String modifierStr = Modifier.toString(field.getModifiers());
                String typeStr = field.getType().getName();
                String fieldStr = field.getName();
                s.append(modifierStr + " " + typeStr + " " + fieldStr + ";");
                s.append("\n");
            }
            
            s.append("}");
            
            System.out.println(s);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
//最好直接append,创建这么多字符串浪费空间

运行结果:
run
靠,有bug,获取类型用getSimpleName():

String typeStr = field.getType().getSimpleName();

正常了:
run

3、通过反射机制访问对象的属性

Class studentClass = Class.forName("Student");
Object obj = studentClass.newInstance();

//getDeclaredFields()拿到的是一个Field集合,getDeclaredField(属性名)拿到的是Field
Field noField = studentClass.getDeclaredField("no"); 
noField.set(obj,9527);
System.out.println("noField的值:"+ noField.get(obj));

//访问私有属性会报错
Field nameField = studentClass.getDeclaredField("name");
nameField.set(obj,"llg");
System.out.println("私有属性name值:"+ nameField.get(obj));

运行报错:java.lang.IllegalAccessException
run
这时可以通过setAccessible(true)方法打破封装,但这样也同时带来了安全问题

Field nameField = studentClass.getDeclaredField("name");

nameField.setAccessible(true);

nameField.set(obj,"llg");
System.out.println("私有属性name值:"+ nameField.get(obj));

4、可变长参数☀☀☀

语法:
类型…(三个点)

举例:

public static void m(int...args){
   System.out.println("doSome!");
}

------------
调用时:
m();
m(10);
m(10,20,30);

注意:可变长度的参数必须在列表的最后一个

错误
args有length属性,说明它可以当作一个数组来看待

public static void m(int...args){
	  for(int i:args){
	      System.out.println(i);
	  }
}

----
调用时也可以传一个数组进去:
int[] num = {1,2,3,4};
m(num);

可变长参数的语法总结:

  • 可变长参数要求参数的个数是0~N个
  • 可变长参数在参数列表只能出现在最后一个位置,也即只能有一个可变长度参数
  • 可变长度参数可以当作一个数组看待

5、反射与反编译Method

/**
 * 用户业务类
 */
public class UserService {
    public boolean login(String name,String password){
        if("admin".equals(name) && "123qweASD".equals(password)){
            return true;
        }else{
            return false;
        }
    }
    public void logout(){
        System.out.println("用户退出登录!");
    }
}

反射Method:

 Class userServiceClass = Class.forName("UserService");
 
 Method[] methods = userServiceClass.getDeclaredMethods();
 
 for(Method method:methods){
 
     System.out.println(Modifier.toString(method.getModifiers())); //修饰符
     
     System.out.println(method.getReturnType().getSimpleName());  //返回值类型

     System.out.println(method.getName()); //方法名
     
     Class[] parameterTypes = method.getParameterTypes(); //所有参数的类型
     
     for(Class parameterType:parameterTypes){
         System.out.println(parameterType.getSimpleName());
     }
 }

运行结果:
run

反编译Method如下:

/**
 * 反编译
 */
class Decompile{
    public static void main(String[] args) throws ClassNotFoundException {
        StringBuilder s = new StringBuilder();
        Class userServiceClass = Class.forName("UserService");
        s.append(Modifier.toString(userServiceClass.getModifiers()) + " " + "class" + " "+ userServiceClass.getSimpleName() + "{");
        s.append("\n");
        Method[] methods = userServiceClass.getMethods();
        for(Method method:methods){
            //频繁创建字符串会占用很多空间,我直接append了
            s.append("\t");
            s.append(Modifier.toString(method.getModifiers()));
            s.append(" ");
            s.append(method.getReturnType().getSimpleName());
            s.append(" ");
            s.append(method.getName());
            s.append("(");
            Class[] parameterTypes = method.getParameterTypes();
            for(Class parameterType:parameterTypes){
                s.append(parameterType.getSimpleName());
                s.append(",");
            }
            //修复bug:对于有形参的,删掉上面加的最后多余的逗号
            if(parameterTypes.length != 0){
                s.deleteCharAt(s.length()-1); 
            }

            s.append("){}\n");
        }
        s.append("}");
        System.out.println(s);
    }

}

运行效果:
run
这玩意很难一次完美反编译出来,运行一下哪里有bug再调代码就好。

6、用反射机制调用对象的方法

Class userServiceClass = Class.forName("UserService");
Object obj = userServiceClass.newInstance();
//注意传参,即区分一个方法是靠方法名+参数
Method loginMethod = userServiceClass.getDeclaredMethod("login",String.class,String.class);
 /**
  * invoke方法
  * loginMethod是要调用的方法的Method对象
  * obj是调用方法的对象
  * 后面是传入的实参列表
  */
Object retValue = loginMethod.invoke(obj,"admin","123qweASD");

System.out.println(retValue); //true

反射机制+配置文件 = 灵活性,体现的OPC原则,对扩展开放,对修改关闭

7、反射与反编译Constructor

先写个素材类:
Vip类
反射就不写了,一些方法直接在反编译中体现:

/**
 * 反编译
 */
class DecompileVip{
    public static void main(String[] args) throws Exception {
        StringBuilder s = new StringBuilder();
        Class vipClass = Class.forName("Vip");
        s.append(Modifier.toString(vipClass.getModifiers()) + " " + "class" + vipClass.getSimpleName() +"{");
        
        Constructor[] constructors = vipClass.getDeclaredConstructors();
        
        for(Constructor constructor:constructors){
            s.append("\n");
            s.append("\t");
            s.append(Modifier.toString(constructor.getModifiers()));
            s.append(" ");
            s.append(vipClass.getSimpleName()); //构造方法名即类名
            s.append("(");
            Class[] parameterTypes = constructor.getParameterTypes();
            for(Class parameterType:parameterTypes){
                s.append(parameterType.getSimpleName());
                s.append(",");
            }
            //修复上面引入的bug,删除最后一个多余的,逗号
            if(parameterTypes.length != 0){
                s.deleteCharAt(s.length()-1);
            }
            s.append("){" + "\n" + "\t" + "}");
            s.append("\n");
        }
        s.append("}");
        System.out.println(s);
    }
}

运行效果:
run

8、用反射机制调用构造方法

Class VipClass = Class.forName("Vip");
Constructor constructor = VipClass.getDeclaredConstructor(int.class,String.class,boolean.class);
//这种调用无参构造的方式已过时
Object obj = VipClass.newInstance();
/**
 * 调用有参构造来new对象
 */
Object obj2 = constructor.newInstance(110,"llg",true);
/**
 * 调用无参构造
 */
Constructor constructor1 = VipClass.getDeclaredConstructor();
Object obj3 = constructor1.newInstance();

9、获取某类的父类以及实现了哪些接口

Class stringClass = Class.forName("java.lang.String");

Class superClass = stringClass.getSuperclass(); //获取父类
System.out.println(superClass.getSimpleName());

Class[] interfaces = stringClass.getInterfaces(); //获取这个类实现的接口
for(Class api:interfaces){
    System.out.println("String类实现的接口有:" + api);
}

运行结果:
在这里插入图片描述

四、注解

1、概述

  • 注释,注解,Annotation
  • 注解Annotation是一种引用数据类型,编译后也生成xx.class文件
  • 定义的语法格式为:
[修饰符列表] @ interface 注释类型名{
}
  • 注解的使用语法是:@注解类型名
  • 注解可以出现在类上、属性上、方法上、变量上等,还可以出现在注解类型上,默认情况下,注解可以出现在任意位置

2、JDK的内置注解

java.lang包下的注解

@Override 表示一个方法声明打算重写超类中的另一个方法声明,源码:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)

public @interface Override {
}

这是一个标识性注解,给编译器做参考的,和运行阶段无关,编译器看到这个注解,就会检查这个方法是否重写了父类的方法,若不是,则报错。故@Override只能注解方法

元注解

用来标注注解类型的注解,称元注解,常见的元注解有Target和Retention。

  • Target用来标注“被标注的注解”可以出现在哪些位置,如@Target(ElementType.METHOD)即被标注的注解只能出现在方法中,
  • Retention用来标注“被标注的注解”最终保存在哪里,如:
@Retention(RetentionPolicy.SOURCE) 表示该注解只能保留在Java源文件中

@Retention(RetentionPolicy.CLASS) 表示该注解只能保留在class文件中

@Retention(RetentionPolicy.RUNTIME) 表示该注解只能保留在class文件中,且可以被反射机制所读取

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

-------
public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

表示过时的注解@Deprecated

方法或类等元素已过时的时候,可以用@Deprecated,从而传达给别人,已过时,当前有更好的解决方案。
过时
源码解析:
源码

3、注解中定义属性

自定义

public @interface MyAnnotation {
    //带括号,看着像方法,但这是MyAnnotation的一个属性
    String name();
    //这是一个有默认值的属性,使用注解时可以不用赋值
    int age() default 22;
}

使用时:

@MyAnnotation(name="llg")
public static void doSome(){

}

当注解中的属性只有一个的时候,使用注解就可以不用加属性名了

public @interface MyAnnotation {
	String value();
}

使用时:
@MyAnnotation("code9527")
...

注解中的属性的类型可以是:byte、short、int、long、float、double、char、String、Class、枚举类型以及以上每一种类型对应的数组形式,如:int[ ] value

public @interface OtherAnnotation {
    int age();
    String[] email();
    Hobby[] hobbyArray();
}
-------------
public enum Hobby {
    RAP,SING,RUN
}
-------------
@OtherAnnotation(age = 22,email = {"code@qq.com","9527@qq.com"},hobbyArray = {Hobby.SING,Hobby.RAP})  //若数组中只有一个元素,{}可省略
public static void doSome(){

}

4、反射注解

Class c = Class.forName("Test7");
//判断该类上是否有注解”OtherAnnotation“
System.out.println(c.isAnnotationPresent(OtherAnnotation.class));

if(c.isAnnotationPresent(OtherAnnotation.class)){
    //获取注解对象
    //getAnnotation方法返回的是Annotation类型,这里强转以匹配前面我写的变量类型
    OtherAnnotation otherAnnotation = (OtherAnnotation) c.getAnnotation(OtherAnnotation.class);
    int ageValue = otherAnnotation.age();
}

注意注解反射的前提是标记了@Retention(RetentionPolicy.RUNTIME)


整理完了,完结撒花!!! 2022-12-10 17:08

在这里插入图片描述

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

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

相关文章

Akka 学习(七)Actor的生命周期

在Actor的生命周期中会调用几个方法,我们在需要时可以重写这些方法。 ● prestart():在构造函数之后调用。 ● postStop():在重启之前调用。 ● preRestart(reason, message):默认情况下会调用postStop()。 ● postRestart()&…

D/A转换器

性能指标:转换精度,转换速度 相互之间是矛盾的,精度越高,相比而言速度就会慢一些 权电阻网络D/A转换器 阻值的选取是按照二进制的位权来选择的,所以我们看到了这个结构,和我们刚才分析的是一致的 权电阻网…

基于花授粉算法优化的lssvm回归预测-附代码

基于花授粉算法优化的lssvm回归预测 - 附代码 文章目录基于花授粉算法优化的lssvm回归预测 - 附代码1.数据集2.lssvm模型3.基于花授粉算法优化的LSSVM4.测试结果5.Matlab代码摘要:为了提高最小二乘支持向量机(lssvm)的回归预测准确率&#xf…

c++11 std::thread和mutex用法

c11 std::thread和mutex用法thread和mutex用法thread简单示例thread构造函数梳理thread关键成员函数mutex使用thread和mutex用法 本文对c 11中的std::thread 和 mutex作简要的使用说明 thread简单示例 #include <iostream> #include <string> #include <thre…

mysql性能监控

一.使用show profile查询剖析工具&#xff0c;查看mysql语句执行时间&#xff1a; 官网&#xff1a;https://dev.mysql.com/doc/refman/8.0/en/show-profile.html mysql -uroot -p //进入数据库服务器 use 数据库名 //进入数据库 set profiling1; //开启profiling参数 select…

Python基础(十二):字典的详细讲解

文章目录 字典的详细讲解 一、字典的应用场景 二、创建字典的语法

具身智能综述和应用(Embodied AI)

什么是具身智能&#xff1f; 目前人工智能的进展&#xff0c;在诸多数据源和数据集&#xff08;Youtube、Flickr、Facebook&#xff09;、机器计算能力&#xff08;CPU、GPU、TPU&#xff09;的加持下&#xff0c;已经在CV、NLP上取得了许多任务&#xff08;如目标检测、语义分…

Python学习----闭包和装饰器

情景&#xff1a; 当我们调用函数的时候&#xff0c;函数调用完成之后&#xff0c;函数内定义的变量都会被销毁&#xff0c;但是我们有时候需要保存函数内的这个变量&#xff0c;每次在这个变量的基础上完成一系列的操作&#xff0c;比如&#xff1a;每次在这个变量的基础上和其…

【全网惟一面向软件测试人员的Python基础教程】- 学Python之前要搞懂的道理

全网惟一面向软件测试人员的Python基础教程 起点&#xff1a;《python软件测试实战宝典》介绍 第一章 为什么软件测试人员要学习Python 第二章 学Python之前要搞懂的道理 文章目录全网惟一面向软件测试人员的Python基础教程计算机的本质是什么&#xff1f;什么是编程呢&#x…

Java泛型的使用和原理

文章目录泛型-概述基础使用泛型类的使用泛型类派生子类泛型接口泛型方法类型通配符类型通配符上限类型通配符下限常用泛型标识符类型擦除使用注意泛型与数组泛型和反射其他泛型-概述 Java 泛型&#xff08;generics&#xff09;是 JDK 5 中引入的一个新特性&#xff0c;泛型提…

第十四届蓝桥杯集训——JavaC组第八篇——进制转换

第十四届蓝桥杯集训——JavaC组第八篇——进制转换 目录 第十四届蓝桥杯集训——JavaC组第八篇——进制转换 短除法 十进制转二进制示例&#xff1a; 十进制转换二进制 十进制转换八进制 十进制转换十六进制 二进制转十进制 八进制转十进制 十六进制转十进制 进制转换…

【✨十五天搞定电工基础】半导体器件

本章要求1. 理解PN结的单向导电性&#xff0c;三极管的电流分配和电流放大作用 2. 了解二极管、稳压管和三极管的基本构造、工作原理和特性曲线&#xff0c;理解主要参数的意义 3. 会分析含有二极管的电路 目录 一、半导体基础知识 1、本征半导体的导电机理 2、杂质半导体 …

部分核心技术(持续更新)

文章目录1.Schedule&#xff08;定时任务&#xff09;2.高并发线程安全的解决方案2.1为什么不适用同步锁&#xff08;Synchronized&#xff09;&#xff1f;2.2 Redis的分布式锁setnx2.3 redisson分布式锁&#xff08;看门狗机制&#xff09;2.3.1 Redis的分布式锁setnx产生的问…

保姆级入门nest笔记

使用 NEXT 搭建后台服务接口 https://docs.nestjs.com/ # 准备工作 安装 node 全局安装 nest npm i -给nestjs/cli nest --version # 创建项目 创建项目next new 启动项目npm run start 或 npm run start:dev 访问接口 localhost:3000 获取命令解释 next g -h # 快速创建…

Pixracer接线图 及电调调参 BLheliSuite

Pixracer接线指南 pixracer官方链接 正反面引脚定义 接口含义 BLheliSuite调参软件 官方下载&#xff1a; https://www.mediafire.com/folder/dx6kfaasyo24l/BLHeliSuite 我使用了如下软件https://www.mediafire.com/file/9uccf1zy3wqb1w5/BLHeliSuite32_32.9.0.3.zip/fil…

Bio-Net:编解码器结构的循环双向连接网络

目录 摘要 方法 循环双向跳跃连接 前向跳跃连接 后向跳跃连接 递归的推断训练 BiO-Net网络结构 总结 摘要 对UNet以前的扩展主要集中对现有模块的改进或者提出新的模块来提高性能。因此这些变量通常会导致模型的复杂性不可忽视的增加。为了解决这种复杂性的问题。在本…

redis cluster 集群安装

redis cluster 集群安装 redis集群方案 哨兵集群 如图&#xff0c;实际上还是一个节点对外提供服务&#xff0c;所以虽然是三台机器&#xff0c;但是还是一台机器的并发量&#xff0c;而且master挂了之后&#xff0c;整个集群不能对外提供服务 cluster集群 多个主从集群节点…

五、伊森商城 前端基础-Vue 整合ElementUI快速开发 p28

目录 一、安装 1、安装ElementUI 2、在main.js文件中引入 2.1、引入ElementUI组件 2.2、让Vue使用ElementUI组件 二、使用 1、在hello.vue组件使用单选框 2、使用ElementUI快速搭建后台管理系统 2.1、修改App.vue 3、修改功能成动态显示 3.1、编写快速生成组件的模板 3…

java计算机毕业设计ssm学习互助平台网站8f554(附源码、数据库)

java计算机毕业设计ssm学习互助平台网站8f554&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff0…

C++11之引用

文章目录目的为啥要引入右值引用什么是右值引用右值引用作用移动构造函数移动语义 std::move移动语义注意事项完美转发博客目的 了解对应左值引用&#xff0c; 右值引用&#xff0c;移动语义&#xff0c; 完美转发含义。 右值引用&#xff08;及其支持的移动语义Move semanti…