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、红蜘蛛、飞秋等软件。

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

两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机的通信的程序。
2.服务器概念
java
1.概述:安装了服务器软件的计算机
网络通信协议:两台计算机在做数据交互时要遵守的规则,协议会对数据的格式,速率等进行规定,只有都遵守了这个协议,才能完成数据交互
两台计算机想完成数据交互,需要遵守网络通信协议

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以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。

TCP 协议中的三次握手和四次挥手
java三次握手: - 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。 - 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。 - 第三次握手,客户端再次向服务器端发送确认信息,确认连接。
java四次挥手: - 第一次挥手:客户端向服务器端提出结束连接,让服务器做最后的准备工作。此时,客户端处于半关闭状态,即表示不再向服务器发送数据了,但是还可以接受数据。 - 第二次挥手:服务器接收到客户端释放连接的请求后,会将最后的数据发给客户端。并告知上层的应用进程不再接收数据。 - 第三次挥手:服务器发送完数据后,会给客户端发送一个释放连接的报文。那么客户端接收后就知道可以正式释放连接了。 - 第四次挥手:客户端接收到服务器最后的释放连接报文后,要回复一个彻底断开的报文。这样服务器收到后才会彻底释放连接。这里客户端,发送完最后的报文后,会等待2MSL,因为有可能服务器没有收到最后的报文,那么服务器迟迟没收到,就会再次给客户端发送释放连接的报文,此时客户端在等待时间范围内接收到,会重新发送最后的报文,并重新计时。如果等待2MSL后,没有收到,那么彻底断开。
4.客户端和服务端交互过程说明

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

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.所以:类加载器的双亲委派和缓存机制共同造就了加载类的特点:保证了类在内存中的唯一性

第三章.反射
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对象

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.如何保证类的全限定名一次性写对:
或者直接写类名->回车
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.执行方法

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")

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());
}
}
}