黑马程序员——mysql——day05——反射、注解、动态代理

news2024/11/26 8:53:14

目录:

  1. 类的加载
    1. 目标
    2. 讲解
      1. 类的加载过程
      2. 类的加载机制
    3. 小结
  2. 类加载器
    1. 目标
    2. 讲解
      1. 类加载器的作用
      2. 类加载器的分类:
      3. 获取类加载器的方式
    3. 小结
  3. 双亲委派机制
    1. 目标
    2. 讲解
      1. 3种类加载器的关系
      2. 双亲委派机制
    3. 小结
  4. 反射:概述
    1. 目标
    2. 讲解
      1. 反射
      2. 反射技术的应用案例:
      3. 反射技术的作用
    3. 小结
  5. 反射:Class类
    1. 目标
    2. 讲解
      1. Class类
      2. 获取Class对象
      3. Class类中的常用方法
    3. 小结
  6. 反射:构造器
    1. 目标
    2. 讲解
      1. Constructor类
      2. 获取Constructor对象的方式
      3. Constructor类常用方法
    3. 小结
  7. 反射:使用构造器创建对象
    1. 目标
    2. 讲解
      1. 案例:使用无参构造器创建对象
      2. 案例:使用有参构造器创建对象
      3. 案例:使用私有构造器创建对象
    3. 小结
  8. 反射:方法
    1. 目标
    2. 讲解
      1. Method
      2. 获取Method对象的方式
      3. Method类常用方法
    3. 小结
    4. 回顾上午内容
  9. 反射:方法调用
    1. 目标
    2. 讲解
      1. 案例:调用无参无返回值的方法
      2. 案例:调用有参有返回值的方法
      3. 案例:调用私有方法
      4. 案例:调用静态方法
    3. 小结
    4. 反射的作用案例演示
  10. 注解:概述
    1. 目标
    2. 讲解
      1. 注解
      2. 注解的作用
    3. 小结
  11. 注解:自定义注解
    1. 目标
    2. 讲解
      1. 注解的定义格式
      2. 带有属性的注解
  12. 注解:注解的使用
    1. 目标
    2. 讲解
      1. 注解的使用格式
      2. 案例代码
      3. 特殊属性value
    3. 小结
  13. 注解:元注解
    1. 目标
    2. 讲解
      1. 元注解的作用
      2. 常用的元注解
      3. 元注解的使用
    3. 小结
  14. 注解:注解解析
    1. 目标
    2. 讲解
      1. 获取注解数据的原理
      2. 案例代码
    3. 小结
  15. 注解:综合案例
    1. 目标
    2. 讲解
      1. 需求
      2. 案例分析
      3. 案例代码
    3. 小结
  16. 代理模式:动态代理_准备案例、提出问题
  17. 代理模式:使用动态代理解决问题介绍
  18. 代理模式:使用动态代理解决问题代码实现
  19. 代理模式:使用动态代理解决问题代码实现

1.类的加载

目标
  • 能够理解字节码加载过程 【了解】

讲解
  1. 类的加载过程

  2. 类的加载时机


类的加载过程
  • 当程序在运行后,第一次使用某个类的时候,会将此类的class文件读取到内存,并将此类的所有信息存储到一个Class对象中

说明:Class对象是指java.lang.Class类的对象,此类由Java类库提供,专门用于存储类型的信息  

类的加载机制

在以下情况下会加载类:

  1. 创建一个类的对象(第1次)

  2. 调用类的静态方法,静态变量 (第1次)

  3. 使用一个类的子类时 (第1次)

  4. 通过反射进行加载类

  5. java命令执行某一个类 (第1次)运行java程序

public class HelloWorld{
    public static void main(String[] args){
        System.out.println("Hello World!");
    }
}

//编译: javac HelloWorld.java    //生成:HelloWorld.class  字节码文件
//运行: Java HelloWorld   //使用java命令执行HelloWorld类(默认调用main方法)
                          //底层: HelloWorld.main(null);

 

小结

问题1:Student.class文件中都包含什么内容?

  • 构造方法、成员变量、成员方法

在jvm执行某个类时,如果该类是第一次被执行:

  • 先把该类的.class文件读取到内存中
  • 基于.class文件创建一个Class对象(方法区)
    • Class对象中存储的是.class文件中的内容:构造方法、成员变量、成员方法
      • Class对象中存储的构造方法:构造器对象 Constructor对象
      • Class对象中存储的成员变量:字段对象 Field对象
      • Class对象中存储的成员方法:方法对象 Method对象

 

2.类加载器

目标
  • 了解类加载器的概念 【了解】

讲解
  1. 类加载器的作用

  2. 类加载器的分类

  3. 获取类加载器的方式


类加载器的作用

什么是类加载器?

  • 加载器是Java运行时环境的一部分,负责加载字节码文件

类加载器的作用:

  • 负责将磁盘上的某个class文件读取到内存并生成Class的对象

类加载器的分类:

Java中有三种类加载器,它们分别用于加载不同种类的class:

  • 启动类加载器(Bootstrap ClassLoader):用于加载系统类库<JAVA_HOME>\bin目录下的class,例如:rt.jar。

  • 扩展类加载器(Extension ClassLoader):用于加载扩展类库<JAVA_HOME>\lib\ext目录下的class。

  • 应用程序类加载器(Application ClassLoader):用于加载我们自定义类的加载器。

获取类加载器的方式

来自Class类型获取类加载器的方法:

public ClassLoader getClassLoader()  //返回该类的类加载器
//有些实现可能使用null来表示引导类加载器(启动类加载器)
//如果该类由引导类加载器(启动类加载器)加载,则此方法在这类实现中将返回 null 

代码实践:

//自定义类型
class Student{
    private int age;
}

//测试类
public class Demo01 {
    public static void main(String[] args){
        //获取自定义类的类加载器
        //1. 先获取Student对应的Class对象
        Class<Student> cls = Student.class;  
        
        //2. 再通过该class对象获取类加载器
        ClassLoader loader = cls.getClassLoader();
        
        System.out.println("loader = "+loader);//ClassLoaders$AppClassLoader@2437c6dc

        
        //获取String类的类加载器
        ClassLoader loader2 = String.class.getClassLoader();
        System.out.println("loader2 = " + loader2);
    }
}

 

小结

类加载器的作用:

  • 把硬盘上的.class文件读取到内存中并创建Class对象

类加载器可以分为3种:

  • 引导类加载器(启动类加载器) 负载加载系统类库(java.lang包)

  • 扩展类加载器 负责加载jdk扩展的类库

  • 应用程序类加载器 负责加载程序员自己写的类

3.双亲委派机制

目标
  • 了解双亲委派机制的工作过程 【了解】

讲解
  1. 3种类加载器的关系

  2. 双亲委派机制

  3. 双亲委派机制的好处


3种类加载器的关系

从上图可知,三种类加载器存在一定的关系:

  • 应用程序类加载器的父级类加器是扩展类加载器

  • 扩展类加载器的父级类加载器是启动类加载器

结论:这种关系称为类加载器的"双亲委派模型"

双亲委派机制

"双亲委派模型"的工作机制:

  • 某个"类加载器"收到类加载的请求,它首先不会尝试自己去加载这个类,而是把请求交给父级类加载器

  • 因此,所有的类加载的请求最终都会传送到顶层的"启动类加载器"中

  • 如果"父级类加载器"无法加载这个类,然后子级类加载器再去加载

"双亲委派模型"中,除了顶层的启动类加载器外,其余的类加载器都应当有自己的"父级类加载器"

小结

双亲委派机制:

  • 在使用一个类时,类并不会由应用程序类加载器来加载,而是由"双亲:启动类加载器、扩展类加载器"先来进行加载,当"双亲"无法加载时,才由应用程序类加载器来完成.class的加载及Class对象的创建

4.反射:概述

目标
  • 了解反射技术的作用 【了解】

讲解
  1. 反射的概述

  2. 反射技术的作用


反射

反射技术:

  • 其实就是对类进行解剖的技术

    • 类中有什么?

      • 构造方法

      • 成员变量

      • 成员方法

结论:反射技术就是把一个类进行了解剖,然后获取到 构造方法、成员变量、成员方法

反射技术的应用案例:
  • idea

  • 框架技术:Spring

想要使用反射技术有一个必备条件:

  • Class对象

    • 原因:.class文件由类加载器读取并创建Class对象。Class对象中存储了.class文件中的内容:构造方法、成员变量、成员方法

反射技术的作用

使用反射技术,可以对类进行解剖,可以获取到类中的:构造方法、成员变量、成员方法

  • 构造方法: 可以创建对象

  • 成员方法: 可以调用执行

  • 成员变量: 赋值、取值

反射技术的作用:

  • 不用使用new关键字,就可以创建对象

  • 不用使用"对象名.方法"形式,就可以调用方法

  • 不用使用"对象名.属性"形式,就可以给属性赋值、取值

    • 通常在类中属性,都被修饰为private(私有的:外部不能访问)

    • 反射技术,可以做到对私有成员进行操作

示例:

"cn.itcast.pojo.Student" stu = new cn.itcast.pojo.Student();


给一个字符串:"cn.icast.pojo.Student"

创建一个对象:?????   //使用new做不到  
           使用反射技术可以实现

示例:

给一个Student.class

程序在运行中,不能停止, 动态的获取一个Student.class
    //使用反射技术,可以在JVM运行状态下,动态的获取并加载Student.class
小结

反射技术 :对类进行解剖的技术

反射技术的作用:可以不通过传统方式,来实现类的实例化、方法的调用

  • 实现的提前:需要使用Class对象

5.反射:Class类

目标
  • 掌握Class对象的获取方式 【掌握】

讲解
  1. Class类

  2. 获取Class类对象的方式

  3. Class类中的常用方法


Class类
  • Class就是用来描述正在运行的java类型

  • Class类的实例表示Java中任何正在运行的类型,每一个类型都有与之对应的Class对象

    • 比如:类,接口,枚举,注解,数组,基本数据类型,void 都有与之对应的Class对象

      • 类名.class
        接口名.class
        int.class
        boolean.class
        array.class    

获取Class对象

获取Class类对象的方式有3种:

方式一:类型名.class   //Student.class
方式二:对象.getClass()  //对象名.getClass()
方式三:Class.forName(String className) //className是全路径类名 = 包名+类型名
//方式1:类型名.class
//应用场景: 当类名明确时,可以直接使用"类名.class"
Class clz = String.class 
Class clz = int.class 
Class clz = double.class
    
//方式2:对象.getClass()
//应用场景:通常是应用方法中
 public void method(Student stu){
    Class clz = stu.getClass();   
 } 

//方式3: Class.forName("类的全名称");//带有包名的类
//应用场景: 通常使用在读取配置文件中的类型
pro.properties文件
--------------文件内容------------------    
className=cn.icast.pojo.Student   
---------------------------------------   
//代码实现    
ResourceBundler r = ResourceBundler.getBundler("pro");
String className = r.getString("className");//"cn.icast.pojo.Student"
    
Class StudentClass = Class.forName(className);//className="cn.icast.pojo.Student" 

//当获取到Class对象了,就可以对类进行解剖了
 Class类中的常用方法
String getSimpleName()  // 获得类名字符串:类名
String getName()   // 获得类全名:包名+类名
T newInstance() // 创建Class对象关联类的对象 (前提:类中有一个无参构造方法)
    
//示例:
      Studentod类    cn.itcast.pojo.Student     //public Student(){}
      
      Class stuClass = Student.class;
      Object obj = stuClass.newInstance();//调用Student()  创建Student对象
      
      Student stu = (Student) obj;

代码实现:  

public class Test01 {

    @Test
    public void testMethod3() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class stuClass = Class.forName("com.itheima.cls.demo2.Student");

        Student stu = (Student) stuClass.newInstance();

        stu.study();
    }



    @Test
    public void testMethod2() throws IllegalAccessException, InstantiationException {
        Student stu =new Student();

        //对象名.getClass()
        Class studentClass = stu.getClass();

        Student student = (Student) studentClass.newInstance();

        student.study();
    }


    @Test
    public void testMethod1() throws IllegalAccessException, InstantiationException {
        // 类型名.class
        Class studentClass = Student.class;
        //System.out.println(studentClass);

        System.out.println("带有包名的类:"+studentClass.getName());
        System.out.println("类名:"+studentClass.getSimpleName());

        //实例化Student对象
        Object obj = studentClass.newInstance();
        Student stu = (Student) obj;
        stu.age=20;
        stu.name="张三";
        System.out.println(stu.name+"==="+stu.age);
        stu.study();
    }
}
小结

获取Class对象的方式:

  1. 类型名.class //明确了具体的类型时,直接使用:类名.class

  2. 对象名.getClass() //当方法中传递的对象时,使用:对象名.getClass()

  3. Class类中的静态方法:forName("带有包名的类") //从配置文件中读取到类的全名称时

6.反射:构造器

目标
  • 能够使用Class对象获取构造器Constructor对象 【掌握】

讲解
  1. Constructor类

  2. 获取构造器Constructor对象的方式

  3. Constructor类中常用方法


Constructor类

Class中的类型:

构造方法对应的类型:          Constructor类型
字段:                                    Field
方法:                                    Method 

Constructor类

  • 代表构造方法(构造器)

  • 类中的每一个构造方法都是一个Constructor类的对象

反射技术中构造器的目的:

  • 获得Constructor对象来创建类的对象

    • 大白话:不使用new关键字,通过Constructor来创建对象

获取Constructor对象的方式

Constructor对象的获取和Class类中方法有关:

Constructor[] getConstructors()
        //获得类中的所有构造方法对象,只能获得public的

Constructor[] getDeclaredConstructors()
        //获得类中的所有构造方法对象
    	//可以是public、protected、(默认)、private修饰符的构造方法    

    
Constructor getConstructor( Class... parameterTypes)
        //根据参数类型获得对应的Constructor对象   获取public修饰的
        //只能获得public修饰的构造方法
/*示例: Student       public Student(String name, int age)    public Student(int age) 
        Class stuClass = Student.class;
        //根据给定的参数类型,来获取匹配的构造器对象
        Constructor c = stuClass.getConstructor( String.class , int.class );
*/  
    
    
Constructor getDeclaredConstructor(Class... parameterTypes)
        //根据参数类型获得对应的Constructor对象
    	//可以是public、protected、默认、private修饰符的构造方法
Constructor类常用方法  
T newInstance(Object... initargs)
 	//根据指定的参数创建对象
/*
        Class stuClass = Student.class;
        //根据给定的参数类型,来获取匹配的构造器对象
        Constructor c = stuClass.getConstructor( String.class , int.class );
        //使用构造器对象,来实例化Student
        c.newInstance( "张三", 22 );//Student(String name, int age)
           
        //无参构造
        Constructor c = stuClass.getConstructor();
        Student stu = (Student) c.newInstance();
*/    
    
    
void setAccessible(true)//应用场景:仅适用于访问有权限检查的成员
   //设置"暴力反射" ——是否取消权限检查,true取消权限检查,false表示不取消

 代码实现:

public class Test1 {
    @Test
    public void testMethod1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
       //获取构造器的步骤
        /*1、先获取到Class对象
          2、使用Class对象中的方法,获取Constructor对象
          3、使用Constructor对象,实例化类
       */
        //获取Class对象(Student.class)
        Class stuClass = Student.class;

        //获取Constructor对象: public Student()
        Constructor con1 = stuClass.getConstructor();

        System.out.println(con1);

        Student stu = (Student)con1.newInstance();
        stu.name="小崔";
        System.out.println(stu.name);
    }
}
小结

Constructor类:

  • 代表类中的一个构造方法

获取Constructor类的方式:

//获取public修饰的构造方法
Constructor getConstructor(Class... parameterTypes)
    
    
//获取非public修饰的方法
Constructor getDeclaredConstructor(Class... parameterTypes)

 常用方法:

Object newInstance(Object... param)  //利用构造器对象,实例化自定义对象

void setAccessible(true) //消除JVM对权限的检查操作 (一次性的。只是对当前操作去除)    

7.反射:使用构造器创建对象

目标
  • 能够使用构造器Constructor对象创建对象 【掌握】

讲解
  1. 案例:使用无参构造器创建对象

  2. 案例:使用有参构造器创建对象

  3. 案例:使用私有构造器创建对象

案例:使用无参构造器创建对象  
@Test
    public void testMethod1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象(Student.class)
        Class stuClass = Student.class;

        //利用Class对象,来获取构造器对象
        Constructor con = stuClass.getConstructor();//方法中的参数为可变参数,可以不传递值

        //使用Constructor对象中的方法,来实例化Student类对象
        Student stu = (Student) con.newInstance();//方法中的参数是可变参数

        stu.study();
    }
案例:使用有参构造器创建对象  
//有参构造方法
    @Test
    public void testMethod2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象(Student.class)
        Class stuClass = Student.class;

        //public Student(String name, int age, String gender)
        //获取带有参数的构造器对象
        //参数:是用来设置构造方法中参数的类型是什么
        Constructor con = stuClass.getConstructor(String.class, int.class, String.class);

        //实例化有参构造方法
        //参数:要传递给Student(String name, int age, String gender)的数据
        Student stu = (Student) con.newInstance("熊大", 22, "男");

        //调用对象中的方法
        stu.study();
    }
案例:使用私有构造器创建对象  
 @Test
    public void testMethod3() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象(Student.class)
        Class stuClass = Student.class;

        // private Student(String name)
        //获取私有构造器对象
        Constructor con = stuClass.getDeclaredConstructor(String.class);

        //当需要对私有成员操作时,需要先取消JVM对访问权限的检查操作
        con.setAccessible(true);//暴力破解(取消权限检查) //仅在当前次取消

        //使用私有构造器,实例化Student对象
        Student stu = (Student) con.newInstance("文平");

        System.out.println(stu.name);
        stu.study();
    }
小结

当获取到私有构造器后,要使用该构造器创建对象,需要:

  • 取消权限检查:setAccessible(true)

 

8.反射:方法

目标
  • 掌握Method对象的获取方式 【掌握】

讲解
  1. Method类

  2. 获取Method对象的方式

  3. Method类常用方法


Method

Method类

  • 代表一个成员方法

    • 每一个成员方法都是一个Method类的对象

反射技术中使用Method的目的:

  • 通过Method对象来调用成员方法

获取Method对象的方式

Method对象的获取和Class类中方法有关:

Method[] getMethods();
    //获得当前类和其父类中的所有public成员方法对象,返回数组

Method[] getDeclaredMethods();
    //获得当前类中的所有成员方法对象,返回数组
    //只获得本类的,包括public、protected、默认、private的

Method getMethod(String name,Class...args);
    //根据方法名和参数类型获得对应的成员方法对象,只能获得public的
    //参数说明:
             name : 类中方法的名字
             args : 方法中参数类型的Class     例:int.class     

Method getDeclaredMethod(String name,Class...args);
    //根据方法名和参数类型获得对应的成员方法对象,包括public、protected、(默认)、private的
Method类常用方法  
//使用方法对象,调用对象中的方法执行(入栈执行)
Object invoke(Object obj, Object... args) 
    // obj: 对象   //"对象名.方法"
    // args:调用方法时传递的实参
//返回值: Object类型      
    
void setAccessible(true)
    // 设置"暴力访问"  ——是否取消权限检查,true取消权限检查,false表示不取消

代码实现:

//获取Method对象的步骤:
1、先获取Class对象
2、使用Class对象,获取Method对象
3、使用Method对象,执行方法
    
public class Test01 {
    @Test
    public void testMethod1() throws ClassNotFoundException {
        //获取Class对象
        Class stuClass  = Class.forName("com.itheima.method.demo1.Student");

        //使用Class对象,获取Method对象
        Method[] methods = stuClass.getMethods();//获取本类及父类中所有的public方法
        for (Method m : methods){
            System.out.println(m);
        }
    }
    @Test
    public void testMethod2() throws ClassNotFoundException {
        //获取Class对象
        Class stuClass  = Class.forName("com.itheima.method.demo1.Student");

        //使用Class对象,获取Method对象
        Method[] methods = stuClass.getDeclaredMethods();//获取本类中所有方法(包含私有)
        for (Method m : methods){
            System.out.println(m);
        }
    }
}    

 

小结

在反射中获取Method对象的步骤:

1、 先获取Class对象

2、基于Class对象,获取Method对象

3、使用Method对象,执行该方法

获取Method对象的方式:

//可以获取到本类及父类中public修饰的方法(指定方法名及方法中的参数类型)
Method getMethod(String name,Class...args);

//获取本类中任意的方法(指定方法名及方法中的参数类型)
Method getDeclaredMethod(String name,Class...args);

Method类中常用方法:

//执行Method对象所代表的方法
Object invoke(Object 对象 ,  Object... 方法中需要的实参);

void setAccessible(true)

回顾上午内容

  • 类加载过程

    • 在java程序中,当第一次访问类时,会把类的.class文件加载到内存中,并基于.class文件,创建一个Class对象(针对.class文件进行了封装)

  • 类加载器

    • java程序要运行,需要依赖于JRE(java运行环境),而jre中有类加载器,利用类加载器来加载.class文件并创建Class对象

    • 获取类加载器的方式:

    • Class类中有一个方法:
          ClassLoader cl = Class对象.getClassLoader();

反射:

什么是反射技术:

  • 反射技术,就是对类进行解剖,解剖出:构造方法、成员方法、成员变量
    • 构造方法: java.lang.reflect.Constructor类
    • 成员方法: java.lang.reflect.Method类
    • 成员变量: java.lang.reflect.Field类

反射技术的应用:

  • 框架技术开发

反射技术的使用:

  • 核心:需要利用Class对象
  • Class类
    • //获取Class对象
      
      //方式1: Class clazz = 类名.class
      //方式2: Class clazz = 对象名.getClass()
      //方式3: Class clazz = Class.forName("类的全名称")
    • 常用方法:
      • String getName() //获取带有包名的类
        String getSimpleName() //获取类名(不包含包名称)
        T  newInstance() //实例化对象(注意:需要有无参构造方法)  
  • 构造器:Constructor类
    • //获取Constructor对象
      //方式1: 获取public修饰的构造方法
      Constructor cons = Class对象.getConstructor(Class... 参数类型)
          
      //方式2: 获取private修饰的构造方法
      Constructor cons  = Class对象.getDeclaredConstructor(Class... 参数类型) 
          
      
      //获取所有的构造器对象:
      Constructor[]  cons = Class对象.getConstructors(); 
      Constructor[]  cons = Class对象.getDeclaredConstructors();
    • 常用方法:
      • //实例化对象
        T  newInstance(Object... 实参)
        
        //去除权限检查
        void setAccessible(true)  //针对非public修饰的  
  •  成员方法:Method类
    • //获取Method对象
      
      //方式1: 获取本类或父类中的public修饰的成员方法
      Method  m = Class对象.getMethod("方法名", Class... 方法中参数类型)
          
      //方式2: 获取本类中private修饰的成员方法
      Method  m = Class对象.getDeclaredMethod("方法名", Class... 方法中参数类型)    
          
      //获取所有的成员方法:
      Method[]  m = Class对象.getMethods() 
      Method[]  m = Class对象.getDeclaredMethods()    
    • 常用方法:
      • //调用方法
        Object invoke(Object  实例对象 , Object...  实参)
            
        //去除权限检查
        void setAccessible(true)

9.反射:方法调用

目标
  • 能够使用Method对象执行方法 【掌握】

讲解
  1. 案例:调用无参无返回值的方法

  2. 案例:调用有参有返回值的方法

  3. 案例:调用私有方法

  4. 案例:调用静态方法

案例:调用无参无返回值的方法  
 @Test
    public void testMethod1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象
        Class stuClass = Student.class;

        //因为在调用Method时,需要传递Student对象
        Constructor con = stuClass.getConstructor();
        Student stu = (Student)con.newInstance();

        //获取public void study()方法的对象
        Method method = stuClass.getMethod("study");

        //使用Method对象 执行study()方法
        method.invoke( stu );
    }
案例:调用有参有返回值的方法  
 //有参有返回值
    @Test
    public void testMethod2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象
        Class stuClass = Student.class;

        //因为在调用Method时,需要传递Student对象
        Constructor con = stuClass.getConstructor();
        Student stu = (Student)con.newInstance();

        //获取public String sayHello(String name)方法的Method对象
        Method method = stuClass.getMethod("sayHello", String.class);

        //调用method方法
       Object result = method.invoke(stu,"波波");

        System.out.println(result);
    }
案例:调用私有方法  
//私有方法
    @Test
    public void testMethod3() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        //获取Class对象
        Class stuClass = Student.class;

        //因为在调用Method时,需要传递Student对象
        Constructor con = stuClass.getConstructor();
        Student stu = (Student)con.newInstance();

        //获取 private void eat(String name)方法的Method对象
        Method method = stuClass.getDeclaredMethod("eat", String.class);

        //去除JVM对当前次权限的检查
        method.setAccessible(true);

        //执行method方法
        method.invoke(stu,"红烧肉");
    }
案例:调用静态方法  
//静态方法
    @Test
    public void testMethod4() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //获取Class对象
        Class stuClass = Student.class;

        //静态方法的调用不需要对象。"类名.静态方法()"
        //获取public static void sleep()方法的Method对象
        Method method = stuClass.getMethod("sleep");

        //执行静态方法
        method.invoke(null);//不需要传递对象(null就表示执行静态方法)
    }
小结

Method对象的使用步骤:

1、获取Class对象

2、基于Class对象,获取Method对象

//有参方法
Method method = Class对象.getMethod("方法名",参数1类型.class,参数2类型.class ...);
//无参方法
Method method = class对象.getMethod("方法名");

3、使用Method对象,执行方法

//调用非静态方法
method对象.invoke(实例对象,方法中需要的实参)
    
//调用静态方法
method对象.invoke(null,方法中需要的实参)    

 

反射的作用案例演示

  • 作用

    反射是框架的灵魂!框架的底层一定会用到反射技术。

  • 需求:要把猫的睡觉方法 变成 狗的吃饭方法

  • 效果:使用反射+Properties完成配置文件。把需要修改的灵活的内容写在配置文件中,代码不需要做任何的改动。

    • 案例演示

public class Dog {

    public void eat(){
        System.out.println("狗爱吃肉");
    }

    public void sleep(){
        System.out.println("狗睡觉流口水");
    }

}

public class Cat {

    public void eat(){
        System.out.println("猫爱吃鱼");
    }

    public void sleep(){
        System.out.println("猫睡觉打呼噜");
    }
}

  public class Demo {
      public static void main(String[] args) throws Exception{
          //不使用反射
          //需求:   要把猫的睡觉方法  变成  狗的吃饭方法
          //Dog d = new Dog();
          //d.eat();
  
          //使用反射
          //properties
          Properties pro = new Properties();
          //load():可以把文件中的键值对读取到集合中
          FileReader fr = new FileReader("day21\\aaa.txt");
          pro.load(fr);
  
          //通过键获取值
          String cn = pro.getProperty("className");
          String mn = pro.getProperty("methodName");
  
          //获取字节码对象
          Class c = Class.forName(cn);
          //获取空参构造
          Constructor con = c.getConstructor();
          //执行构造方法
          Object o = con.newInstance();
          //获取方法
          Method m = c.getMethod(mn);
          //执行方法
          m.invoke(o);
  
      }
  }
  
  配置文件:
  	className=com.itheima_05.Cat
  	methodName=sleep

 

10.注解:概述

目标
  • 能够理解注解在程序中的作用 【了解】

讲解
  1. 什么是注解

  2. 注解的作用

注解

什么是注解?

  • 注解(Annotation)也称为元数据,是一种代码级别的说明

  • 注解是JDK1.5版本引入的一个特性,和类、接口是在同一个层次

  • 注解可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明

注解:就是具有特殊含义的标记(注解是给机器阅读的)

 

注解的作用

注解就是在代码里添加一些特殊标志,这些标志可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行操作

注解的作用:

1.编译检查:

  • @Override:用来修饰方法声明。

  • 用来告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败

 

2.代码分析:

  • 通过代码里标识的注解对代码进行分析
  • 框架的配置( 框架 = 代码 + 配置 )
  • 具体使用请关注框架课程的内容的学习(注解去配置数据)

3.生成帮助文档:

  • @author:用来标识作者姓名
  • @version:用于标识对象的版本号,适用范围:文件、类、方法
  • 使用@author和@version注解就是告诉Javadoc工具在生成帮助文档时把作者姓名和版本号也标记在文档中

 

使用过的注解:

  • @Override

    • 用来修饰方法声明,告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败

  • @Test

    • Junit测试注解

  • @FunctionalInterface //函数式接口

小结

注解:在代码中添加的标记,JVM看到注解标记后会执行一些操作

注解的作用:

  • 编译检查

  • 运行时代码分析

  • 生成文档

 

11.注解:自定义注解

目标
  • 能够熟悉自定义注解的格式 【会用】

讲解
  1. 注解的定义格式

  2. 定义带有属性的注解


注解的定义格式

定义注解使用关键字:@interface

public @interface 注解名{
   //内容
}

注解本质上就是一个接口。所有注解都会继承一个接口:Annotation  

public interface 自定义注解名 extends java.lang.annotation.Annotation {}
带有属性的注解
  1. 属性的格式

    • 格式1:数据类型 属性名(); //无默认值的属性

    • 格式2:数据类型 属性名() default 默认值; //有默认值的属性

  2. 属性定义示例

 

public @interface Student {
  String name();                // 姓名
  int age() default 18;         // 年龄
  String gender() default "男"; // 性别
} 
// 该注解就有了三个属性:name,age,gender

属性适用的数据类型【记住】  

1. 八种数据数据类型(int,short,long,double,byte,char,boolean,float)
2. String,Class,注解类型,枚举类
3. 以上类型的一维数组形式

小结

注解的定义格式:

public @interface 注解名
{
    //属性格式 :  数据类型 属性名()
    String 属性名();
    int 属性名() default 默认值;
}
//注意:属性的类型只能是8种基本数据类型、String、Class、枚举、注解、(以及一维数组形式)

 

12.注解:注解的使用

目标
  • 能够掌握注解的基本使用 【会用】

讲解
  1. 注解的使用格式

  2. 案例代码

  3. 特殊属性value


注解的使用格式

格式:

//无属性注解
@注解名                      例:@Test

//有属性注解
@注解名(属性=值,属性=值)

注解可以在类上,成员变量上,构造方法上,方法上,参数上....

有默认值的属性,可以不用进行赋值。

案例代码

将Book注解使用起来

public @interface Book {
    String name();

    double price() default 100.0;

    String[] author();
}

建立一个BookStore的类,在类中定义成员变量,构造方法,成员方法

@Book(name = "西游记", author = {"吴承恩", "张三"})
public class BookStore {
    @Book(name = "三国", price = 10, author = {"罗贯中"})
    private String book;

    @Book(name = "三国", price = 10, author = {"罗贯中"})
    public BookStore() {
    }


    @Book(name = "三国", price = 10, author = {"罗贯中"})
    public void test() {

    }
}
特殊属性value

如果注解中只有一个属性要赋值,而且名字是value,可以将value给省略,可以直接给值

@interface A{
    String value();
}

@interface B{
    String value();
    String name();
}

@interface C{
    String value();
    int price() default 100; //有默认值
}
//测试类
public class Demo {
    @A("值")  //当自定义注解中仅有一个value属性时,可以省略value属性名
    public void test1() {
    }

    @B(value = "值",name="aa") //当自定义注解中除了value属性外,还有其它属性,value不能省略
    public void test2() {

    }

    @C("值")//自定义注解中除了value属性外,还有其它带有默认值的属性,value可以省略
    public void test3() {

    }
}
小结

自定义注解:

public @interface Book{
    //属性
    String name();
    double price() default 100;
}

在程序代码中使用自定义注解:

//注解可以应用在:类、方法、变量、构造方法

@Book(name="属性值")  //price属性使用默认值
public class BookStore{
    
    @Book(name="属性值",price="新的值") //新的price值,会覆盖默认值
    public void method(){
        
    }
}
    1.如果自定义注解中的属性不给默认值,那么使用的时候必须赋值,如果有默认值,使用的时候可以不给值
    2.使用注解:@注解名(属性名=属性值,属性名=属性值,....)
    3.如果注解中没有属性,使用的时候@注解名
    4.如果属性是数组,那么赋值方式:
        @注解名(属性名=属性值,属性名=属性值,属性名={属性值,属性值,..}....)
    5.如果属性是数组类型,并且使用的时候只给一个值,那么可以省略大括号
    6.如果属性只有一个并且属性名是value,那么给value赋值的时候可以不写value
    7.如果含有多个属性,并且没有默认值,那么给value赋值的时候必须书写value
    8.如果含有多个属性,并且具有默认值,那么给value赋值的时候可以不写value
    9.同一个注解不能同时修饰同一个方法或者同一个类
    10.不同注解可以同时修饰同一个方法或者同一个类

13.注解:元注解

目标
  • 熟悉Target和Retention两个元注解的作用 【会用】

讲解
  1. 元注解的作用

  2. 常用的元注解

  3. 元注解的使用


元注解的作用

默认情况下,注解可以用在任何地方,比如类,成员方法,构造方法,成员变量等地方

如果要限制自定义注解的使用位置怎么办?那就要学习一个新的知识点:元注解

结论:元注解是用来约束自定义注解的使用范围、生命周期

常用的元注解

常用元注解:@Target、@Retention

@Target

  • 作用:指明此注解用在哪个位置,如果不写默认是任何地方都可以使用

  • @Target可选的参数值在枚举类ElemenetType中包括:

    • TYPE: 用在类,接口上

    • FIELD:用在成员变量上

    • METHOD: 用在方法上

    • PARAMETER:用在参数上

    • CONSTRUCTOR:用在构造方法上

    • LOCAL_VARIABLE:用在局部变量上

@Retention

  • 作用:定义该注解的生命周期(有效范围)。

  • @Retention可选的参数值在枚举类型RetentionPolicy中包括:

    • SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了

      • 使用场景:针对一些检查性的操作,比如:@Override ,就使用SOURCE注解

    • CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有,默认值

      • 使用场景:在编译时进行一些预处理操作,比如:生成一些辅助代码,就用CLASS注解

    • RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,程序可以通过反射获取该注解

      • 使用场景:要在运行时去动态获取注解信息,那只能用 RUNTIME 注解

元注解的使用
@Target({ElementType.METHOD,ElementType.TYPE}) //元注解
@interface Stu{
    String name();
}

//类
@Stu(name="jack")  //成功
public class AnnotationDemo02 {
    // 成员变量
    @Stu(name = "lily")  // 编译失败
    private String gender;
    
    // 成员方法
    @Stu(name="rose")  //成功
    public void  test(){
    }
   
    // 构造方法
    @Stu(name="lucy") // 编译失败
    public AnnotationDemo02(){}
}
小结

元注解的作用:

  • 限定自定义注解的使用范围、生命周期

    • 限制使用范围:@Target

    • 限定生命周期:@Retention

 

14.注解:注解解析

目标
  • 能够使用反射的技术完成注解数据的解析 【会用】

讲解
  1. 获取注解数据的原理

  2. 案例代码


获取注解数据的原理

想要对注解中的数据进行解析,需要借助:AnnotatedElement接口

  • Field,Method,Constructor,Class等类都是实现了AnnotatedElement接口

AnnotatedElement 是一个接口,定义了解析注解的方法:

1. boolean isAnnotationPresent(Class<Annotation> annotationClass)   
   判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
   
   public class BookStore{
       
       @Book(name="书名")
       public void buy() // Method对象 判断该对象上是否使用了@Book注解
       {                 // boolean flag = Method对象.isAnnotationPresent(Book.class)
       }
   } 
    
  
2. T getAnnotation(Class<T> annotationClass) 
   根据注解类型获得对应注解对象
   // 获取对象上的自定义注解
   // Book bookAnno = Method对象.getAnnotation(Book.class); 
   //      bookAnno.属性   //获取注解中属性的值
    

Class,Constructor,Method,Field都会实现AnnotatedElement 接口

  1. 解析类型上的注解:借助字节码对象(Class对象)

  2. 解析构造方法上的注解:借助构造器对象(Constructor对象)

  3. 解析方法上的注解:借助方法对象(Method对象)

  4. 解析字段上的注解:借助字段对象(Field对象)

注解解析的步骤:(注解是书写在:类、方法、变量上)

  1. 利用反射技术获取注解作用的对象:类、方法、变量、构造方法
  2. 判断对象上是否有自定义注解存在
  3. 有:获取对象上的自定义注解
  4. 使用获取到的自定义注解对象,拿到注解中的属性值
  5. 注意:注解解析必须保证自定义注解生命周期在RUNTIME(程序运行中)

 

案例代码

需求如下:

  1. 定义注解Book,要求如下:

    • 包含属性:String value() 书名

    • 包含属性:double price() 价格,默认值为 100

    • 包含属性:String[] authors() 多位作者

    • 限制注解使用的位置:类和成员方法上 【Target】

    • 指定注解的有效范围:RUNTIME 【Retention】

  2. 定义BookStore类,在类和成员方法上使用Book注解

  3. 定义TestAnnotation测试类获取Book注解上的数据

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.TYPE}) //使用范围:方法、类
@Retention(RetentionPolicy.RUNTIME) //保证注解在程序执行时有效(适用于注解解析)
public @interface Book {
    String value();
    double price() default 100;
    String[] authors();
}


//类
public class BookStore {
    @Book(value = "Java入门", authors = {"张老师", "毕老师"})
    public void buy() {
        System.out.println("购书.....");
    }
}

//对注解中的数据进行解析
public class TestBookStore {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //反射套路:1、Class  2、构造器   3、Method
        Class<BookStore> bookStoreClass = BookStore.class;

        //获取构造器
        Constructor<BookStore> con = bookStoreClass.getConstructor();
        BookStore bookStore = con.newInstance();//实例化对象

        //获取Method
        Method method = bookStoreClass.getMethod("buy");

        //解析注解的步骤
        if(method.isAnnotationPresent(Book.class)){
            //获取Method对象上的Book注解
            Book bookAnno = method.getAnnotation(Book.class);

            //获取注解上的数据
            String bookName = bookAnno.value();
            double bookPrice = bookAnno.price();
            String[] bookAuthors = bookAnno.authors();

            System.out.println("书名:"+bookName);
            System.out.println("价格:"+bookPrice);
            System.out.println("作者:"+ Arrays.toString(bookAuthors));
        }
    }
}
小结

注解解析的步骤:

  1. 利用反射技术获取相关的对象:类、构造器、方法、变量

  2. 使用方法getAnnotation,获取自定义注解对象

  3. 使用注解对象,分别获取注解中的属性值

注解扩展小示例:

public class Student{
    private String name;//姓名
    private int age;//年龄
    private String gender;//性别
    private double score;//成绩
    private String id;//学号
}
数据:
    张三,20,男,90,it1001

利用注解+反射,给Student类中的成员变量赋值

//自定义注解
public @interface Entity{
    String value;
}
//Student类
public class Student{
    @Entity(value="张三")
    private String name;//姓名
    
    @Entiry(value="20")
    private int age;//年龄
    
    private String gender;//性别
    
    private double score;//成绩
    
    private String id;//学号
}

15.注解:综合案例

目标
  • 熟悉反射结合注解的使用 【会用】

讲解
  1. 案例需求

  2. 案例分析

  3. 案例代码


需求

需求:模拟Junit测试的@Test

案例分析
  1. 模拟Junit测试的注释@Test,首先需要编写自定义注解@MyTest,并添加元注解,保证自定义注解只能修饰方法,且在运行时可以获得。

  2. 然后编写目标类(测试类),然后给目标方法(测试方法)使用 @MyTest注解,编写三个方法,其中两个加上@MyTest注解。

  3. 最后编写调用类,使用main方法调用目标类,模拟Junit的运行,只要有@MyTest注释的方法都会运行

案例代码 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//自定义注解
@Target(ElementType.METHOD)//仅能应用在方法上
@Retention(RetentionPolicy.RUNTIME)//生命周期 :运行时
public @interface MyTest {
    //无属性注解
}


public class TestAnnotationParse {

    //方法1
    @MyTest
    public void method1(){
        System.out.println("我是方法1");
    }

    @MyTest
    public void method3(){
        System.out.println("我是方法3");
    }


    public void method2(){
        System.out.println("我是方法2");
    }

}



public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        //获取Class对象
        Class<TestAnnotationParse> testAnnotationParseClass = TestAnnotationParse.class;

        //获取Class对象中,所有的Method方法
        Method[] methods = testAnnotationParseClass.getMethods();
        
        //遍历数组
        for (int i = 0; i < methods.length; i++) {
            //获取每一个Method对象
            Method method = methods[i];

            //判断Method对象上,是否存在@MyTest
            if(method.isAnnotationPresent(MyTest.class)){
                method.invoke(testAnnotationParseClass.newInstance());
            }
        }
    }
}
小结

注解解析的步骤:

  1. 获取Class对象 //类名.class、对象名.class、Class.forName("...")

  2. 基于Class对象,来获取:构造器/成员方法/成员变量 //getConstructor() getMethod() getField()

  3. 基于构造器/成员方法/成员变量,判断是否存在自定义注解 // isAnnotationPresent(注解.class)

  4. 存在:获取自定义注解对象 // 注解 对象 = 构造器/方法/变量/类 .getAnnotation(注解.class)

  5. 基于自定注解对象,获取其属性值 // 注解对象.属性()

16.代理模式:动态代理_准备案例、提出问题

  • 需求:模拟某企业用户管理业务,需包含用户登录,用户删除,用户查询功能,并要统计每个功能的耗时

  • 分析:

    • 定义一个UserService表示用户业务接口,规定必须完成用户登录,用户删除,用户查询功能。

    • 定义一个实现类UserServiceImpl实现UserService,并完成相关功能,且统计每个功能的耗时。

    • 定义测试类,创建实现类对象,调用方法。

  • 代码实现:

package com.itheima.sh.web;

public interface UserService {

    void login();
    void delete();
    void query();
}
package com.itheima.sh.web;

public class UserServiceImpl implements UserService{
    @Override
    public void login() {
        try {
            long start = System.currentTimeMillis();
            System.out.println("登录");
            Thread.sleep(3000);
            long end = System.currentTimeMillis();
            System.out.println("耗时:"+(end-start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void delete() {
        try {
            long start = System.currentTimeMillis();
            System.out.println("删除");
            Thread.sleep(4000);
            long end = System.currentTimeMillis();
            System.out.println("耗时:"+(end-start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void query() {
        try {
            long start = System.currentTimeMillis();
            System.out.println("查询");
            Thread.sleep(5000);
            long end = System.currentTimeMillis();
            System.out.println("耗时:"+(end-start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.itheima.sh.web;

public class Test01 {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        userService.login();
        userService.delete();
        userService.query();
    }
}
  • 本案例存在哪些问题?

业务对象的的每个方法都要进行性能统计,存在大量重复的代码。

17.代理模式:使用动态代理解决问题介绍

  • 概念

代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的。

  • 关键步骤

    • 1.必须有接口,实现类要实现接口(代理通常是基于接口实现的)。

    • 2.创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。

 

  • 相关API介绍


动态代理API

在java中实现动态代理,关键要使用到一个Proxy类和一个InvocationHandler接口

Proxy类

java.lang.reflect.Proxy:是 Java 动态代理机制的主类(父类),它提供了用于创建动态代理类和实例的静态方法

public static Object newProxyInstance(
                                      ClassLoader loader, 
                                      Class<?>[] interfaces, 
                                      InvocationHandler handle 
                                     ) 
**解释说明:    
- 返回值:     该方法返回就是动态生成的代理对象
- 参数列表说明:
  ClassLoader loader         :定义代理类的类加载器
  Class<?>[] interfaces      :代理类要实现的接口列表,要求与被代理类的接口一样
  InvocationHandler handle   :就是具体实现代理逻辑的接口 
    
    
//参数的应用:
ClassLoader loader     //对象.getClass().getClassLoader()  
           //目标对象通过getClass方法获取类的所有信息后,调用getClassLoader()方法来获取类加载器
           /*获取类加载器后,可以通过这个类型的加载器,在程序运行时,将生成的代理类加载到JVM即Java虚拟机中,以便运行时需要*/ 
    
Class<?>[] interfaces  //对象.getClass().getInterfaces() 
           //获取被代理类的所有接口信息,以便于生成的代理类可以具有代理类接口中的所有方法
    
    
InvocationHandler 
          //用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类方法的处理以及访问  

InvocationHandler接口

java.lang.reflect.InvocationHandler是代理对象的实际处理代理逻辑的接口,具体代理逻辑在其 invoke 方法中实现

public Object invoke(Object proxy, Method method, Object[] args)
**解释说明:
- 返回值:方法被代理后执行的结果
- 参数列表说明:
  Object proxy   :  就是代理对象(通常不使用)
  Method method  :  代理对象调用的方法
  Object[] args  :  被代理方法中的参数 (因为参数个数不定,所以用一个对象数组来表示)
                     如果方法不使用参数,则为 null
    
//所有代理对象调用的方法,执行是都会经过invoke
//因此如果要对某个方法进行代理增强,就可以在这个invoke方法中进行定义    

18.代理模式:使用动态代理解决问题代码实现

package com.itheima.sh.web;

public interface UserService {

    void login();
    void delete();
    void query();
}
package com.itheima.sh.web;

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

public class Test02 {
    public static void main(String[] args) {
        ClassLoader loader = UserService.class.getClassLoader();
        Class[] interfaces = {UserService.class};
        InvocationHandler h = new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Exception{
                String name = method.getName();
                long start = System.currentTimeMillis();
                if("login".equals(name)){
                    //登录
                    System.out.println("登录");
                    Thread.sleep(3000);
                }else if("delete".equals(name)){
                    //删除
                    System.out.println("删除");
                    Thread.sleep(4000);
                }else if("query".equals(name)){
                    //查询
                    System.out.println("查询");
                    Thread.sleep(5000);
                }
                long end = System.currentTimeMillis();
                System.out.println(name+"耗时:"+(end-start));
                return null;
            }
        };
        UserService proxyUserServiceImpl = (UserService) Proxy.newProxyInstance(loader, interfaces, h);
        proxyUserServiceImpl.query();
        proxyUserServiceImpl.login();
        proxyUserServiceImpl.delete();
    }
}

19.代理模式:使用动态代理解决问题代码实现

  • 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接口本身做代理。

  • 可以为被代理对象的所有方法做代理。

  • 可以在不改变方法源码的情况下,实现对方法功能的增强。

  • 不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。

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

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

相关文章

建都寿春的袁术兴亡史

三国(220年-280年)是中国历史上位于汉朝之后&#xff0c;晋朝之前的一段历史时期。这一个时期&#xff0c;先后出现了曹魏、蜀汉、东吴三个主要政权。袁术的地盘很小&#xff0c;为了在三国时期能够立足&#xff1f; 事实上&#xff0c;袁术巅峰时期的地盘并不小&#xff0c;而…

通过IP地理位置阻止网络攻击:有效性与局限性

网络攻击已成为当今互联网世界中的一项常见挑战。黑客和恶意用户利用各种手段对网络系统进行攻击&#xff0c;造成数据泄露、服务中断甚至财产损失。在这种背景下&#xff0c;寻找有效的网络安全解决方案变得至关重要。 IP地理位置阻止是一种基于黑名单的网络安全措施。它的原…

不到2毛钱的IGBT绝缘栅晶体管/MOSFET场效应管栅极驱动器N531

功率开关控制器 较大功率的IGBT或MOSFET都需要外部电流驱动&#xff0c;这个可能和大部分人的想法是不同的&#xff0c;明明它们是电压驱动器件&#xff0c;为什么还要电流驱动&#xff1f;因为这些器件的输入存在CISS等输入电容&#xff0c;需要给它们快速的充电和放电&#…

第一天学C++(C++入门)

一、HelloWorld &#xff08;第一个C入门程序&#xff09; 1.1代码 #include<iostream> using namespace std; // 1.单行注释// 2. 多行注释 /* main 是一个程序的入口 每个程序都必须有这么一个函数 有且仅有一个 */ int main() {// 第九行代码的含义就是在屏幕中输出…

element plus el-date-picker type=“datetime“ 限制年月日 时分秒选择

如何限制el-date-picker组件的时分秒选中&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 文档 文档在这里&#xff1a;DateTimePicker 日期时间选择器 | Element Plus 它提供的disabled-date给我们来限制日期选择 nice&#xff01;&…

【Java学习笔记】9.5 Java中的Lambda表达式

Lambda表达式是从Java8版本开始增加的语法。Lambda表达式有利于实现函数式编程&#xff0c;简化开发。 9.5.1 Lambda表达式入门 Lambda表达式由三部分组成&#xff1a;参数列表、箭头(->),及一个表达式或语句块。其完整的语法格式如下&#xff1a; (Type 1 param1 , Type…

软考133-上午题-【软件工程】-软件项目估算

一、COCOMO 估算模型 COCOMO 模型是一种精确的、易于使用的成本估算模型。 COCOMO 模型按其详细程度分为&#xff1a;基本 COCOMO 模型、中级 COCOMO 模型和详细 COCOMO 模型。 1&#xff09;基本 COCOMO 模型 基本 COCOMO 模型是一个静态单变量模型&#xff0c;用于对整个软…

Java基础 - 10 - IO流(二)

一. IO流 - 字符流 1.1 FileReader&#xff08;文件字符输入流&#xff09; 作用&#xff1a;以内存为基准&#xff0c;可以把文件中的数据以字符的形式读入到内存中去 构造器说明public FileReader(File file)创建字符输入流管道与源文件接通public FileReader(String pathn…

java:基于TCP协议的网络聊天室

基于TCP协议的网络聊天室 简单用java写了一个基于TCP协议的网络聊天室 基本功能 多用户同时在线聊天 收到消息时服务端会向所有在线用户群发消息 用户加入连接和断开连接时会提示 服务端 Socket socket;ArrayList<Socket> list;public ServerThread(Socket socket,…

使用Docker,【快速】搭建个人博客【WordPress】

目录 1.安装Mysql&#xff0c;创建&#xff08;WordPress&#xff09;用的数据库 1.1.安装 1.2.创建数据库 2.安装Docker 3.安装WodPress&#xff08;使用Docker&#xff09; 3.1.创建文件夹 3.2.查看镜像 3.3.获取镜像 3.4.查看我的镜像 3.5.使用下载的镜像&#xf…

产品创新领域中的生产率:以新产品销售额与研发支出的关系为视角

一、摘要 在当今日新月异的商业环境中&#xff0c;产品创新已成为企业获取竞争优势、实现持续增长的关键因素。而如何衡量产品创新的成效&#xff0c;即产品创新的生产率&#xff0c;则是众多企业所关注的焦点。本文将探讨产品创新领域中的生产率概念&#xff0c;并以新产品销…

Windows的Tensorrt的安装

Tensorrt的下载 确定自己的CUDA版本,匹配的去下载Tensorrt。 Tensorrt的下载 下载完成之后,直接解压到文件夹即可。 环境变量配置 最重要的一部就是环境变量的配置。 官方的安装指导文件给出了两种方法: (1)要么直接将/lib 添加到环境变量 PATH 中 (诶,windows没有LD_L…

时序预测 | Transformer时间序列预测 Matlab代码

文章目录 效果一览文章概述源码设计参考资料 效果一览 文章概述 1.时序预测 | Transformer时间序列预测 Matlab代码 2.单变量时间序列预测&#xff1b; 3.多指标评价&#xff0c;评价指标包括&#xff1a;R2、MAE、MBE等&#xff0c;代码质量极高&#xff1b; 4.excel数据&…

QTableView获取可见的行数

场景 当我们需要实时刷新QTableView时&#xff0c;而此时tableView的数据量较大&#xff0c;如果全部刷新显然不合理&#xff0c;如果可以只对用户看的到的数据进行刷新那就最好了&#xff0c;经过一番摸索找到了几种方式&#xff0c;可供参考 代码 方法1 QVector<int>…

护眼台灯怎么选看哪些指标?五款性价比高的照明品牌综合对比

鉴于儿童近视率的不断攀升&#xff0c;为孩子打造一个优质的学习环境变得愈发关键。在这其中&#xff0c;护眼台灯无疑占据了举足轻重的地位。那么&#xff0c;护眼台灯怎么选看哪些指标&#xff1f;本文将详尽解析与护眼台灯密切相关的核心指标&#xff0c;帮助大家在选购时能…

数据结构中的顺序表的删除和查找

对于顺序表&#xff0c;它包括&#xff1a;初始化&#xff0c;取值&#xff0c;查找&#xff0c;插入&#xff0c;以及删除。接下来就讲一讲删除和查找。 删除&#xff1a;它包括头删和尾删&#xff0c;为什么顺序表中要用到删除呢&#xff1f;按我的理解就是&#xff1a;为插入…

Linux服务器硬件及RAID配置

一、服务器硬件 塔式服务器&#xff1a;最初的服务器形态之一&#xff0c;类似于传统的台式电脑&#xff0c;但具有更强的处理能力和稳定性&#xff0c;适合小型企业或部门使用。 机架式服务器&#xff1a;设计为可安装在标准化机架内的模块化单元&#xff0c;可以有效地节省空…

上位机图像处理和嵌入式模块部署(树莓派4b固件功能设计)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们说过&#xff0c;上位机的功能都是基于插件进行开发的。但是上位机的成本比较贵&#xff0c;一般的企业不一定愿意接接受。这个时候另外一…

Notion 开源替代品 AFFINE 部署和使用教程

AFFiNE 是一款完全开源的 Notion Miro 替代品&#xff0c;与 Notion 相比&#xff0c;AFFiNE 更注重隐私安全&#xff0c;优先将笔记内容保存到本地。 GitHub 地址&#xff1a;https://github.com/toeverything/AFFiNE AFFiNE 使用 Rust 和 Typescript 构建&#xff0c;只需…

重生奇迹mu怎么卡智力的方法

1、准备3个号A打手,B智力MM,C随意。 2、使用C匹配组队,但是不能选择自动进入队伍。 3、用A申请C的队伍,但是C不做通过处理。 4、用A组B,用快捷键D的方式。 5、所谓的卡智力就是智力MM可以给打手加属性加血&#xff0c;但是并不在一个队伍里享受经验&#xff0c;适用于MM不是…