java学习笔记第八周(一)

目录

一、反射机制

1、反射机制概述

1.1 反射机制作用

1.2 反射机制相关类的包

1.3 反射机制相关的重要的类

1.4 获取Class的三种方式

1.5 通过反射实例化对象

1.6 Class.forName()方法调用

2、获取路径

2.1 以流的方式直接返回

2.2 资源绑定器

3、类加载器(扩展)

3.1 类加载器概述

3.2 三个加载器介绍

3.3 双亲委派机制

4、反射属性

4.1 获取field

4.2 反编译Filed

4.3 通过反射机制访问对象属性(重点)

5、反射Method(重点)

5.1 可变长度参数

5.2 反射Method(了解)

5.3 反编译Method

5.4 通过反射机制调用方法(重点)

5.5 反编译Constructor

5.6 反射机制调用构造方法

5.7 获取父类和父接口

6、注解

6.1 注解自定义的使用

6.2 JDK内置注解

6.3 注解怎么定义使用

6.4 元注解

6.5 Deprecated注解

6.6 注解中定义属性

6.7 注解属性名为value

6.8 属性是一个数组时

6.9 通过反射获取类上的注解

6.10 通过反射获取方法上的注解

6.11注解在开发中的作用


一、反射机制

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值