Skip to content

day21.反射_注解

java
课前回顾:
  1.FileOutputStream:字节输出流
    a.构造: FileOutputStream(String path)
           FileOutputStream(String path,boolean flag) 续写追加
    b.方法: write方法
  2.FileInputStream:字节输入流
    a.构造:FileInputStream(String path)
    b.方法: read
  3.FileWriter:字符输出流
    a.构造:FileWriter(String path)
    b.方法:write
    c.特有方法:flush
  4.FileReader:字符输入流
    a.构造:FileReader(String path)
    b.read
  5.ObjectOutputStream:序列化流
    a.构造:ObjectOutputStream(OutputStream os)
    b.方法:writeObject()
  6.ObjectInputStream:反序列化流
    a.构造:ObjectInputStream(InputStream is)
    b.方法:readObject()
  7.PrintStream:打印流
    a.构造:PrintStream(String path)
    b.println
      print

  8.Properties:属性集
    load(InputStream in) 将流中的数据加载到properties集合中
    解析配置文件

今日重点:
  1.知道客户端和服务端之间的交互过程
  2.会利用反射操作构造,方法,属性
  3.体会反射的好处 -> 根据涛哥准备的练习
  4.会使用注解

第一章.网编相关知识点说明

java
1.概述:在一定的协议下,完成数据的传输的技术  -> 网络编程
2.场景:
  聊天   网游
  只要是在一定协议下进行的网络传输,都会有网编的存在

1.软件结构

  • C/S 结构 :全称为 Client/Server 结构,是指客户端和服务器结构。常见程序有QQ、红蜘蛛、飞秋等软件。
1744102968813

B/S 结构 :全称为 Browser/Server 结构,是指浏览器和服务器结构。常见浏览器有 IE、谷歌、火狐等。

1744102977988

两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机的通信的程序。

2.服务器概念

java
1.概述:安装了服务器软件的计算机

网络通信协议:两台计算机在做数据交互时要遵守的规则,协议会对数据的格式,速率等进行规定,只有都遵守了这个协议,才能完成数据交互

两台计算机想完成数据交互,需要遵守网络通信协议

1744333725410

3.通信三要素

java
[IP地址]:计算机的唯一标识,用于两台计算机之间的连接

      a.概述:指互联网协议地址(Internet Protocol Address),俗称IP
            计算机的唯一标识
      b.作用:可用于计算机和计算机之间的连接
      c.IPV4
        32位的二进制数,通常被分为4个字节,表示成a.b.c.d 的形式,例如192.168.65.100 。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个。
        IPV6
        为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789->号称能给地球上的每一粒沙子分配一个IP地址

      d.查看ip的命令:ipconfig
        测试是否能连接其他计算机的命令:ping ip地址

      e:特殊的地址:代表的是本机地址,到了哪里都不会变,代表自己
        127.0.0.1 -> 固定不变
        localhost

        localhost(主机名,写的是服务器的IP):端口号/应用名称/资源
        localhost:8080/web应用程序名称/资源

[协议]
     TCP:面向连接协议
         需要先确认连接,才能进行数据交互
         三次握手:
            - 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
            - 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
            - 第三次握手,客户端再次向服务器端发送确认信息,确认连接。

         好处:数据安全,能给数据的传输提供一个安全的传输环境
         坏处:效率低

     UDP:面向无连接协议
         好处:效率高
         坏处:传输的数据不安全,容易丢失数据包

[端口号]
   每一个应用程序的唯一标识

  用两个字节表示的整数,它的取值范围是0~65535。其中,0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
1744334937111

TCP 协议中的三次握手和四次挥手

java
三次握手:
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
- 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接。
java
四次挥手:
- 第一次挥手:客户端向服务器端提出结束连接,让服务器做最后的准备工作。此时,客户端处于半关闭状态,即表示不再向服务器发送数据了,但是还可以接受数据。

- 第二次挥手:服务器接收到客户端释放连接的请求后,会将最后的数据发给客户端。并告知上层的应用进程不再接收数据。

- 第三次挥手:服务器发送完数据后,会给客户端发送一个释放连接的报文。那么客户端接收后就知道可以正式释放连接了。

- 第四次挥手:客户端接收到服务器最后的释放连接报文后,要回复一个彻底断开的报文。这样服务器收到后才会彻底释放连接。这里客户端,发送完最后的报文后,会等待2MSL,因为有可能服务器没有收到最后的报文,那么服务器迟迟没收到,就会再次给客户端发送释放连接的报文,此时客户端在等待时间范围内接收到,会重新发送最后的报文,并重新计时。如果等待2MSL后,没有收到,那么彻底断开。

4.客户端和服务端交互过程说明

1744335121458

第二章.类的加载时机

java
1.new对象
2.new子类(new子类先初始化父类)
3.调用静态成员
4.执行main方法
5.利用反射获取class对象
1744335748439

1.类加载器(了解)_ClassLoader

java
作用:主要是将类加载到内存
java
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说:正好我加载核心类,行吧,我加载吧!

7.类加载器的cache(缓存)机制(扩展):一个类加载到内存之后,缓存中也会保存一份儿,后面如果再使用此类,如果缓存中保存了这个类,就直接返回他,如果没有才加载这个类.下一次如果有其他类在使用的时候就不会重新加载了,直接去缓存中拿,保证了类在内存中的唯一性

8.所以:类加载器的双亲委派和缓存机制共同造就了加载类的特点:保证了类在内存中的唯一性
1684463885399

第三章.反射

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

java
1.class对象-> class文件的对象
2.万物皆对象
   a.类有对象->Class对象 -> 用于描述class对象的类就是class类
   b.构造有对象->Constructor对象 -> 用于描述Constructor对象的类叫做Constructor类
   c.属性有对象-> Field对象 -> 用于描述Field对象的类叫做Field类
   d.方法有对象 -> Method对象 -> 用于描述Method对象的类叫做Method类
java
1.反射的作用:是用来解剖class对象的技术
2.解剖class对象能解剖出啥来呢?
  a.解剖出构造:创建对象
  b.解剖属性:赋值取值
  c.解剖方法:调用执行
3.反射怎么学:
   当成一套API来学 -> 调用不同的方法,有不同效果作用
4.通过涛哥的案例体会反射代码的灵活性,通用性

5.玩儿反射之前最重要的是干啥:拿到class对象
1744339428844

2.反射之获取 Class 对象

java
1.new对象,调用Object类中的getClass方法
  Class<?> getClass()

2.调用Class类中的静态方法:
  static Class<?> forName(String className)  -> 参数传递的是类的全限定名(包名.类名)

3.jvm为基本类型和引用类型都提供了一个共同的静态属性:
  class
java
public class Person {
    private String name;
    private Integer age;

    public Person() {
    }

    /**
     * 新添加一个私有的构造
     * @param name
     */
    private Person(String name) {
        this.name = name;
    }

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

    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;
    }
}
java
public class Demo01Reflect {
    public static void main(String[] args) throws ClassNotFoundException {
        /*
        1.new对象,调用Object类中的getClass方法
           Class<?> getClass()
         */
        Person person = new Person();
        Class<? extends Person> aClass1 = person.getClass();
        System.out.println("aClass1 = " + aClass1);

        System.out.println("=====================");
        /*
          2.调用Class类中的静态方法:
           static Class<?> forName(String className)  -> 参数传递的是类的全限定名(包名.类名)
         */
        Class<?> aClass2 = Class.forName("com.atguigu.a_reflect.Person");
        System.out.println("aClass2 = " + aClass2);

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

        /*
           3.jvm为基本类型和引用类型都提供了一个共同的静态属性:
             class
         */
        Class<Person> aClass3 = Person.class;
        System.out.println("aClass3 = " + aClass3);


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

    }
}

1.如何验证类的全限定名写对了:

按住 ctrl 不放,鼠标往类名上点击,能跳到这个类里面就这名写对了

2.如何保证类的全限定名一次性写对:

1744340140612

或者直接写类名->回车

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

java
static Class<?> forName(String className)  -> 参数传递的是类的全限定名(包名.类名)
properties
className=com.atguigu.a_reflect.Student
java
public class Demo02Reflect {
    public static void main(String[] args) throws ClassNotFoundException, IOException {
        Properties properties = new Properties();
        FileInputStream is = new FileInputStream("day21_reflect/pro.properties");
        properties.load(is);
        String className = properties.getProperty("className");

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

    }
}

2.2.开发中最常用的是哪一种

java
类名.class

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

3.1.获取所有 public 的构造方法

java
Class类中的方法:
   Constructor<?>[] getConstructors()  获取所有public的构造
java
    private static void method01() {
        Class<Person> personClass = Person.class;
        Constructor<?>[] constructors = personClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("constructor = " + constructor);
        }
    }

3.2.获取空参构造_public

java
1.Class类中的方法:
  Constructor<T> getConstructor(Class<?>... parameterTypes)获取指定的public的构造
                                形参:是一个可变参数,可以传递0个或者多个实参
                                    传递的是参数类型的class对象

                                如果获取空参构造,那么不用传递参数
                                如果获取有参构造,就传递这个有参构造参数类型的class对象

2.Constructor类中的方法:
   T newInstance(Object... initargs)-> 根据构造创建对象
                 initargs:是一个可变参数,可以传递0个或者多个实参
java
    @Test
    public void method02()throws Exception {
        Class<Person> personClass = Person.class;
        Constructor<Person> constructor = personClass.getConstructor();
        //Person person = new Person()
        Person person = constructor.newInstance();
        //相当于直接输出对象名,默认调用toString方法
        System.out.println(person);
    }

3.3.利用空参构造创建对象的快捷方式_public

java
1.Class类中的方法:
  T newInstance()

2.前提:
  被反射的类中必须有空参构造
java
@Test
public void method03()throws Exception{
    Class<Person> personClass = Person.class;
    Person person = personClass.newInstance();
    System.out.println("person = " + person);
}

3.4.利用反射获取有参构造并创建对象_public

java
1.Class类中的方法:
  Constructor<T> getConstructor(Class<?>... parameterTypes)获取指定的public的构造
                                形参:是一个可变参数,可以传递0个或者多个实参
                                    传递的是参数类型的class对象

                                如果获取空参构造,那么不用传递参数
                                如果获取有参构造,就传递这个有参构造参数类型的class对象

2.Constructor类中的方法:
   T newInstance(Object... initargs)-> 根据构造创建对象
                 initargs:是一个可变参数,可以传递0个或者多个实参
java
 @Test
    public void method04()throws Exception{
        Class<Person> personClass = Person.class;
        Constructor<Person> constructor = personClass.getConstructor(String.class, Integer.class);
        //好比是 Person person = new Person("张三",18);
        Person person = constructor.newInstance("张三", 18);
        System.out.println("person = " + person);
    }

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

java
1.Class类中的方法:
   Constructor<?>[] getDeclaredConstructors()获取所有的构造方法包括public以及private
   Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)  获取指定的构造,包括public以及private的

2.Constructor类中的方法:
   T newInstance(Object... initargs)-> 根据构造创建对象
                 initargs:是一个可变参数,可以传递0个或者多个实参

3.解除私有权限:Constructor, Field, Method 有一个共同的父类AccessibleObject,AccessibleObject中有一个方法:
  void setAccessible(boolean flag)  -> flag为true,证明是解除私有权限
java
    @Test
    public void method05()throws Exception{
        Class<Person> personClass = Person.class;
        Constructor<Person> constructor = personClass.getDeclaredConstructor(String.class);
        //接触私有权限
        constructor.setAccessible(true);
        //好比是 Person person = new Person("张三");
        Person person = constructor.newInstance("张三");
        System.out.println("person = " + person);
    }

4.反射方法_Method

4.1.利用反射获取所有成员方法_public

java
1.Class类中的方法:
  Method[] getMethods()  -> 获取所有的public的成员方法
java
   @Test
    public void method01(){
       Class<Person> personClass = Person.class;
       Method[] methods = personClass.getMethods();
       for (Method method : methods) {
           System.out.println("method = " + method);
       }
   }

4.2.反射之获取方法(有参,无参)_public

java
1.Class类中的方法:
  Method getMethod(String name, Class<?>... parameterTypes) 获取指定的方法
                   name:方法名
                   parameterTypes:传递的是方法参数类型的class对象
2.Method类中的方法:
  Object invoke(Object obj, Object... args) 执行指定的方法
                obj:对象
                args:此方法的实参
                返回值Object: 被执行方法的返回值,如果此方法没有返回值,不需要用Object接收了
java
    @Test
    public void method02() throws Exception {
        Class<Person> personClass = Person.class;
        Person person = personClass.newInstance();
        Method setName = personClass.getMethod("setName", String.class);
        setName.invoke(person, "张三");
        System.out.println("person = " + person);

        Method getName = personClass.getMethod("getName");
        Object name = getName.invoke(person);
        System.out.println(name);
    }

4.3.反射之操作私有方法

java
1.Class类中的方法:
  Method getDeclaredMethod(String name, Class<?>... parameterTypes)-> 获取指定的成员方法,包括public以及private
                           name:方法名
                           parameterTypes:方法参数类型的class对象
java
    @Test
    public void method03()throws Exception{
        Class<Person> personClass = Person.class;
        Person person = personClass.newInstance();
        Method eat = personClass.getDeclaredMethod("eat");
        eat.setAccessible(true);
        eat.invoke(person);
    }

5.反射成员变量_Field

5.1.获取所有属性

java
1.Class类中的方法:
  Field[] getFields()  -> 获取所有public的属性
  Field[] getDeclaredFields() -> 获取所有属性包括public以及private的
java
    @Test
    public void method01()throws Exception{
        Class<Person> personClass = Person.class;
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("========================");
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
    }

5.2.获取指定属性

java
1.Class类中的方法:
  Field getField(String name)  -> 获取指定的public的属性
                 name:属性名

  Field getDeclaredField(String name) -> 获取指定的属性包括public以及private
                 name:属性名


2.Field类中的方法:
  Object get(Object obj) 获取属性值
  void set(Object obj, Object value) 为属性赋值
           obj:对象
           value:属性值
java
    @Test
    public void method02()throws Exception{
        Class<Person> personClass = Person.class;
        Person person = personClass.newInstance();
        Field gender = personClass.getField("gender");
        //为属性赋值
        gender.set(person, "男");
        //获取属性值
        Object o = gender.get(person);
        System.out.println("o = " + o);

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

        Field name = personClass.getDeclaredField("name");
        name.setAccessible(true);
        name.set(person, "小红");
        Object o1 = name.get(person);
        System.out.println("o1 = " + o1);
    }

6.反射练习(编写一个小框架)

java
public interface 接口{
    public Employee getEmployeeById(int id);
}


xml配置文件:

<select id = "getEmployeeById" resultType = "Employee的全限定名">
     select 列名 from 表名 where 条件
</select>

框架可以根据指定的类获取对应的class对象,然后根据配置好的方法名获取此方法,执行此方法
========================================================================
1.要求:创建一个properties配置文件
      配置className = 类的全限定名
      配置methodName = 方法名

      解析配置文件,根据className拿到methodName,让其执行起来
java
1.解析配置文件
  a.问题:配置文件应该放到什么位置上
        在模块下创建一个文件夹,取名为resources,并将其变成资源目录(如下图)
        然后将配置文件都放到这个resources目录下

        这样运行代码配置文件会自动在out路径下生成 ->然后我们就可以直接将out路径下的class文件以及项目用到的配置文件打包给用户了


  b.配置文件怎么读取? -> 类加载器
    InputStream is = 当前类名.class.getClassLoader().getResourceAsStream("配置文件名.后缀名")

    自动读取resources目录下的配置文件

2.将配置文件中的className对应的类的全限定名获取出来,创建对应的class对象
3.根据配置文件中的methodName获取到方法名
4.执行方法
1744353119204
properties
className=com.atguigu.b_reflect.Student
methodName=study
java
public class Demo01Reflect {
    public static void main(String[] args)throws Exception {
        //1.创建properties集合对象
        Properties properties = new Properties();
        //2.读取配置文件
        InputStream in = Demo01Reflect.class.getClassLoader().getResourceAsStream("reflect.properties");
        //3.将流中的数据加载到properties集合中
        properties.load(in);
        //4.获取propertis中的配置
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");
        //5.根据获取出来的类的全限定名获取class对象
        Class<?> aClass = Class.forName(className);
        //6.根据class对象获取对应的实例对象
        Object o = aClass.newInstance();
        //7.根据class对象获取对应的方法对象
        Method method = aClass.getMethod(methodName);
        //8.执行方法
        method.invoke(o);
    }
}

InputStream is = 当前类名.class.getClassLoader().getResourceAsStream("配置文件名.后缀名") 解析

读取 resources 目录下的配置文件需要用到类的加载器

1.当前类调用 class,获取 Class 对象

2.利用 Class 对象中的方法 getClassLoader()获取类加载器对象(ClassLoader 对象)

3.利用 ClassLoader 对象中的 getResourceAsStream 方法读取配置文件,此方法最终返回一个 InputStream 对象

第四章.注解

1.注解的介绍

java
1.引用数据类型:
  类 数组 接口 枚举 注解 Record

2.jdk1.5版本的新特性->一个引用数据类型
       和类,接口,枚举是同一个层次的

       引用数据类型:类 数组  接口 枚举 注解  Record
3.作用:
        说明:对代码进行说明,生成doc文档(API文档)

        检查:检查代码是否符合条件   @Override(会用) @FunctionalInterface

        分析:对代码进行分析,起到了代替配置文件的作用(会用)

4.JDK中的注解:
        @Override  ->  检测此方法是否为重写方法
           jdk1.5版本,支持父类的方法重写
           jdk1.6版本,支持接口的方法重写
        @Deprecated -> 方法已经过时,不推荐使用
                       调用方法的时候,方法上会有横线,但是能用
        @SuppressWarnings->消除警告  @SuppressWarnings("all")
1744356278341

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

java
1.格式:
  public @interface 注解名{}

2.属性定义:增强注解的功能
  a.数据类型 属性名()  -> 这种属性没有默认值,到时候使用注解的时候,必须为其赋值
  b.数据类型 属性名() default-> 这种属性是有默认值的,到时候使用注解的时候,不用为其赋值
3.注解中能定义什么类型的属性呢?
  a.8种基本类型
  b.String类型,class类型,枚举类型,注解类型
  c.以及以上类型的一维数组
java
public @interface Book {
    String name();//书名
    String[] author();//作者
    int price();//价格
    int count() default 10;
}

其实人家在注解中不是属性,其实是抽象方法

那为啥我跟它叫做属性呢?原因是一会使用注解的时候,我们会给这些方法赋值 -> 方法名 = 值 -> 跟属性赋值一样,所以跟它叫做属性

3.注解的使用(重点)

java
1.注解的使用:为属性赋值
  a.使用位置:在类上,方法上,形参上,属性上,构造上等上使用
  b.@注解名(属性名 = 值,属性名 = 值...)
  c.如果注解中的属性是数组的话:
    @注解名(属性名 = {元素1,元素2})
java
public @interface Book {
    String name();//书名
    String[] author();//作者
    int price();//价格
    int count() default 10;
}
java
@Book(name="金瓶梅",author={"涛哥","金莲"},price=69)
public class BookShelf {
}
java
注解注意事项:
      1.空注解可以直接使用->空注解就是注解中没有任何的属性
      2.不同的位置可以使用一样的注解,但是同样的位置不能使用一样的注解
      3.使用注解时,如果此注解中有属性,注解中的属性一定要赋值,如果有多个属性,用,隔开
        如果注解中的属性有数组,使用{}
      4.如果注解中的属性值有默认值,不用重新赋值,反之必须赋值
      5.如果注解中只有一个属性,并且属性名叫value,那么使用注解的时候,属性名不用写,直接写值
        (包括单个类型,还包括数组)
java
public @interface Book2 {
    String value();
}
java
@Book(name="金瓶梅",author={"涛哥","金莲"},price=69)
@Book2("涛哥和金莲在苞米地的故事")
//@Book2
public class BookShelf {
    @Book2("涛哥和金莲在苞米地的故事")
    public void method(){}
}

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

java
1.接口:AnnotatedElement接口
  实现类:AccessibleObject, Class, Constructor, Field, Method, Package

2.接口中的方法:
  a.boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) -> 判断指定位置上有没有指定的注解

    比如:判断BookShelf类上有没有Book注解
    Class class = BookShelf.class
    class.isAnnotationPresent(Book.class)


  b.T getAnnotation(Class<T> annotationClass) -> 获取指定的注解

    比如:获取BookShelf类上的Book注解
        Class class = BookShelf.class
        boolean b = class.isAnnotationPresent(Book.class)
        如果b为true,就获取Book注解
        Book book = class.getAnnotation(Book.class);
java
public @interface Book {
    String name();//书名
    String[] author();//作者
    int price();//价格
    int count() default 10;
}
java
@Book(name="金瓶梅",author={"涛哥","金莲"},price=69)
public class BookShelf {
}
java
public class Demo01Annotation {
    public static void main(String[] args) {
        //获取BookShelf的Class对象
        Class<BookShelf> bookShelfClass = BookShelf.class;
        //判断bookShelfClass是否有Book注解
        boolean b = bookShelfClass.isAnnotationPresent(Book.class);
        System.out.println("b = " + b);
        if (b){
            Book book = bookShelfClass.getAnnotation(Book.class);
            System.out.println(book.name());
            System.out.println(Arrays.toString(book.author()));
            System.out.println(book.price());
            System.out.println(book.count());
        }
    }
}

涛哥猜想:如果自定义的注解没有在运行的时候被加载到内存中,那么即使使用了,在内存中也获取不到

第五章.元注解

java
1.概述:元注解本身也是一个注解
2.作用:管理自定义的注解
3.都从哪些方面管理呢?
  a.管理注解的使用位置
  b.管理注解的生命周期

4.@Target: 管理注解的使用位置
  a.ElementType[] value();
  b.ElementType:是一个枚举类
    TYPE:控制注解只能在类上使用
    FIELD:控制注解只能在属性上使用
    METHOD:控制注解只能在方法上使用
    PARAMETER:控制注解只能在参数上使用
    CONSTRUCTOR:控制注解只能在构造上使用
    LOCAL_VARIABLE:控制注解只能在局部变量上使用

5.@Retention:控制注解的生命周期
  a.@Retention中只有一个属性:RetentionPolicy value();
  b.RetentionPolicy:是一个枚举
    SOURCE:控制注解能在源码中出现
    CLASS:控制注解能在class文件中出现
    RUNTIME:控制注解能在运行时内存中出现
java
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
    String name();//书名
    String[] author();//作者
    int price();//价格
    int count() default 10;
}
java
@Book(name = "金瓶梅", author = {"涛哥", "金莲"}, price = 69)
public class BookShelf {
    @Book(name = "金瓶梅", author = {"涛哥", "金莲"}, price = 69)
    public void method() {

    }
}

1.注解再次解析(成功了)

java
public class Demo01Annotation {
    public static void main(String[] args) {
        //获取BookShelf的Class对象
        Class<BookShelf> bookShelfClass = BookShelf.class;
        //判断bookShelfClass是否有Book注解
        boolean b = bookShelfClass.isAnnotationPresent(Book.class);
        System.out.println("b = " + b);
        if (b){
            Book book = bookShelfClass.getAnnotation(Book.class);
            System.out.println(book.name());
            System.out.println(Arrays.toString(book.author()));
            System.out.println(book.price());
            System.out.println(book.count());
        }
    }
}

第六章.知识点总结