Java基础-注解与反射

1. 注解

定义

注释 commont 给人看的
注解 annotation 给程序解释 可以被起程序读取
注解的作用:通过注解标识,程序解析时,解析到注解,会去找哪块引用了注解,根据注解功能的不同对业务进行扩展

格式

以"@注解名"在程序中存在的,还可以添加一些参数值 如:

@EnableAspectJAutoProxy(proxyTargetClass = true)

位置

可以附加在 package , class , method , field 等 上面,相当于给他们添加了额外的辅助信息 , 我们可以通过反射机制实现对注解的访问

1.1 java 内置注解

@Override

定义在java.lang.Override中,只适用于修饰方法,表示一个方法重写超类中的某个方法

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

@Deprecated

定义在java.lang.Deprecated中,表示不鼓励程序员使用这样的元素,当时可以使用,通常存在更好的选择

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

在这里插入图片描述

@SuppressWarnings

镇压警告,抑制编译时的警告信息(标黄的元素),通常是定义后未被使用的元素

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
}

在这里插入图片描述

在这里插入图片描述

1.2 java元注解

  • 元注解负责解释其他注解,java定义了4个标准的meta-annontation类型,他们用来提供对其他注解类型做说明

@Target

描述注解的使用范围,即被标识的注解可以用在什么地方

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {

    ElementType[] value();
    
}

ElementType[]是一个枚举类型,可以传递一个数字,标识注解作用域,即在哪个地方有效
在这里插入图片描述
举例:
在这里插入图片描述

@Retention

标识注解的生命周期
SOURCE < CLASS < RUNTIME

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
   
    RetentionPolicy value();
}

@Documented

表示是否将注解生成在Javadoc中

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

@Inherited

说明子类可以继承父类中的注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

1.3 自定义注解

定义规则

在这里插入图片描述

案例

package com.jt.anno;
/**
 * 自定义注解
 * 注解有多个参数时,使用时不需要关注参数顺序
 * 注解只有一个参数且参数名为value,参数赋值时可省略value
 */
@MyAnnotation(name = "吵吵")
public  class  Test01{

}
@MyAnnotation02("猪八戒")
class  Test02{

}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    /**
     * 注解的参数不是一个方法,有自己的格式
     * 参数类型 + 参数名();
     * 定义了参数,使用注解时就必须赋值
     * 或者可以加一个默认值  default ""    为空即可
     */
        String   name() default "";
        int age() default 0;
        int id() default -1; //默认值为-1代表不存在
        String[] school() default {"清华","北大"};
}

/**
 *如果注解只有一个参数,建议使用value命名
 * 使用注解时,为参数赋值可省略value
 * @author Cmj
 */
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation02{
    String value() default "";
}

2. 反射机制

Reflection 赋予java语言动态性,创建对象(除 new 和 clone )的另一种形式,可以获取类的注解,泛型等

2.1 反射机制概述

动态语言和静态语言

  • 动态语言
    是一类在运行时可以改变其结构的语言,在运行时,代码可以根据某些条件改变自身结构 如: JavaScript,PHP,Python等
  • 静态语言
    运行时结构不可改变,如Java , C, C++等,java准确的说是类动态语言,我们可以通过反射机制获得类似动态语言的特性
    在这里插入图片描述
    在这里插入图片描述
  • 一个类在内存中只有一个class对象
  • 一个类在被加载后, 类的整个结构都会被封装在class对象中
package com.jt.reflection;

/**
 * @author CMJ
 * 2021/6/14 17:14
 */
public class TestReflection {
    /***  手写的类路径JVM有可能找不到,所以会有ClassNotFoundException异常信息*/
    public static void main(String[] args) throws ClassNotFoundException {

        //通过反射获取类的Class对象,类路径是人写的,所以不确定泛型约束类型是什么
        Class<?> c1 = Class.forName("com.jt.pojo.User");

        System.out.println(c1);
        //结果: class com.jt.pojo.User   class类型的user对象

        Class<?> c2 = Class.forName("com.jt.pojo.User");
        Class<?> c3 = Class.forName("com.jt.pojo.User");
        Class<?> c4 = Class.forName("com.jt.pojo.User");
        /**
         * 一个类在内存中只有一个class对象
         * 一个类在被加载后, 类的整个结构都会被封装在class对象中
         */
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());
       
    }
}

在这里插入图片描述

2.2 JVM如何加载类获取class实例

Class类

在这里插入图片描述

Class类的常用方法

在这里插入图片描述

如何获取Class类的实例

在这里插入图片描述

案例

package com.jt.reflection;

/**
 * @author CMJ
 * 2021/6/14 17:59
 * 测试Class类的创建方式有哪些
 */
public class GetClass {
    public static void main(String[] args) {
        Person person=new Student();
        System.out.println("这个人是:"+person.name);
        //这个人是:学生

        //方式一: 通过对象获得
        Class<? extends Person> c1 = person.getClass();
        System.out.println(c1.hashCode());
        //460141958

        //方式二: 通过静态方法 forName ("类路径") 获得
        try {
            Class<?> c2 = Class.forName("com.jt.reflection.Student");
            System.out.println(c2.hashCode());
            //460141958
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //方式三; 通过 类名.class  获得
        Class<Student> c3 = Student.class;
        System.out.println(c3.hashCode());
        //460141958

        //方式四: 基本内置类型的包装类都有一个TYPE属性
        Class<Integer> c4 = Integer.TYPE;
        System.out.println(c4);
        System.out.println(c4.hashCode());
        //int
        //1163157884

        //获得父类类型
        Class<?> c5 = c1.getSuperclass();
        System.out.println(c5);
        //class com.jt.reflection.Person

    }

}
class Person{
    public String name;

    public Person() {
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student extends Person{
    public Student() {
        this.name="学生";
    }
}
class Teacher extends Person{
    public Teacher() {
        this.name="老师";
    }
}

在这里插入图片描述

哪些类型可以有class对象?

/**
 * @author CMJ
 * 2021/6/14 18:33
 * 测试哪些类型有Class对象
 */
public class WhoHaveClass {
    public static void main(String[] args) {
        //类      class java.lang.Object
        Class c1 = Object.class;
        //接口    interface java.lang.Comparable
        Class c2 = Comparable.class;
        //数组    class [Ljava.lang.String;
        Class c3 = String[].class;
        //二维数组 class[[I
        Class c4 = int[][].class;
        //注解    interface java.lang.Override
        Class c5 = Override.class;
        //枚举    class java.lang.annotation.ElementType
        Class c6 = ElementType.class;
        //基本数据类型    class java.lang.Integer
        Class c7 = Integer.class;
        //void  代表一个空类型     void
        Class c8 = void.class;
        //Class 本身就是一个类     class java.lang.Class
        Class c9 = Class.class;

        /**只要元素类型与维度一样,就是同一个class对象
         *  一个类只有一个class对象
         */

        int[] a = new int[10];
        int[] b = new int[100];
        System.out.println(a.getClass().hashCode());
        //460141958
        System.out.println(b.getClass().hashCode());
        //460141958
    }
}

2.3 类的加载与ClassLoader

在这里插入图片描述

类的加载过程

在这里插入图片描述
在这里插入图片描述

package com.jt.reflection;
/**
 * @author CMJ
 * 2021/6/14 19:24
 * 类是如何加载的?
 * 类中的变量初始化发生了什么
 *
 * 1.加载到内存 , 产生一个类对应的class对象 , 每个类都拥有一个自己的class对象
 * 2.链接    链接结束后  m=0 , 为类变量设置初始值
 * 3.初始化    < clinit >(){
 *                  根据类变量的赋值顺序合并所有赋值动作
 *                  static int m =100;
 *                  m=300;
 *      }
 *     赋值完成,初始化完成 m=300
 * */
public class ClassInit {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(A.m);
    }
}


class A{
    static int m =100;
    static {
        System.out.println("A类的静态代码块初始化");
        m=300;
    }


    public A(){
        System.out.println("A类的无参构造初始化");
    }

}

在这里插入图片描述

在这里插入图片描述

什么时候发生类的初始化

在这里插入图片描述

/**
 * @author CMJ
 * 2021/6/14 20:23
 * 
 * 测试类什么时候会初始化
 * 
 * 类的主动引用和被动引用
 */
public class ActiveReference {
    static {
        System.out.println("main类被加载");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        //1.主动引用

        Son son = new Son();
        /**
         * main类被加载
         * 父类被加载
         * 子类被加载
         */

        //反射也是主动引用
        Class<?> son = Class.forName("com.jt.reflection.Son");
        /**
         * main类被加载
         * 父类被加载
         * 子类被加载
         * 极大的消耗资源
         */

        //2.被动引用

        //子类调用父类的静态方法或变量,不会导致子类被初始化
        System.out.println(Son.b);
        /**
         * main类被加载
         * 父类被加载
         * 2
         */

        //通过数组定义类引用,不会触发此类的初始化
        Son[] array = new Son[10];
        /**
         * main类被加载
         */

        //引用常量
        System.out.println(Son.M);
        /**
         * main类被加载
         * 1
         *
         * 因为所有的常量还有静态变量在类的链接阶段就已经设置默认初始值
         * 常量在链接阶段就存入了调用类的常量池中了
         * 静态变量可以重新赋值,而常量值不能被改变
         * 所以引用此类的常量不会触发此类的初始化
         */
    }
}
class Father{
    static int b = 2;
    static {
        System.out.println("父类被加载");
    }

}
class Son extends Father{
    static {
        System.out.println("子类被加载");
        m=300;
    }
    static int m=100;
    static final int M=1;
}

ClassLoader 类加载器

在这里插入图片描述
在这里插入图片描述

  • java核心库---------rt.jar
  • java扩展包---------jre/lib/ext
    程序不是凭空运行,由类加载器加载到内存
    在这里插入图片描述
  • 双亲委派机制
    自定义类时,不能与java核心包重名,加载自定义类时,加载器会层层向上级核实—>系统类加载器—>扩展类加载器—>引导类加载器 如自定义java.lang.String类 无法加载运行,以保证java运行环境的安全性
package com.jt.reflection;
/**
 * @author CMJ
 * 2021/6/14 21:03
 * 获取系统类加载器
 */
public class GetClassLoader {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取系统类的加载器---用户的一个类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
        //获取系统类加载器的父类加载器---扩展类加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);
        //获取扩展类加载器的父类加载器---根加载器(C/C++编写)无法打印
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);
        /**
         * sun.misc.Launcher$AppClassLoader@18b4aac2
         * sun.misc.Launcher$ExtClassLoader@1b6d3586
         * null
         */

        //测试当前类是哪个加载器加载的
        ClassLoader classLoader = Class.forName("com.jt.reflection.GetClassLoader").getClassLoader();
        System.out.println(classLoader);
        //测试JDK内置的类是谁加载的
        ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader1);
        /**
         * sun.misc.Launcher$AppClassLoader@18b4aac2
         * null
         */

        // .sout 可以把写好的代码打印
        //获得系统类加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
        /**    运行环境jar包
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\charsets.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\deploy.jar;
         *     扩展类jar包
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\access-bridge-64.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\cldrdata.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\dnsns.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jaccess.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jfxrt.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\localedata.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\nashorn.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunec.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunjce_provider.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunmscapi.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunpkcs11.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\zipfs.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\javaws.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\jce.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfr.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfxswt.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\jsse.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\management-agent.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\plugin.jar;
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\resources.jar;
         *      java核心库jar包
         * C:\Program Files\Java\jdk1.8.0_211\jre\lib\rt.jar;
         *      本类jar包
         * E:\Pritices\JavaBase_Reflection\target\classes;
         * E:\softwear\idea\IntelliJ IDEA 2021.1\lib\idea_rt.jar
         */ 
    }
}

2.4 创建运行时类的对象

获取运行时类的完整结构

在这里插入图片描述

package com.jt.reflection;
/**
 * @author CMJ
 * 2021/6/14 21:55
 * 获取类的信息
 */
public class GetClassInformation {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class<?> c1 = Class.forName("com.jt.pojo.User");
       /* User user = new User();
        Class<? extends User> c1 = user.getClass();*/
        System.out.println("获取类的全类名:"+c1.getName());
        //com.jt.pojo.User  包名.类名
        System.out.println("获取类的简单名称:"+c1.getSimpleName());
        //User   类名
        System.out.println("==============================================");
        //获得类的属性
        Field[] fields = c1.getFields();
        //只能找到public属性
        //fields.for   直接循环打印
        for (Field field : fields) {
            System.out.println(field);
        }

        Field[] fields1 = c1.getDeclaredFields();
        //可以找到全部属性
        for (Field field : fields1) {
            System.out.println(field);
        }
        /**
         * private java.lang.Integer com.jt.pojo.User.id
         * private java.lang.String com.jt.pojo.User.name
         */
        //获取指定属性
        System.out.println(c1.getDeclaredField("name"));
        System.out.println("==============================================");
        //获取类的方法
        Method[] methods = c1.getMethods();
        //获取本类及父类的所有public方法
        for (Method method : methods) {
            System.out.println("getMethods:"+method);
        }
        //获取本类所有的public和private方法
        Method[] methods1 = c1.getDeclaredMethods();
        for (Method method : methods1) {
            System.out.println("getDeclaredMethods"+method);
        }

        //获得指定方法
        //java中有方法的重载,所以在获取指定方法是需要指定参数类型
        Method getName = c1.getDeclaredMethod("getName", null);
        System.out.println(getName);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(setName);
        /**
         * public java.lang.String com.jt.pojo.User.getName()
         * public void com.jt.pojo.User.setName(java.lang.String)
         */
        System.out.println("==============================================");

    }
}

动态创建对象执行方法

  • 创建独享
    在这里插入图片描述
  • 调用指定方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 测试
package com.jt.reflection;
/**
 * @author CMJ
 * 2021/6/14 22:37
 * 通过反射,动态创建对象,调用方法和属性
 */
public class GetInstance {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class<?> c1 = Class.forName("com.jt.pojo.User");
        User user = (User) c1.newInstance();
        System.out.println(user);
        /**
         * User{id=null, name='null'}
         * 该方法本质上调用无参构造创建对象
         */

        //通过构造器创建对象
        Constructor<?> Constructor = c1.getDeclaredConstructor(Integer.class, String.class);
        User user2 = (User) Constructor.newInstance(18, "爱我中华");
        System.out.println(user2);
        /**
         * User{id=18, name='爱我中华'}
         * 构造器可通过有参构造创建User对象
         */

        User user3= (User) c1.newInstance();
        //通过反射调用普通方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //invoke:激活的意思 需要传递的参数("哪个对象的方法","方法的参数值")
        setName.invoke(user3,"猪八戒");
        System.out.println(user3.getName());
        /**
         * 猪八戒
         */
        //通过反射操作属性
        User user4= (User) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true);
        name.set(user4,"孙悟空");
        System.out.println(user4.getName());
        /**
         *  can not access a member of class
         *  com.jt.pojo.User with modifiers "private"
         * 可以获取私有属性信息,但是不能直接操作私有属性
         * 需要关闭关闭程序的安全检测,操作私有属性和方法通用的
         *
         * 孙悟空
         */
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值