0
点赞
收藏
分享

微信扫一扫

java学习笔记第八周(一)

落花时节又逢君to 2022-03-11 阅读 31

一、反射机制

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

    }
}

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 反射机制调用构造方法

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属性!");
            }
        }
    }
}
举报

相关推荐

0 条评论