Java——注解与反射文章

1.什么是注解

注解可以被其他程序(比如编译器)读取

2.内置注解

@Override:重写

@Deprecated:废弃

@SuppressWarnings(""):抑制编译时的警告信息(需要添加参数)

3.元注解

负责注解其他注解

@Target:被描述的注解可以用在什么地方

@Retention:表示需要在什么级别保存改注释信息,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)什么时候有效

@Documented:说明该注解将被包含在javadoc中

@Inherited:说明子类可以继承父类中的该注解

4.自定义注解

使用@interface自定义注解:

//自定义注解

public class Test03 {

    //注解可以显示的赋值,如果没有默认值,我们就必须该注解赋值

    @MyAnnotation2(age = 18)

    public void test(){}

    @MyAnnotation3("ikun")

    public void Test2(){}

}

@Target({ElementType.TYPE,ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@interface MyAnnotation2{

    //这不是方法,是注解的参数

    String name() default "";

    int age() default 0;//默认值是-1代表不存在

    String[] schools() default {"清华","北大"};

}

@Target({ElementType.TYPE,ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@interface MyAnnotation3{

    //这不是方法,是注解的参数

    String value();


}


5.反射概述

动态语言:就是在运行时代码可以根据某些条件改变自身结构(c#,JavaScript,php,python)

静态语言:运行时结构不可变(Java,C,C++)

在java中我们可以利用反射机制获得类似动态语言的特性

Java Reflection

6.获得反射对象

反射相关的主要API

java.lang.Class:代表-个类

java.lang.reftect.Method:代表类的方法

java.lang.reflect.Field:代表类的成员变量

java.lang.reflect.Constructor:代表类的构造器

7.得到class类的几种方式(重点)

Class类

对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。

对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特

定某个结构(class/.interface/.enum/annotation/primitive type/.void/们)的有关信息。

Class本身也是一个类

Class对象只能由系统建立对象

一个加载的类在JVM中只会有一个Class实例

一个Class对象对应的是一个加载到JVM中的一个.class文件

每个类的实例都会记得自己是由哪个Class实例所生成

通过Classi可以完整地得到一个类中的所有被加载的结构

Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象

//方式一:通过对象获得

        Class  c1 = person.getClass();

        System.out.println(c1.hashCode());

        //方式二:forName获得(常用)

        Class  c2 = Class.forName("com.qjd.reflection.Student");

        System.out.println(c2.hashCode());

        //方式三:通过类名.class

        Class  c3 = Student.class;

        System.out.println(c3.hashCode());

        //方式四:基本内置类型的包装类都有一个Type属性

        Class  c4 = Integer.TYPE;

        System.out.println(c4);

8.所有类型的class对象

哪些类型可以有Class对象

class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。

interface:接口

[]:数组

enum:枚举

annotation:注解@interface

primitive type:基本数据类型

void

9.类加载内存分析

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化

public class Test05 {

    public static void main(String[] args) {

        A a = new A();

        System.out.println(A.m);

        /**

        * 1.加载到内存,会产生一个类对应Class对象

        * 2.链接,链接结束后,m=0

        * 3.初始化

        *  <clinit>{  System.out.println("A类静态代码块初始化");

        *              m=300;

        *              m=100;

        *  }

        *

        *  m=100

        *

        *

        */

    }

}

class A{

        static{

            System.out.println("A类静态代码块初始化");

            m=300;

        }

        /*

        * m=300

        * m=100

        * */

        static int m = 100;

        public A(){

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

        }

}

内存图分析

10.分析类初始化

注:常量不会引发初始化

11.类加载器

public class Test07 {

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

        //测试当前类是哪个加载器加载的(系统)

        ClassLoader classLoader = Class.forName("com.qjd.reflection.Test07").getClassLoader();

        System.out.println(classLoader);

        //测试jdk内置的类是哪个加载器加载的(根)

        classLoader = Class.forName("java.lang.Object").getClassLoader();

        System.out.println(classLoader);

        //如何获得系统类加载器可以加载的路径

        System.out.println(System.getProperty("java.class.path"));

        //D:\Program Files (x86)\java\jdk1.8\jre\lib\charsets.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\deploy.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\cldrdata.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\dnsns.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\jaccess.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\jfxrt.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\localedata.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\nashorn.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\sunec.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\sunmscapi.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\ext\zipfs.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\javaws.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\jce.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\jfr.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\jfxswt.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\jsse.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\management-agent.jar;D

        // :\Program Files (x86)\java\jdk1.8\jre\lib\plugin.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\resources.jar;

        // D:\Program Files (x86)\java\jdk1.8\jre\lib\rt.jar;

        // E:\SSM\反射和注解\reflect\target\classes;

        // E:\Java\IntelliJ IDEA 2020.3.4\lib\idea_rt.jar



        //双亲委派机制

        //(如果存在重名)检测跟加载器的包而不是自己写的

    }

}

12.创建运行时类的对象(重点)

//获得类的信息

public class Test08 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {

        Class c1 = Class.forName("com.qjd.reflection.User");

        //获得类的名字

        System.out.println(c1.getName());//包名加类名

        System.out.println(c1.getSimpleName());//类名

        //获得类的属性

        System.out.println("===========================================================");

        Field[] fields = c1.getFields();//只能找到public属性

        fields = c1.getDeclaredFields();//找到全部的属性

        for (Field field : fields) {

            System.out.println(field);

        }

        //获得指定属性的值

        Field name = c1.getDeclaredField("name");

        System.out.println(name);

        //获得类的方法

        System.out.println("===========================================================");

        Method[] methods = c1.getMethods();//获得本类及其父类全部的public方法

        for (Method method : methods) {

            System.out.println("正常的"+method);

        }

        Method[] declaredMethods = c1.getDeclaredMethods();//获得本类的所有方法包括private方法

        for (Method declaredMethod : declaredMethods) {

            System.out.println("declaredMethods"+declaredMethod);

        }

        //获得指定方法

        //重载

        System.out.println("===========================================================");

        Method getName = c1.getMethod("getName", null);

        Method setName = c1.getMethod("setName", String.class);

        System.out.println(getName);

        System.out.println(setName);

        //获得构造器

        System.out.println("===========================================================");

        Constructor[] constructors = c1.getConstructors();//获得public方法

        for (Constructor constructor : constructors) {

            System.out.println(constructor);

        }


        Constructor[] declaredConstructors = c1.getDeclaredConstructors();//获得全部方法

        for (Constructor declaredConstructor : declaredConstructors) {

            System.out.println(declaredConstructor);

        }

        //获得指定的构造器

        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);

        System.out.println("指定的"+declaredConstructor);

    }

}

13.动态创建对象执行方法(重点)

代码实现

//动态创建对象,通过反射

public class Test09 {

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

        //获得Class对象

        Class c1 = Class.forName("com.qjd.reflection.User");

        //构造一个对象

        //User user = (User) c1.newInstance();//本质上是调用类的无参构造器

        //System.out.println(user);

        //通过构造器创建对象

//        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);

//        User user2 = (User) constructor.newInstance("ikun",001,18);

//        System.out.println(user2);

        //通过反射调用普通方法

        User user3 = (User) c1.newInstance();

        //通过反射获取一个方法

        Method setName = c1.getMethod("setName", String.class);

        //invoke激活

        //(对象,“方法的值”)

        setName.invoke(user3,"kunkun");

        System.out.println(user3.getName());

        //通过反射操作属性

        System.out.println("===========================================");

        User user4 = (User) c1.newInstance();

        Field name = c1.getDeclaredField("name");

        //不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true);

        name.setAccessible(true);

        name.set(user4,"坤坤");

        System.out.println(user4.getName());

    }

}

14.性能对比分析

//分析性能问题

public class Test10 {

    //普通方式调用

    public static void test01(){

        User user = new User();

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 1000000000; i++) {

            user.getName();

        }

        long endTime = System.currentTimeMillis();

        System.out.println("普通方式执行1000000000次:"+(endTime-startTime)+"ms");

    }

    //反射方式调用

    public static void test02() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {

        User user = new User();

        Class c1 = user.getClass();

        Method getName = c1.getDeclaredMethod("getName", null);

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 1000000000; i++) {

            getName.invoke(user,null);

        }

        long endTime = System.currentTimeMillis();

        System.out.println("反射方式执行1000000000次:"+(endTime-startTime)+"ms");

    }

    //反射方式调用  关闭检测

    public static void test03() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {

        User user = new User();

        Class c1 = user.getClass();

        Method getName = c1.getDeclaredMethod("getName", null);

      getName.setAccessible(true);

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 1000000000; i++) {

            getName.invoke(user,null);

        }

        long endTime = System.currentTimeMillis();

        System.out.println("关闭检测执行1000000000次:"+(endTime-startTime)+"ms");

    }

    public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        test01();

        test02();

        test03();

    }

}

结果

15.获取泛型信息

反射操作泛型

Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除

为了通过反射操作这些类型,Java新增ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型

ParameterizedType:表示一种参数化类型,比如Collection

GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

ypeVariable:是各种类型变量的公共父接口

WildcardType:代表一种通配符类型表达式

16.反射操作注解

ORM

//练习反射操作注解

public class Test12 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {

        Class c1 = Class.forName("com.qjd.reflection.Student2");

        //通过反射获得注解

        Annotation[] annotations = c1.getAnnotations();

        for (Annotation annotation : annotations) {

            System.out.println(annotation);

        }

        //获得注解的value的值

      TableQjd tableQjd = (TableQjd)c1.getAnnotation(TableQjd.class);

        String value = tableQjd.value();

        System.out.println(value);

        //获得类指定的注解

        System.out.println("===================");

        Field field = c1.getDeclaredField("name");

        FieldQjd annotation = field.getAnnotation(FieldQjd.class);

        System.out.println(annotation.columnName());

        System.out.println(annotation.type());

        System.out.println(annotation.length());

    }

}

@TableQjd("db_student")

class Student2{

    @FieldQjd(columnName = "db_id",type = "int",length = 10)

    private int id;

    @FieldQjd(columnName = "db_age",type = "int",length = 10)

    private int age;

    @FieldQjd(columnName = "db_name",type = "varchar",length = 3)

    private String name;

    public Student2(int id, int age, String name) {

        this.id = id;

        this.age = age;

        this.name = name;

    }

    public Student2() {

    }

    @Override

    public String toString() {

        return "Student2{" +

                "id=" + id +

                ", age=" + age +

                ", name='" + name + '\'' +

                '}';

    }

    public int getId() {

        return id;

    }

    public void setId(int id) {

        this.id = id;

    }

    public int getAge() {

        return age;

    }

    public void setAge(int age) {

        this.age = age;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

}

//类名的注解

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@interface TableQjd{

    String value();

}

//属性的注解

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

@interface FieldQjd{

    String columnName();

    String type();

    int length();

}

喜欢的话,记得点赞,关注+转发!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容