目录
一、反射机制
1、反射机制概述
1.1 反射机制作用
1.2 反射机制相关类的包
反射机制在java.lang.Class.*包下
1.3 反射机制相关的重要的类
1.4 获取Class的三种方式
package 反射;
import java.util.Date;
/**
* 要操作一个类的字节码,首先需要先获取到这个类的字节码,怎么获取java.long.Class实例?
* 三种方式
* 1、Class c=Class.forName("完整类名带包名")
* 2、Class c =对象.getClass();
* 3、
*/
public class ReflectTest01 {
public static void main(String[] args) {
/*第一种方式:通过一个静态方法
Class.forName()
1、静态方法
2、方法的参数是一个字符串
3、字符串需要的是一个完整类名
4、完整类名必须包含包名。java.lang包不能省略
*/
Class c1=null;
Class c2=null;
try {
c1=Class.forName("java.lang.String");//c1代表String.class文件,或者说代表String类型
c2=Class.forName("java.util.Date");//c2代表Date类型
Class c3=Class.forName("java.lang.Integer");//c3代表Integer类型
Class c4=Class.forName("java.lang.System");//c4代表System类型
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//第二种方法
//java中每一个对象都有一个方法:getClass()
String s="abc";
Class x=s.getClass();//x代表String.class字节码文件,x代表String类型
System.out.println(c1==x);
Date time=new Date();
Class y=time.getClass();
System.out.println(c2==y);//ture(c2和y两个变量中保存到内存地址是一样的,都指向方法区中的字节码 )
//第三种方式:java语言中任何一种类型,包括基本数据类型,他都有.class属性
Class z=String.class;
Class k=int.class;
System.out.println(k==z);//false,z代表String类型,k代表int类型
}
}
1.5 通过反射实例化对象
package reflect;
import java.io.FileReader;
import java.util.Properties;
/**
* 验证反射机制的灵活性
* java代码写一遍,再不改变java原代码的基础上,可以做到不同对象的实例化,非常灵活
*
*/
public class ReflectTest03 {
public static void main(String[] args) throws Exception {
//User user =new User();
//以下代码是灵活的,代码不需要改动,可以修改配置文件,修改后,可以创建出不同的实例对象
//通过IO流读取classInfo.properties文件
FileReader reader = new FileReader("classInfo.properties");
//创建属性类对象Map
Properties pro = new Properties();
//加载
pro.load(reader);
//关闭流
reader.close();
//通过key获取value
String className = pro.getProperty("className");
System.out.println(className);
//通过反射机制实例化对象
Class c=Class.forName(className);
Object obj=c.newInstance();
System.out.println(obj);
}
}
1.6 Class.forName()方法调用
package reflect;
/**
* Class.forName()方法发生了什么
* 记住重点:
* 如果你只是希望一个类的静态代码块执行,其他代码块一律不执行
* 你可以使用:Class.forName("完整类名")
* 这个方法的执行会导致:类加载,类加载时,静态代码块执行
*/
public class ReflectTest04 {
public static void main(String[] args) {
//Class.forName()这个方法的执行会导致:类加载
try {
Class.forName("reflect.MyClass");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class MyClass{
//静态方法块被执行那么类一定被加载
static {
System.out.println("MyClass类的静态代码块被执行了");
}
}
2、获取路径
FileReader reader = new FileReader("classInfo.properties");
这种方式的路径缺点是:可移植性差,在IDEA中默认的当前路径是project的根。
这个代码假设离开了IDEA,换到了其他的位置,可能当前路径就不是Project的根了,这个时候路径就会无效。
package getPath;
import java.io.FileNotFoundException;
import java.io.FileReader;
/**
* 研究以下路径问题
*/
public class AboutPath {
public static void main(String[] args) throws FileNotFoundException {
//这种方式的路径缺点是:可移植性差,在IDEA中默认的当前路径是project的根。
//这个代码假设离开了IDEA,换到了其他的位置,可能当前路径就不是Project的根了,这个时候路径就会无效。
//FileReader reader=new FileReader("classInfo2.properties");
//上面这行代码使用绝对路径也不好,因为以后程序可能会放到Linux系统上,而Linux没有c盘d盘啥的,因此用下面的方法比较好
/**
* 接下来说一种比较通用的一种路径,即使代码换位置了,这样编写仍然是通用的
* 注意:使用以下通用方式的前提是:这个文件必须在类路径下。
* 什么是类路径下?方式在src下的都是类路径下【记住它】
* src是类的根路径
*/
/*
解释:
Thread.currentThread() 当前线程对象
getContextClassLoader()是当前对象的方法,可以获取到当前线程的类的加载器对象
getResource() 【获取资源】这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源
*/
String path=Thread.currentThread().getContextClassLoader().getResource("classInfo2.properties").getPath();
/*
* 采用以上的代码可以拿到一个文件的绝对路径
* /C:/Users/jlkjlk/IdeaProjects/Thread/out/production/Thread/classInfo2.properties
* 这种方法获取的绝对路径是通用的
*/
System.out.println(path);
//获取db.properties文件的绝对路径(默认路径从类的根路径下作为起点开始)
String path2=Thread.currentThread().getContextClassLoader().getResource("getPath/Test/db.properties").getPath();
System.out.println(path2);
}
}
2.1 以流的方式直接返回
package reflect;
import java.io.InputStream;
import java.util.Properties;
public class IOPropertiesTest {
public static void main(String[] args) throws Exception {
//获取一个文件的绝对路径了!!
/*String path=Thread.currentThread().getContextClassLoader().getResource("classInfo2.properties").getPath();
FileReader reader=new FileReader(path);*/
//直接以流的方式进行返回,相当于上面两行代码结合
InputStream reader=Thread.currentThread().getContextClassLoader().getResourceAsStream("classInfo2.properties");
Properties pro=new Properties();
pro.load(reader);
reader.close();
//通过key获取value
String className=pro.getProperty("className");
System.out.println(className);
}
}
注意:之前在IO流、Thread多线程中所用的路径都要用Thread.currentThread().getContextClassLoader().getResource("classInfo2.properties").getPath();
这个方法,或者直接以流的形式返回,这样在不同操作系统下能够使用
但是,这种方法一定要在类路径中才能使用这种方法!
2.2 资源绑定器
java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容。
使用以下这种方式的时候,属性配置文件xxx.proper.ties必须放到类路径下。
package reflect;
import java.util.ResourceBundle;
/**
* java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容
* 使用以下这种方式的时候,属性配置文件xxx.proper.ties必须放到类路径下。
*/
public class ResourceBundleTest {
public static void main(String[] args) {
//资源绑定器,只能绑定xxx.proper.ties,并且这个文件必须要在类路径下。文件拓展名必须是properties
//并且在写路径的时候,路径后面的拓展名不能写
ResourceBundle bundle=ResourceBundle.getBundle("classInfo2");
ResourceBundle bundle1=ResourceBundle.getBundle("getPath/Test/db");
String className=bundle.getString("className");
String className1=bundle1.getString("className");
System.out.println(className);
System.out.println(className1);
}
}
3、类加载器(扩展)
3.1 类加载器概述
3.2 三个加载器介绍
1、首先通过“启动类加载器”进行加载
注意:启动类加载器专门加载:D:\java\lib\rt.jar
rt.jar 中都是JDK中最核心的类库
2、如果”启动类加载器“加载不到,会通过”扩展类加载器“加载
注意:扩展类加载器专门加载:D:\java\lib\ext
3、如果“扩展类加载器”中没有加载到,会通过”应用类加载器“加载
注意:应用类加载器专门加载:classpath中的类。
3.3 双亲委派机制
4、反射属性
4.1 获取field
package bean;
/**
* 反射属性Field
*/
public class Student {
//Filed翻译为字段,其实就是属性/成员
//4个Filed,分别采用了不同的访问控制权限修饰符
private String name;
protected int age;
boolean sex;
public int no;
public static final double MATH_PI=3.141592;
}
package reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* 获取Filed
* 反射Student类中所有Field
*/
public class ReflectTest05 {
public static void main(String[] args) throws Exception {
//获取整个类
Class studentClass=Class.forName("bean.Student");
String className=studentClass.getName();
System.out.println("完整类名: "+className);
String simpleName=studentClass.getSimpleName();
System.out.println("简单类名: "+simpleName);
//获取类中的所有的public修饰的Field并放入数组中
Field[] fields=studentClass.getFields();
System.out.println(fields.length);//测试数组中只有一个元素
//取出这个Field
Field f=fields[0];
String fieldName=f.getName();
System.out.println(fieldName);
//获取所有的Field
Field[] fs=studentClass.getDeclaredFields();
System.out.println(fs.length);
//遍历
for(Field field:fs){
//获取属性的修饰符列表
int i=field.getModifiers();
System.out.println(i);
//可以把上面的代号转为“字符串”吗?
String modifierString= Modifier.toString(i);
System.out.println(modifierString);
//获取属性的类型
Class fieldType=field.getType();
//String fName=fieldType.getName();
String fName=fieldType.getSimpleName();
System.out.println(fName);
//获取属性的名字
System.out.println(field.getName());
}
}
}
4.2 反编译Filed
可以通过反编译直接获取一个类的属性
package reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* 通过反射机制,反编译一个类的属性Filed
*/
public class ReflectTest06 {
public static void main(String[] args) throws ClassNotFoundException {
//创建这个是为了拼接字符串
StringBuilder s=new StringBuilder();
// Class studentClass=Class.forName("bean.Student");
Class studentClass=Class.forName("java.lang.Integer");
s.append(Modifier.toString(studentClass.getModifiers())+" class "+studentClass.getSimpleName()+"{\n");
Field[] fields=studentClass.getDeclaredFields();
for(Field field:fields){
s.append("\t");
s.append(Modifier.toString(field.getModifiers()));
s.append(" ");
s.append(field.getType().getSimpleName());
s.append(" ");
s.append(field.getName());
s.append(";\n");
}
s.append("}");
System.out.println(s);
}
}
4.3 通过反射机制访问对象属性(重点)
package reflect;
import bean.Student;
import java.lang.reflect.Field;
/**
* 必须掌握:
* 怎么通过反射机制访问一个java对象的属性
* 给属性赋值,获取属性的值
*/
public class ReflectTest07 {
public static void main(String[] args) throws Exception {
//如果不使用反射机制,怎么去访问一个对象的属性
Student s=new Student();
//给属性赋值
s.no=111;
//读属性值
System.out.println(s.no);
//使用反射机制怎么去访问一个对象的属性(set get)
Class studentClass=Class.forName("bean.Student");
Object obj=studentClass.newInstance();//obj就是Student对象(底层调用无参构造器)
//获取属性通过名字来区分
//获取no属性
Field noFile=studentClass.getDeclaredField("no");
//给obj(Student对象)的no属性赋值
/**
* 虽然使用了反射机制,但是三要素还是缺一不可
* 要素1:obj对象
* 要素2:no属性
* 要素3:赋值
* 注意:反射机制让代码复杂了,但是灵活了,这是值得的
*/
noFile.set(obj,11);//给obj对象的no属性赋值
//读取属性的值
//两个要素:获取ob对象的no属性的值
System.out.println(noFile.get(obj));
//可以访问私有的属性吗?
Field nameField=studentClass.getDeclaredField("name");
//如果要访问私有属性,要打破封装(反射的缺点),不安全
nameField.setAccessible(true);
nameField.set(obj,"java");
System.out.println(nameField.get(obj));
}
}
5、反射Method(重点)
5.1 可变长度参数
package reflect;
/**
* 可变长参数
* int...args这就是可变长参数
* 语法是:类型...(注意:一定是3个点)
*
* 1、可变长度参数要求的参数个数是:0~N个
* 2、可变长长度数在参数列表中必须在最后一个位置上,而且只能出现一个可变长参数
*/
public class ArgsTest {
public static void main(String[] args) {
m();
m(10);
m(20);
//编译报错
//m("abc");
m2(100);
m2(100,"abc");
m2(200,"abc","def");
m3("ab","de","kk","ff");
String[] strs={"a","b","c"};
m3(strs);
//m3(new String[]{"我","是","中","国","人"});//没必要,直接赋值就行
m3("我","是","中","国","人");
}
public static void m(int ...args){
System.out.println("m方法执行啦");
}
// public static void m2(String... args1,int... args2){}//会报错,
public static void m2(int a,String... args1){}
public static void m3(String... args){
//args有length属性,说明args是一个数组!
//可以将可变长度参数当作一个数组来看
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
}
}
5.2 反射Method(了解)
package reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* 作为了解内容:(不需要掌握)
* 反射Method
*/
public class ReflectTest08 {
public static void main(String[] args) throws Exception{
//获取类
Class userServiceClass=Class.forName("bean.UserService");
//获取所有Method(包括私有的)
Method[] methods=userServiceClass.getDeclaredMethods();
System.out.println(methods.length);
//遍历Method
for(Method method:methods){
//获取修饰符列表
System.out.println(Modifier.toString(method.getModifiers()));
//获取方法的返回值类型
System.out.println(method.getReturnType().getSimpleName());
//获取方法名
System.out.println(method.getName());
//方法的修饰符列表(一个方法的参数可能有多个,因此返回值应该是一个Class数组)
Class[] parameterTypes=method.getParameterTypes();
for(Class parameterType:parameterTypes){
System.out.println(parameterType.getSimpleName());
}
}
}
}
5.3 反编译Method
package reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ReflectTest09 {
public static void main(String[] args) throws Exception {
StringBuilder s=new StringBuilder();
Class userServiceClass=Class.forName("java.lang.String");
s.append(Modifier.toString(userServiceClass.getModifiers())+" class "+userServiceClass.getSimpleName()+" {\n");
Method[] methods=userServiceClass.getDeclaredMethods();
//public boolean login(String name,String password){
for(Method method:methods){
s.append("\t");
s.append(Modifier.toString(method.getModifiers()));
s.append(" ");
s.append(method.getReturnType().getSimpleName());
s.append(" ");
s.append(method.getName());
s.append("(");
//参数列表
Class[] parameterTypes=method.getParameterTypes();
for(Class parameterType:parameterTypes){
s.append(parameterType.getSimpleName());
s.append(",");
}
if(s.charAt(s.length()-1)==','){
s.deleteCharAt(s.length()-1);
}
s.append("){}\n");
}
s.append("}");
System.out.println(s);
}
}
5.4 通过反射机制调用方法(重点)
package reflect;
import bean.UserService;
import java.lang.reflect.Method;
/**
* 通过反射机制怎么调用一个对象的方法?(重点,必须掌握)
* 调用方法要素分析:
* 要素1:对象userService
* 要素2:login方法名
* 要素3:实参列表
* 要素4:返回值
*/
public class ReflectTest10 {
public static void main(String[] args) throws Exception{
//不用反射机制
UserService userService=new UserService();
boolean loginSuccess=userService.login("admin","123");
System.out.println(loginSuccess?"登录成功":"登陆成功");
//使用反射机制来台调用一个对象的方法(通过方法名和形参)
Class useServiceClass=Class.forName("bean.Student");
//创建对象
Object obj=useServiceClass.newInstance();
//获取Method
Method loginMethod=useServiceClass.getDeclaredMethod("login",String.class,String.class);
//反射机制中最最最重要的方法,必须记住
Object retValue=loginMethod.invoke(obj,"admin","123");
}
}
5.5 反编译Constructor
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
/**
* 反编译一个类的Cons
*/
public class ReflectTest11 {
public static void main(String[] args) throws Exception{
StringBuilder s=new StringBuilder();
Class vipClass=Class.forName("bean.Vip");
s.append(Modifier.toString(vipClass.getModifiers()));
s.append(" class ");
s.append(vipClass.getSimpleName());
s.append("{\n");
//凭借构造方法
Constructor[] constructors=vipClass.getDeclaredConstructors();
for(Constructor constructor:constructors){
s.append("\t");
s.append(Modifier.toString(constructor.getModifiers()));
s.append(" ");
s.append(vipClass.getSimpleName());
s.append("(");
//拼接参数
Class[] parameterTypes=constructor.getParameterTypes();
for(Class parameterType:parameterTypes){
s.append(parameterType.getSimpleName());
s.append(",");
}
//删除最后下标位置上的字符
//if(parameterTypes.length>0){
// s.deleteCharAt(s.length()-1)
// }
if(s.charAt(s.length()-1)==','){
s.deleteCharAt(s.length()-1);
}
s.append("){}\n");
}
s.append("}");
System.out.println(s);
}
}
5.6 反射机制调用构造方法
要记得在Vip类中重写toString
package reflect;
import bean.Vip;
import java.lang.reflect.Constructor;
/**
* 比上一个例子重要一些
*/
public class ReflectTest12 {
public static void main(String[] args) throws Exception{
//不使用反射机制
Vip v1=new Vip();
Vip v2=new Vip(110,"xutao","2003-3-6",true);
//使用反射机制怎么创建对象呢
Class c=Class.forName("bean.Vip");
//调用无参数的构造方法
Object obj=c.newInstance();
System.out.println(obj);
//调用有参数的构造方法怎么办?
//第一步:先获取到这个有参数的构造方法
Constructor con=c.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
//第二步:调用构造方法new对象
Object newObj=con.newInstance(110,"jj","2022-3-6",true);
System.out.println(newObj);
//获取无参数构造方法
Constructor con2=c.getDeclaredConstructor();
Object newObj2=con2.newInstance();
System.out.println(newObj2);
}
}
5.7 获取父类和父接口
package reflect;
public class ReflectTest14 {
public static void main(String[] args) throws Exception{
//String举例
Class stringClass=Class.forName("java.lang.String");
//获取String的父类
Class superclass=stringClass.getSuperclass();
System.out.println(superclass);
//获取String类实现的所有接口(一个类可以实现多个接口)
Class[] interfaces=stringClass.getInterfaces();
for(Class in:interfaces){
System.out.println(in.getName());
}
}
}
6、注解
6.1 注解自定义的使用
package annotation;
/**
* 1、注解,或者叫做注释类型(注意不是//)
* 2、注解是一种引用数据类型。编译以后也是生产xxx.class文件
* 3、怎么自定义注解呢?语法格式?
* 【修饰符列表】 @interface 注解类型名{
*
* }
* 4、注解怎么使用,用在什么地方?
* 第一:注解使用时语法格式是@注解类型名
* 第二:注解可以出现在类上、属性上、方法上、变量上等......还可以出现在注解类型上
*
* 默认情况下,注解可以出现在任意位置
*/
@MyAnnotation
public class AnnotationTest01 {
@MyAnnotation
private int no;
@MyAnnotation
private AnnotationTest01(){}
@MyAnnotation
public static void m1(){
@MyAnnotation
int i=0;
}
@MyAnnotation
public void m2(@MyAnnotation String name){
}
@MyAnnotation
public static void main(String[] args) {
}
}
@MyAnnotation
interface MyInterface{
}
@MyAnnotation
enum Season{
SPRING,SUMMER,AUTUMN,WINTER
}
6.2 JDK内置注解
6.3 注解怎么定义使用
package annotation;
/**
* 关于JDK lang包下的Override注解
* 源代码:
* public @interface Override{
*
* }
*
*
* @Override这个注解只能注解方法
* @Override这个注解是编译器参考的,和运行阶段没有关系
* 凡是java中的方法带有这个注解的,编译器都会进行编译检查,如果这个方法不是重写父类的方法,编译器会报错
*/
public class AnnotationTest02 {
@Override
public String toString() {
return "toString";
}
}
6.4 元注解
RUNTIME可以被反射机制读
6.5 Deprecated注解
package annotation;
/**
* @Deprecated 表示这个类已经过时
*/
public class AnnotationTest03 {
public static void main(String[] args) {
AnnotationTest03 at=new AnnotationTest03();
at.doSome();
}
@Deprecated
public void doSome(){
System.out.println("do something");
}
@Deprecated
public static void doOther(){
System.out.println("do other");
}
}
class T{
public static void main(String[] args) {
AnnotationTest03 at=new AnnotationTest03();
at.doSome();
AnnotationTest03.doOther();
try {
Class c=Class.forName("java.util.Date");
Object obj=c.newInstance();//这个方法JDK8没有过时
} catch (Exception e) {
e.printStackTrace();
}
}
}
6.6 注解中定义属性
package annotation.annotation2;
public @interface MyAnnotation {
/**
* 我们通常在注解当中可以定义属性,以下这个是MyAnnotation的name属性。
* 看着像一个方法,但实际上我们称作为属性name
* @return
*/
String name();
String color();
int age() default 25;//属性指定默认值
}
package annotation.annotation2;
public class MyAnnotationTest {
//报错的原因,如果一个注解当中有属性,那么必须给属性赋值
/*@MyAnnotation
public void doSome(){
}
*/
//@MyAnnotation(属性名=属性值)
//指定属性值
@MyAnnotation(name="java",color = "red")//如果指定了使用了default指定了默认值,就不用指定属性值了
public void doSome(){
}
}
6.7 注解属性名为value
当注解属性名为value且只有一个属性的时候,value可以省略
package annotation.annotation3;
public @interface MyAnnotation {
/**
* 指定一个value属性
*/
String value();
//String email();
}
package annotation.annotation3;
/**
* 如果一个注解的属性名字是value的话,并且只有一个属性的时候,在赋值的时候value可以省略
*/
public class MyAnnotationTest {
//报错原因:没有指定属性值
/*@MyAnnotation()
public void doSome(){}
*/
@MyAnnotation(value = "hehe")
public void doSome(){
}
@MyAnnotation("haha")
public void doOther(){
}
}
6.8 属性是一个数组时
package annotation.annotation4;
public @interface MyAnnotation {
/**
* 注解中属性可以是哪一种类型
* 属性的类型可以是:byte short int float double boolean char String Class 枚举类型以及其数组
*/
int value1();
String value2();
int[] value3();
String[] value4();
Season value5();
Season[] value6();
Class parameterType();
Class[] parameterTypes();
}
package annotation.annotation4;
public @interface OtherAnnotation {
//年龄属性
int age();
/*
邮箱地址属性,支持多个
*/
String[] email();
/**
* 季节数组,Season是枚举类型
* @return
*/
Season[] seasonArray();
}
package annotation.annotation4;
public class OtherAnnotationTest {
@OtherAnnotation(age=25,email={"zhangsan@123.com","zhangsan@sohu.com"},seasonArray = {Season.SPRING,Season.SUMMER,Season.AUTUMN,Season.WINTER})
public void doSome(){
}
//如果数组中只有一个元素,大括号可以省略
@OtherAnnotation(age=25,email = "zhangsan@123.com",seasonArray = Season.AUTUMN)
public void doOther(){
}
}
6.9 通过反射获取类上的注解
package annotation.annotation5;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//只允许该注解只可以标注类和方法
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
//希望这个注解可以被反射到
@Retention(RetentionPolicy.RUNTIME)
//@Retention(RetentionPolicy.SOURCE)//这个注解只保存在java源文件中,不能被反射出来
public @interface MyAnnotation {
String value() default "jx";
}
package annotation.annotation5;
@MyAnnotation("jx1")
public class MyAnnotationTest {
//@MyAnnotation //不行
int i;
//@MyAnnotation
public MyAnnotationTest(){}
@MyAnnotation
public void doSome(){
// @MyAnnotation //不行
int i;
}
}
package annotation.annotation5;
public class ReflectAnnotationTest {
public static void main(String[] args) throws Exception{
//获取这个类
Class c=Class.forName("annotation.annotation5.MyAnnotationTest");
//判断类上面是否有@MyAnnotation
System.out.println(c.isAnnotationPresent(MyAnnotation.class));
if(c.isAnnotationPresent(MyAnnotation.class)){
//获取该注解对象
MyAnnotation myAnnotation=(MyAnnotation) c.getAnnotation(MyAnnotation.class);
System.out.println("类上面的注解对象"+myAnnotation);
//获取注解对象的属性怎么办?和调接口没区别(已经获取到对象了,直接.调用就行)
String value=myAnnotation.value();
System.out.println(value);
}
//判断String类上面是否存在这个注解
Class stringClass=Class.forName("java.lang.String");
System.out.println(stringClass.isAnnotationPresent(MyAnnotation.class));
}
}
6.10 通过反射获取方法上的注解
package annotation.annotation6;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
/*
* username属性
*/
String username();
/*
password属性
*/
String password();
}
package annotation.annotation6;
import java.lang.reflect.Method;
public class MyAnnotationTest {
@MyAnnotation(username = "admin",password = "123")
public void doSome(){
}
public static void main(String[] args) throws Exception{
//获取MyAnnotationTest的doSome()方法上面的注解信息
Class c=Class.forName("annotation.annotation6.MyAnnotationTest");
Method doSomeMethod=c.getDeclaredMethod("doSome");
//判断该方法上是否存在这个注解
if(doSomeMethod.isAnnotationPresent(MyAnnotation.class)){
MyAnnotation myAnnotation=doSomeMethod.getAnnotation(MyAnnotation.class);
System.out.println(myAnnotation.password());
System.out.println(myAnnotation.username());
}
}
}
6.11注解在开发中的作用
实例:
package annotation.annotation7;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//表示这个注解只能在类上面
@Target(ElementType.TYPE)
//该注解可以被反射机制取到
@Retention(RetentionPolicy.RUNTIME)
public @interface Id {
}
//这个注解@Id用来标注类,被标注类的中必须有一个int类型的Id属性,否则就报异常
package annotation.annotation7;
@Id
public class User {
int id;
String name;
String password;
}
package annotation.annotation7;
/**
* 自定义异常
*/
public class HasNotIdPropertyException extends RuntimeException{
public HasNotIdPropertyException(){}
public HasNotIdPropertyException(String s){
super(s);
}
}
package annotation.annotation7;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) throws Exception{
//获取类
Class userClass=Class.forName("annotation.annotation7.User");
boolean isOk=false;//给一个默认标记
//判断类上是否存在Id注解
if(userClass.isAnnotationPresent(Id.class)){
//当一个类上面有@Id注解的时候,要求类中必须存在int类型的id属性,没有就报异常
//获取类的属性
Field[] fields=userClass.getDeclaredFields();
for(Field field:fields){
if("id".equals(field.getName())&&"int".equals(field.getType().getSimpleName())){
//表示这个类是合法的类,有@Id注解,则这个类中必须有int类型
isOk=true;
break;
}
}
//判读是否合法
if(!isOk){
throw new HasNotIdPropertyException("被Id注解标注的类中必须要有一个int类型属性的id属性!");
}
}
}
}