JavaSE高阶篇-反射

第一部分、Junit单元测试

1)介绍

1.概述:Junit是一个单元测试框架,在一定程度上可以代替main方法,可以单独去执行一个方法,测试该方法是否能跑通,但是Junit是第三方工具,所以使用之前需要导入jar包

2)Junit的基本使用(重点啊)

1.导入Junit的jar包
2.定义一个方法,在方法上写注解:  @Test
3.执行方法:
  a.点击该方法左边的绿色按钮,点击run执行 -> 单独执行一个指定的方法
  b.如果想要执行所有带@Test的方法,点击类名左边绿色按钮,点击run执行-> 执行当前类中所有@Test的方法

public class Demo01Junit {
    @Test
   public void add(){
       System.out.println("我是@Test执行的add方法");
   }

   @Test
   public void delete(){
       System.out.println("我是@Test执行的delete方法");
   }
}

 3)Junit的注意事项

1.@Test不能修饰static方法
2.@Test不能修饰带参数方法
3.@Test不能修饰带返回值方法 

 4)Junit的相关注解

@Before:在@Test之前执行,有多少个@Test执行,@Before就执行多少次 -> 一般都是用作初始化变量
@After:在@Test之后执行,有多少个@Test执行,@After就执行多少次   -> 一般可以用作关闭资源

public class Demo01Junit {
    @Test
    public void add() {
        System.out.println("我是@Test执行的add方法");
    }

    @Test
    public void delete() {
        System.out.println("我是@Test执行的delete方法");
    }

    @Before
    public void methodBefore() {
        System.out.println("我是@Before执行的方法");
    }

    @After
    public void methodAfter() {
        System.out.println("我是@After执行的方法");
    }
}

5)@Test以后怎么使用

/**
 * 此类专门去测我们写好的功能
 */
public class Demo02Junit {
   /* public static void main(String[] args) {
        CategoryController cc = new CategoryController();
        int result = cc.add("蔬菜");
        System.out.println("result = " + result);

        List<String> list = cc.findAllCategory();
        System.out.println(list);
    }*/

    /**
     * 此方法专门测添加功能
     */
    @Test
    public void add(){
        CategoryController cc = new CategoryController();
        int result = cc.add("蔬菜");
        System.out.println("result = " + result);
    }

    /**
     * 此方法专门测查找功能
     */
    @Test
    public void find(){
        CategoryController cc = new CategoryController();
        List<String> list = cc.findAllCategory();
        System.out.println(list);
    }
}
public class CategoryController {
    /**
     * 添加功能
     */
    public int add(String categoryName){
        ArrayList<String> list = new ArrayList<>();
        list.add(categoryName);
        return 1;//如果返回一个1,证明添加成功了
    }

    /**
     * 查找功能
     */
    public List<String> findAllCategory(){
        ArrayList<String> list = new ArrayList<>();
        list.add("蔬菜");
        list.add("水果");
        list.add("服装");
        list.add("电器");
        list.add("玩具");
        list.add("手机");
        return list;
    }
}

 扩展注解:

@BeforeClass:在@Test之前执行,只执行一次,可以修饰静态方法

@AfterClass:在@Test之后执行,只执行一次,可以修饰静态方法

public class Demo03Junit {
 @Test
 public void add() {
     System.out.println("我是@Test执行的add方法");
 }

 @Test
 public void delete() {
     System.out.println("我是@Test执行的delete方法");
 }

 @BeforeClass
 public static void methodBefore() {
     System.out.println("我是@Before执行的方法");
 }

 @AfterClass
 public static void methodAfter() {
     System.out.println("我是@After执行的方法");
 }
}

 第二部分、类的加载时机

1.new对象
2.new子类对象(new子类对象先初始化父类)
3.执行main方法
4.调用静态成员
5.反射,创建Class对象   

1.类加载器(了解)_ClassLoader

1.概述:
   在jvm中,负责将本地上的class文件加载到内存的对象_ClassLoader
2.分类:
   BootStrapClassLoader:根类加载器->C语言写的,我们是获取不到的
                        也称之为引导类加载器,负责Java的核心类加载的
                        比如:System,String等
                        jre/lib/rt.jar下的类都是核心类
   ExtClassLoader:扩展类加载器
                  负责jre的扩展目录中的jar包的加载
                  在jdk中jre的lib目录下的ext目录
   AppClassLoader:系统类加载器
                  负责在jvm启动时加载来自java命令的class文件(自定义类),以及classPath环境变量所指定的jar包(第三方jar包)
        
    不同的类加载器负责加载不同的类
       
3.三者的关系(从类加载机制层面):AppClassLoader的父类加载器是ExtClassLoader
            ExtClassLoader的父类加载器是BootStrapClassLoader
 
  但是:他们从代码级别上来看,没有子父类继承关系->他们都有一个共同的父类->ClassLoader

4.获取类加载器对象:getClassLoader()是Class对象中的方法
  类名.class.getClassLoader()
 
5.获取类加载器对象对应的父类加载器
  ClassLoader类中的方法:ClassLoader      
  getParent()->没啥用
      
6.双亲委派(全盘负责委托机制)

   a.Person类中有一个String
     Person本身是AppClassLoader加载
     String是BootStrapClassLoader加载
   b.加载顺序:
     Person本身是App加载,按道理来说String也是App加载
     但是App加载String的时候,先问一问Ext,说:Ext你加载这个String吗?
     Ext说:我不加载,我负责加载的是扩展类,但是app你别着急,我问问我爹去->boot
     Ext说:boot,你加载String吗?
     boot说:正好我加载核心类,行吧,我加载吧!
         
   =======================================================================
         
    比如:
      class Test{
          new Person()
      }

    a.Test是app加载,person按理来说也是app加载,但是app先问ext要不要加载
      ext说不负责加载自定义类,我找boot去,boot一看,我不负责加载自定义类->perosn
      app一看,两个爹都不加载,我自己加载
      
    b.结论:当一个类加载器加载类的时候,总会先去上一级问一问,问上一级要不要加载,如果上级不加载,才自己加载
    
    =======================================================================
7.类加载器的cache(缓存)机制(扩展):一个类加载到内存之后,缓存中也会保存一份儿,后面如果再使用此类,如果缓存中保存了这个类,就直接返回他,如果没有才加载这个类.下一次如果有其他类在使用的时候就不会重新加载了,直接去缓存中拿,保证了类在内存中的唯一性
     
8.所以:类加载器的双亲委派和缓存机制共同造就了加载类的特点:保证了类在内存中的唯一性   

 

public class Demo01ClassLoader {
    public static void main(String[] args) {
        app();
        //ext();
        //boot();
    }

    /**
     * 负责加载核心类
     * BootStrapClassLoader:C语言编写,我们是获取不到的
     */
    private static void boot() {
        ClassLoader classLoader = String.class.getClassLoader();
        System.out.println("classLoader = " + classLoader);
    }

    /**
     * 负责加载扩展类
     */
    private static void ext() {
        ClassLoader classLoader = DNSNameService.class.getClassLoader();
        System.out.println("classLoader = " + classLoader);
    }

    /**
     * 负责加载自定义类
     */
    private static void app() {
        ClassLoader classLoader = Demo01ClassLoader.class.getClassLoader();
        System.out.println("classLoader = " + classLoader);

        ClassLoader parent = classLoader.getParent();
        System.out.println("parent = " + parent);

        ClassLoader parent1 = parent.getParent();
        System.out.println("parent1 = " + parent1);//null
    }
}

 第三部分、反射

1)class类的以及class对象的介绍以及反射介绍

1.反射:是一种解剖class对象的技术
2.能解剖出点啥来?
   a.成员变量 -> 赋值取值
   b.构造方法 -> new对象
   c.成员方法 -> 调用执行

3.反射的作用:写出来的代码更灵活,通用
4.怎么学反射:先把反射技术看成是一套纯API来学
   根据涛哥设计的案例去体会反射代码的通用性

5.反射是解剖class对象的,所以玩儿反射第一步要干啥?
   获取class对象
    
    
6.class对象:class文件对应的对象
  class类:描述class对象的类叫做class类

 2)反射之获取Class对象

1.方式1:调用Object中的getClass()方法:
        Class<?> getClass()
            
2.方式2:不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class
    
3.方式3:Class类中的静态方法:
       static Class<?> forName(String className)  
                               className:类的全限定名(包名.类名)

public class Person {
    private String name;
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    //私有构造
    private Person(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 

public class Test01 {
    public static void main(String[] args)throws Exception {
        /*
          1.方式1:调用Object中的getClass()方法:
                  Class<?> getClass()
         */
        Person person = new Person();
        Class aClass = person.getClass();
        System.out.println("aClass = " + aClass);

        System.out.println("===================");

        //2.方式2:不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class
        Class<Person> aClass1 = Person.class;
        System.out.println("aClass1 = " + aClass1);

        System.out.println("===================");

        /*
         3.方式3:Class类中的静态方法:
               static Class<?> forName(String className)
                               className:类的全限定名(包名.类名)
         */
        Class<?> aClass2 = Class.forName("com.atguigu.c_reflect.Person");
        System.out.println("aClass2 = " + aClass2);

        System.out.println("===================");

        //System.out.println(aClass1==aClass2);

    }
}

三种获取Class对象的方式最通用的一种

1.static Class<?> forName(String className)  
                               className:类的全限定名(包名.类名)
2.原因:参数为String形式,可以和Properties文件结合使用

 

className=com.atguigu.c_reflect.Student
public class Test02 {
    public static void main(String[] args)throws Exception {
        Properties properties = new Properties();
        FileInputStream in = new FileInputStream("day22_reflect\\pro.properties");
        properties.load(in);

        String className = properties.getProperty("className");

        Class<?> aClass = Class.forName(className);
        System.out.println("aClass = " + aClass);
    }
}

 3)获取Class对象中的构造方法

(1)获取所有public中的构造方法

1.Class类中的方法:
  Constructor<?>[] getConstructors() -> 获取的所有public的构造

public class Test02 {
    public static void main(String[] args)throws Exception {
        Properties properties = new Properties();
        FileInputStream in = new FileInputStream("day22_reflect\\pro.properties");
        properties.load(in);

        String className = properties.getProperty("className");

        Class<?> aClass = Class.forName(className);
        System.out.println("aClass = " + aClass);
    }
}

(2)获取空参构造_public

1.Class类中的方法:
  Constructor<T> getConstructor(Class<?>... parameterTypes)->获取指定的public的构造
                                parameterTypes:可变参数,可以传递0或多个参数
 
  a.如果获取的是空参构造:参数不用写
  b.如果获取的是有参构造:参数写参数类型的class对象
      
2.Constructor类中的方法:
  T newInstance(Object... initargs)  -> 创建对象
               initargs:传递的是构造方法的实参
                
  a.如果根据空参构造new对象,initargs不写了
  b.如果根据有参构造new对象,initargs传递实参

public class Test03_GetConstructor {
    public static void main(String[] args) throws Exception {
        Class<Person> personClass = Person.class;
        Constructor<Person> constructor = personClass.getConstructor();
        System.out.println("constructor = " + constructor);
        /*
          好比是: Person person = new Person();
         */
        Person person = constructor.newInstance();

        //好比是:直接输出对象名,默认调用toString
        System.out.println(person);
    }
}

 (3)利用空参构造创建对象的快捷方式_public

Class类中的方法:
  T newInstance()   ->  根据空参构造new对象
      
前提:被反射的类中必须有public的空参构造  

public class Test04_GetConstructor {
    public static void main(String[] args) throws Exception {
        Class<Person> personClass = Person.class;
        Person person = personClass.newInstance();
        System.out.println(person);
    }
}

(4)利用反射获取有参构造并创建对象_public

1.Class类中的方法:
  Constructor<T> getConstructor(Class<?>... parameterTypes)->获取指定的public的构造
                                parameterTypes:可变参数,可以传递0或多个参数
 
  a.如果获取的是空参构造:参数不用写
  b.如果获取的是有参构造:参数写参数类型的class对象
      
2.Constructor类中的方法:
  T newInstance(Object... initargs)  -> 创建对象
               initargs:传递的是构造方法的实参
                
  a.如果根据空参构造new对象,initargs不写了
  b.如果根据有参构造new对象,initargs传递实参

public class Test05_GetConstructor {
    public static void main(String[] args) throws Exception {
        Class<Person> class1 = Person.class;
        Constructor<Person> constructor = class1.getConstructor(String.class, Integer.class);
        System.out.println("constructor = " + constructor);

        /*
           好比是:Person person = new Person("柳岩",36);
         */
        Person person = constructor.newInstance("柳岩", 36);

        //好比是直接输出Person对象,默认调用toString
        System.out.println(person);
    }
}

(5)利用反射获取私有构造(暴力反射)

1.Constructor<?>[] getDeclaredConstructors()  -> 获取所有构造方法,包括private和public
2.Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) -> 获取指定构造,包括private和public
               parameterTypes:参数类型的class对象
                   
                   
3.Constructor有一个父类叫做AccessibleObject,里面有一个方法:
  void setAccessible(boolean flag) -> 修改访问权限
                     flag为true-> 解除私有权限

public class Test06_GetConstructor {
    public static void main(String[] args) {
        Class<Person> personClass = Person.class;
        Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
    }
}
public class Test07_GetConstructor {
    public static void main(String[] args)throws Exception {
        Class<Person> personClass = Person.class;
        Constructor<Person> ds = personClass.getDeclaredConstructor(String.class);

        //解除私有权限 -> 暴力反射
        ds.setAccessible(true);

        Person person = ds.newInstance("曼曼");
        System.out.println(person);
    }
}

4)反射方法

(1)利用反射获取所有成员方法_public

1.Class类中的方法:
  Method[] getMethods() -> 获取所有的public的方法,包括父类中的public方法

public class Test08_GetMethod {
    public static void main(String[] args) {
        Class<Person> personClass = Person.class;
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}

(2)反射之获取方法(有参,无参)

1.Class类中的方法:
  Method getMethod(String name, Class<?>... parameterTypes)->获取指定的public的成员方法
                   name:传递方法名
                   parameterTypes:方法参数类型的class对象
                       
2.Method中的方法:
  Object invoke(Object obj, Object... args)  -> 执行方法
                obj:根据构造new出来的对象
                args:方法实参
                    
                返回值:Object -> 接收被执行方法的返回值的,如果方法没有返回值,不用接收了   

public class Test09_GetMethod {
    public static void main(String[] args)throws Exception {
        Class<Person> personClass = Person.class;
        Person person = personClass.newInstance();
        Method setName = personClass.getMethod("setName", String.class);

        /*
          相当于:person.setName("柳岩")
         */
        setName.invoke(person,"柳岩");
        System.out.println(person);

        System.out.println("================================================");

        Method getName = personClass.getMethod("getName");

        //好比是:Object o = person.getName()
        Object o = getName.invoke(person);
        System.out.println("o = " + o);
    }
}

反射小练习

<select id="findAll" class="类的全限定名">
     select * from 表名
</select>

public List<泛型类型> findAll();

 需求:在配置文件中,配置类的全限定名,以及方法名,通过解析配置文件,让配置好的方法执行起来
     className=com.atguigu.d_reflect.Person
     methodName=eat
    
步骤:
  1.创建properties配置文件,配置信息
    a.问题:properties配置文件放到哪里?
          将来我们开发完之后我们给用户的是out路径下的class文件,如果将配置文件直接放到模块下,那么out路径下是不会生成配置文件的,如果没有配置文件,程序也运行不起来
          所以我们将配置文件可以放到src下,放到src下,out路径下就会自动生成配置文件
        
    b.问题:将配置文件放到src下,out路径下会自动生成该配置文件,但是如果我们将所有的配置文件都放到src下,那么src会显得非常乱
          所以我们可以单独去创建一个文件夹,将所有配置文件放到此文件夹下,将此文件夹改成资源目录resources
         
  2.读取配置文件,解析配置文件
    a.问题:如果将配置文件放到resources资源目录下,我们怎么读取
      new FileInputStream("模块名\\resources\\properties文件名")-> 这样不行,out下没有resources
        
    b.问题解决:用类加载器
      ClassLoader classLoader = 当前类.class.getClassLoader()
      InputStream in = classLoader.getResourceAsStream("文件名称"); //自动扫描resource下的文件(可以简单理解为扫描out路径下的配置文件)     
          
  3.根据解析出来的className创建class对象
  4.根据解析出来的methodName,获取对应的方法
  5.执行方法

className=com.atguigu.d_reflect.Person
methodName=eat

 

public class Test01 {
    public static void main(String[] args)throws Exception {
        //1.创建Properties集合
        Properties properties = new Properties();
        //2.读取配置文件
        InputStream in = Test01.class.getClassLoader().getResourceAsStream("pro.properties");
        //3.将流中的数据加载到集合中
        properties.load(in);
        //4.获取读取到的配置文件中的信息
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");
        //5.根据className获取class对象
        Class<?> aClass = Class.forName(className);
        Object o = aClass.newInstance();
        //6.根据methodName获取方法
        Method method = aClass.getMethod(methodName);
        //7.执行被反射出来的方法
        method.invoke(o);
    }
}

第四部分、注解

1)注解的基本介绍

1.引用数据类型:
  类 数组 接口 枚举 注解
      
1.jdk1.5版本的新特性->一个引用数据类型
       和类,接口,枚举是同一个层次的
     
       引用数据类型:类 数组  接口 枚举 注解
2.作用:
        说明:对代码进行说明,生成doc文档(API文档)
        检查:检查代码是否符合条件   @Override(会用) @FunctionalInterface
        分析:对代码进行分析,起到了代替配置文件的作用(会用)
3.JDK中的注解:
        @Override  ->  检测此方法是否为重写方法
           jdk1.5版本,支持父类的方法重写
           jdk1.6版本,支持接口的方法重写
        @Deprecated -> 方法已经过时,不推荐使用
                       调用方法的时候,方法上会有横线,但是能用
        @SuppressWarnings->消除警告  @SuppressWarnings("all")     

public class Person {
    @Deprecated
    public void eat(){
        System.out.println("人要干饭");
    }
}
@SuppressWarnings("all")
public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.eat();

        System.out.println("=================");

        ArrayList list = new ArrayList();
        list.add("1");
    }
}

2)注解的定义以及属性的定义格式

1.定义:
  public @interface 注解名{
      
  }

2.定义属性:增强注解的作用
  数据类型 属性名() -> 此属性没有默认值,需要在使用注解的时候为其赋值
  数据类型 属性名() default 值 -> 此属性有默认值,如果有需要,也可以二次赋值
 
3.注解中能定义什么类型的属性呢?
  a.8种基本类型
  b.String类型,class类型,枚举类型,注解类型  
  c.以上类型的一维数组   

public @interface Book {
    //书名
    String bookName();
    //作者
    String[] author();
    //价格
    double price();
    //数量
    int count() default 10;
}

 3)注解的使用(重点)

1.注解的使用:
  说白了就是为注解中的属性赋值
2.使用位置上:
  在类上使用,方法上使用,成员变量上使用,局部变量上使用,参数位置使用等
3.使用格式:
  a.@注解名(属性名 = 值,属性名 = 值...)
  b.如果属性中有数组:
    @注解名(属性名 = {元素1,元素2})

public @interface Book {
    //书名
    String bookName();
    //作者
    String[] author();
    //价格
    double price();
    //数量
    int count() default 10;
}
@Book(bookName = "金瓶梅",author = {"涛哥","金莲"},price = 9.9,count = 200)
public class BookShelf {
    
}
注解注意事项:
      1.空注解可以直接使用->空注解就是注解中没有任何的属性
      2.不同的位置可以使用一样的注解,但是同样的位置不能使用一样的注解
      3.使用注解时,如果此注解中有属性,注解中的属性一定要赋值,如果有多个属性,用,隔开
        如果注解中的属性有数组,使用{}
      4.如果注解中的属性值有默认值,那么我们不必要写,也不用重新赋值,反之必须写上
      5.如果注解中只有一个属性,并且属性名叫value,那么使用注解的时候,属性名不用写,直接写值
        (包括单个类型,还包括数组)

4)注解解析的方法->AnnotatedElement接口

1.注解解析涉及的接口:
  AnnotatedElement接口:
   实现类:AccessibleObject, Class, Constructor, Field, Method
       
2.解析思路:  先判断指定位置上有没有使用指定的注解,如果有,获取指定的注解,获取注解中的属性值
  a.boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)->判断指定位置上有没有指定的注解
    
    比如:判断BookShelf上有没有Book注解
        Class bookShelf = BookShelf.class
        bookShelf.isAnnotationPresent(Book.class)  
            
  b.getAnnotation(Class<T> annotationClass)-> 获取指定的注解
    比如:获取BookShelf上的Book注解
        Class bookShelf = BookShelf.class
        boolean result = bookShelf.isAnnotationPresent(Book.class)
        Book book = bookShelf.getAnnotation(Book.class) 

public @interface Book {
    //书名
    String bookName();
    //作者
    String[] author();
    //价格
    double price();
    //数量
    int count() default 10;
}
@Book(bookName = "金瓶梅", author = {"涛哥", "金莲"}, price = 9.9, count = 200)
public class BookShelf {
}
public class Test01 {
    public static void main(String[] args) {
        Class<BookShelf> bookShelfClass = BookShelf.class;
        boolean b = bookShelfClass.isAnnotationPresent(Book.class);
        //System.out.println(b);
        if (b){
            Book book = bookShelfClass.getAnnotation(Book.class);
            System.out.println(book.bookName());
            System.out.println(Arrays.toString(book.author()));
            System.out.println(book.price());
            System.out.println(book.count());
        }
    }
}

以上代码没解析出来:

涛哥猜想:如果Book注解被加载到内存中了,那么我们一定是能判断出来BookShelf上有没有Book注解的,但是现在没有判断出来,但是 BookShelf上确实用了Book注解了,所以涛哥猜想,Book注解有可能就没有在内存中出现

第五部分、元注解

1.概述:元注解是管理注解的注解
2.从哪些方面管理呢?
  a.控制自定义注解的使用位置
    控制自定义注解是否能在类中使用
    控制自定义注解是否能在方法上使用
    控制自定义注解是否能在成员变量上使用等
    
  b.控制自定义注解的生命周期(加载位置):
    控制自定义注解是否能在源码中出现
    控制自定义注解是否能在class文件中出现
    控制自定义注解是否能在内存中出现
        
3.怎么使用:
  a.@Target:控制自定义注解的使用位置
            属性:ElementType[] value();
                ElementType是一个枚举,里面的枚举类型可以类名直接调用
            ElementType中的枚举:
                TYPE:控制注解能使用在类上
                FIELD:控制注解能使用在属性上
                METHOD:控制注解能使用在方法上
                PARAMETER:控制注解能使用在参数上
                CONSTRUCTOR:控制注解能使用在构造上
                LOCAL_VARIABLE:控制注解能使用在局部变量上    
                    
  b.@Retention:控制自定义注解的生命周期(加载位置)
               属性:RetentionPolicy value()
                   RetentionPolicy是一个枚举类,里面的枚举可以类名直接调用
               RetentionPolicy中的枚举:
                   SOURCE:控制注解能在源码中出现  -> 默认
                   CLASS:控制注解能在class文件中出现    
                   RUNTIME:控制注解能在内存中出现   

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
    //书名
    String bookName();
    //作者
    String[] author();
    //价格
    double price();
    //数量
    int count() default 10;
}

注解再次解析(成功了)

public class Test01 {
    public static void main(String[] args) {
        Class<BookShelf> bookShelfClass = BookShelf.class;
        boolean b = bookShelfClass.isAnnotationPresent(Book.class);
        //System.out.println(b);
        if (b){
            Book book = bookShelfClass.getAnnotation(Book.class);
            System.out.println(book.bookName());
            System.out.println(Arrays.toString(book.author()));
            System.out.println(book.price());
            System.out.println(book.count());
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【jinja2】模板渲染

HTML文件 return render_template(index.html)h1: 一级标题 变粗变大(狗头 <

VSCode断点调试(ROS)

0、安装ros插件 在扩展商店中安装ROS插件&#xff08;Microsoft&#xff09; 1、修改CMakeList.txt # set(CMAKE_BUILD_TYPE "Release") // 注释Release模式 set(CMAKE_BUILD_TYPE "Debug") // 设置为Debug模式 # set(CMAKE_CXX_FLAGS_RELEASE &…

PolarDB MySQL 版 Serverless评测|一文带你体验什么是极致弹性

PolarDB MySQL 版 Serverless评测|一文带你体验什么是极致弹性 什么是PolarDB MySQL 版PolarDB MySQL版体验弹性压测一弹性压测二弹性压测三弹性缩容 操作体验 在体验PolarDB MySQL 版之前&#xff0c;这里先为大家提供一下PolarDB MySQL 版 Serverless评测入口&#xff0c;以供…

五种主流数据库:集合运算

关系型数据库中的表与集合理论中的集合类似&#xff0c;表是由行&#xff08;记录&#xff09;组成的集合。因此&#xff0c;SQL 支持基于数据行的各种集合运算&#xff0c;包括并集运算&#xff08;Union&#xff09;、交集运算&#xff08;Intersect&#xff09;和差集运算&a…

neo4j使用详解(十八、java driver使用及性能优化<高级用法>——最全参考)

Neo4j系列导航&#xff1a; neo4j安装及简单实践 cypher语法基础 cypher插入语法 cypher插入语法 cypher查询语法 cypher通用语法 cypher函数语法 neo4j索引及调优 neo4j java Driver等更多 1.依赖引入 <dependency><groupId>org.neo4j.driver</groupId><…

线程池 ThreadPoolExecutor 配置参数详解

《开发语言-Java》 线程池 ThreadPoolExecutor 参数详解 一、引言二、主要内容2.1 核心构造函数2.2 核心线程数2.3 最大线程数2.4 空闲线程存活时间2.5 keepAliveTime 的时间单位2.6 核心线程在空闲时的回收策略2.7 工作队列2.8 线程工厂2.9 拒绝策略 三、总结 一、引言 提到 …

密码学 | 承诺:基本概念

目录 正文 1 承诺的交互 2 承诺的属性 3 硬币抛掷问题 3.1 朴素版方案 3.2 承诺版方案 &#x1f951;源自&#xff1a;https://en.wikipedia.org/wiki/Commitment_scheme &#x1f951;写在前面&#xff1a;英文的承诺是 commitment scheme&#xff0c;否则很难进行…

项目实践---贪吃蛇游戏(游戏的概述)

这里要准备三个文件&#xff1a;1.头文件&#xff08;snake.h&#xff09; 2.测试文件&#xff08;test.c&#xff09; 3.主文件&#xff08;snake.c&#xff09; 贪吃蛇游戏是一个经典的C语言代码实现的项目&#xff0c;大约500行代码。对于大家来说&#xff0c;贪吃蛇都玩过…

如何用个人电脑搭建一台本地服务器,并部署项目到服务器详细教程

服务器是一种高性能计算机&#xff0c;作为网络的节点&#xff0c;它存储、处理网络上80%的数据、信息&#xff0c;因此也被称为网络的灵魂。与普通计算机相比&#xff0c;服务器具有高速CPU运算能力、长时间可靠运行、强大I/O外部数据吞吐能力以及更好的扩展性。 服务器的主要…

【QT进阶】Qt Web混合编程之html、 js的简单交互

往期回顾 【QT进阶】Qt Web混合编程之VS2019 CEF的编译与使用&#xff08;图文并茂超详细介绍&#xff09;-CSDN博客【QT进阶】Qt Web混合编程之QWebEngineView基本用法-CSDN博客【QT进阶】Qt Web混合编程之CMake VS2019编译并使用QCefView&#xff08;图文并茂超详细版本&…

NSSCTF Round#22 Reverse个人专项赛 WP

1. ezcrypt&#xff08;史&#xff09; pyinstxtractor.py解包exe&#xff0c;然后pycdc反编译NSSCTF.pyc 得到的源码并不完整&#xff0c;但是重要的部分已经有了&#xff0c;就是一个blowfish加密 但是密钥是crypto.SomeEncode&#xff0c;这并不是字面意义的字符串&#x…

基于弹簧鞘复合纱和迁移学习算法的可穿戴人体重构和智能试衣系统

研究背景 在信息时代和元宇宙的背景下&#xff0c;虚拟服装设计对满足服装行业的个性化需求至关重要。与传统方法不同&#xff0c;虚拟试衣节省时间、方便客户&#xff0c;并提供多样化的款式。准确得测量人体围度并重构出人体的模型是虚拟试衣的关键。为了实现动态人体重构&a…

路径规划 | RRT结合APF算法快速探索随机树结合人工势场法的路径规划算法(Matlab)

目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 RRT结合APF算法的matlab代码。地图为可以替换的栅格地图。代码是在复现华中科技大学发表的英文论文的基础上的进一步改进。RRT算法。人工势场算法。 1.原论文方法简介&#xff1a;针对快速探索随机树&#xff08;RRT&…

用 Pytorch 训练一个 Transformer模型

昨天说了一下Transformer架构&#xff0c;今天我们来看看怎么 Pytorch 训练一个Transormer模型&#xff0c;真实训练一个模型是个庞大工程&#xff0c;准备数据、准备硬件等等&#xff0c;我只是做一个简单的实现。因为只是做实验&#xff0c;本地用 CPU 也可以运行。 本文包含…

C++ STL 容器 vector

目录 1. vector 对象2. vector 大小 size 和 容量 capacity3. vector 成员函数3.1 迭代器3.2 容量3.3 元素访问3.4 插入3.5 删除3.6 动态扩充与收缩 4. vector 迭代器失效问题总结其他补充 本文测试环境为 编译器 gcc 13.1 vector 是 STL 中的一个顺序容器&#xff0c;它给我们…

如何将静态网页资源“打包“成.exe或者.apk

Hello , 我是小恒不会java。最近有音乐播放器win桌面应用程序的需求&#xff0c;那就说说上手electron 又想到很多人对apk文件不太了解&#xff0c;apk文件就是安卓桌面应用程序&#xff0c;比如你手机现在打开的微信 当然&#xff0c;exe文件基本都清楚&#xff0c;windows可执…

正则表达式(Regular Expression)

正则表达式很重要&#xff0c;是一个合格攻城狮的必备利器&#xff0c;必须要学会&#xff01;&#xff01;&#xff01; &#xff08;参考视频&#xff09;10分钟快速掌握正则表达式&#xff08;奇乐编程学院&#xff09;https://www.bilibili.com/video/BV1da4y1p7iZ在线测试…

React Hooks(常用)笔记

一、useState&#xff08;保存组件状态&#xff09; 1、基本使用 import { useState } from react;function Example() {const [initialState, setInitialState] useState(default); } useState(保存组件状态) &#xff1a;React hooks是function组件(无状态组件) &#xf…

再拓信创版图-Smartbi 与东方国信数据库完成兼容适配认证

近日&#xff0c;思迈特商业智能与数据分析软件 [简称&#xff1a;Smartbi Insight] V11与北京东方国信科技股份有限公司 &#xff08;以下简称东方国信&#xff09;CirroData-OLAP分布式数据库V2.14.1完成兼容性测试。经双方严格测试&#xff0c;两款产品能够达到通用兼容性要…

浪潮信息成功打造大规模、高性能、高可靠的单存储集群方案!

为帮助企业应对商业智能应用中面临的关于海量数据存储及实时分析的难题&#xff0c;浪潮信息日前通过技术研发&#xff0c;创新推出全球首个SAP HANA集群方案&#xff0c;该方案实现了最大可支持HANA集群服务器节点数量的翻倍&#xff0c;单存储即可支持16节点的&#xff0c;大…
最新文章