注解与反射机制(Annocation、Reflection)

注解(Java.Annotation)

注释(comment)

注解作用:

1.可以被其他程序(比如:编译器等)读取

2.不是程序本身,可以对程序作出解释(和注释差不多)

注解的格式:

@注解名,还可以添加一些内置参数值

比如@SuppressWarnings(value = "unchecked")

注解的使用地点:

可以在package,class,method,field上使用,相当于给他们添加了一些辅助信息,我们可以通过反射机制编程实现对这些源数据的访问

内置注解

注解的常用几种:

@Override 方法的重写

@Deprecated 不推荐使用,或存在危险,有更好的方法替代,但是可以使用,使用的方法打有横杠

@SuppressWarnings()镇压警告,编写代码时,黄色警告被镇压,后面有参数,可以传递一个或多个参数

@SuppressWarnings("all")

@SuppressWarnings("unchecked")

@SuppressWarnings("unchecked","desprecatoin"),

元注解

作用:用来注解其他注解

//Target,用来注解自定义注解的使用范围,
//参数类型 ElementType[] value()
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//Retention,表示注解在什么时候有效
//SOURCE<CLASS<RUNTIME
@Retention(RetentionPolicy.SOURCE)
//Documented  该注解是否出现在javadoc里面
@Documented
//Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{

}
自定义注解
package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//自定义注解
public class TestAnnotation02 {
    //注解可以显示赋值,如果没有默认值,必须赋值
    @MyAnnotation02(name = "小明")
    public void test01(){

    }
    @MyAnnotation03("小明")
    public void test03(){

    }
}
//元注解,对自定义注解的注解
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
//自定义注解的格式 public @interface 自定义注解名
@interface MyAnnotation02{
    // 注解的参数  参数类型 参数名() ;
    String name();
    //设置 默认值格式为  参数类型 参数名() default 默认值;
    int age() default 21;

}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation03{
    //如果注释中只有一个参数,将参数名命名为value,这样在赋值时候,可以省略赋值名
    String value();
}
添加的这些辅助信息,可以通过反射机制来读取这些元数据信息

反射机制(Reflection)

静态语言与动态语言

动态语言:在运行的时候可以改变其结构的语言:比如javascript、Object-C、C#、PHP、phython

静态语言:在运行时结构不发生改变:比如Java,C,C++

Java不是动态语言,但是可以通过反射机制来获得类似动态语言,可以成为“准动态语言”。

Java反射机制提供的功能

1.运行时判断任意一个对象所属的类

2.运行时构造任意一个类对象

3..运行时判断任意一个类所具有的成员变量和方法

4.在运行时获取泛型信息

5.在运行时调用任意一个对象的成员变量和方法

6.在运行时处理注解

7.生成动态代理

............

Java反射的优缺点

优点:可以实现动态创建对象和编译,体现出很大的灵活性

缺点:对性能有影响。使用反射基本是一种解释操作,我们可以告诉jvm,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。

package annotation;

public class TestReflect01 extends Object{
    public static void main(String[] args) throws ClassNotFoundException {
        //通过反射来获取类的Class对象
        Class c1 = Class.forName("annotation.User");
        Class c2 = Class.forName("annotation.User");
        Class c3 = Class.forName("annotation.User");

        //一个类在内存中只有一个Class对象
        //一个类被加载后,类的整个结构都会被封装在Class对象中
        System.out.println(c1);//三者输出相同
        System.out.println(c2);
        System.out.println(c3);
    }
}

class User{
    private String name;
    private int age;
    private int id;

    public User() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
}
获取class对象的几种方法:
package annotation;
//获取class对象的几种方法
public class TestReflect02 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person student = new Student();
        //通过在Object类中继承的getClass()方法,来返回一个class对象
        Class c1 = student.getClass();
        System.out.println(c1);//c1,c2,c3打印结果相同

        //通过Class类中静态方法forName("类的路径(className)"),来返回一个class对象,这个方法必须知道其类的地址
        Class c2 = Class.forName("annotation.Student");
        System.out.println(c2);

        //通过类名.class,来返回一个class对象
        Class c3 = Student.class;
        System.out.println(c3);

        //基本内置类型的包装类都有一个TYPE属性,可以通过这个静态属性来返回一个class对象
        Class<Integer> c4 = Integer.TYPE;
        System.out.println(c4);//int

        //获取父类class对象
        Class superclass = c1.getSuperclass();
        System.out.println(superclass);

    }
}

class Person {
    public String name;

    public Person() {
    }

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

class Student extends Person{
    public Student() {
        this.name = "学生";
    }

}

class Teacher extends Person{
    public Teacher() {
        this.name = "老师";
    }
}
哪些类型可以有Class对象?

只要元素的类型和纬度是一样的,就是同一个Class.

package annotation;

import java.lang.annotation.ElementType;

public class TestClass01 {
    public static void main(String[] args) {
        Class c1 = Object.class;//类的class对象
        Class c2 = Comparable.class;//接口的class对象
        Class c3 = String[].class;//一维数组的class对象
        Class c4 = int[][].class;//二维数组的class对象
        Class c5 = Override.class;//注解的class对象
        Class c6 = ElementType.class;//枚举的class对象
        Class c7 = Integer.class;//基本数据类型的class对象
        Class c8 = void.class;//void类型的class对象
        Class c9 = Class.class;//class类型的class对象

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);


        //只要元素的类型和纬度是一样的,就是同一个Class.
        int[] a = new int[10];
        int[] b = new int[100];
        System.out.println(a.getClass());//两者相同
        System.out.println(b.getClass());




    }
}

运行结果:

类的加载过程

类初始化

package annotation;
//测试类初始化时,主动引用和被动引用
public class TestClass02 {
    static {
        System.out.println("main类被加载");

    }

    public static void main(String[] args) throws ClassNotFoundException {
        //1.主动引用,先加载父类,再加载子类
//        Son son = new Son();

        //2.反射也会产生主动引用
//        Class.forName("annotation.Son");

        //3.不会产生类的引用
//        System.out.println(Son.b);//调用父类的静态常量,son本身不会加载,father被加载了
//        Son[] sons = new Son[10];//子类和父类都不会加载

        System.out.println(Son.M);//常量池中常量,并不会引起子类和父类的加载
    }
}

class Father{
    static int b = 2;
    static {
        System.out.println("父类被加载了");
    }
}

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

    static final int M = 10;//常量池
}
类加载器

用class类中的方法来获取该类的类名、属性、方法、构造器
package annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

//测试用class类中的方法来获取该类的类名、属性、方法、构造器
public class TestClass04 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("annotation.A");

        //获取类名
        System.out.println(c1.getName());//包名.类名
        System.out.println(c1.getSimpleName());//简单的类名

        System.out.println("====================");
        //获取属性
        Field[] fields = c1.getFields();//获取公共属性
        for (Field field : fields) {
            System.out.println(field);
        }

        fields = c1.getDeclaredFields();//获取全部属性
        for (Field field : fields) {
            System.out.println("----"+field);
        }

        System.out.println(c1.getField("name"));//获取特定名称的公共属性
        System.out.println(c1.getDeclaredField("id"));//获取特定名称的属性,包括私有属性

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

        //获取类的方法
        Method[] methods = c1.getMethods();//获取该类的所有公共方法,包括继承来的,不包括私有方法
        for (Method method : methods) {
            System.out.println(method);
        }

        methods = c1.getDeclaredMethods();//获取该类本身自有的方法,包括私有方法
        for (Method method : methods) {
            System.out.println("-----"+method);
        }

        System.out.println(c1.getMethod("getName",null));//返回指定名称的公有方法,为什么会名称后有参数,方法的重载
        System.out.println(c1.getDeclaredMethod("test",null));//返回指定名称的所有方法,包括私有方法

        System.out.println("====================");
        //获取类的构造器
        Constructor[] constructors = c1.getConstructors();//获取公共构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        constructors = c1.getDeclaredConstructors();//获取所有构造器,包括私有
        for (Constructor constructor : constructors) {
            System.out.println("----"+constructor);
        }

        System.out.println(c1.getConstructor(String.class, int.class, int.class));//获取指定参数类型的公有构造器
        System.out.println("---"+c1.getDeclaredConstructor(String.class, int.class, int.class));//获取指定参数类型的构造器,包括私有构造器


    }
}



class A{
    public String name;
    private int id;
    public int age;

    public A() {
    }

    public A(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.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;
    }
    private void test(){}
}
动态创建对象执行方法
package annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

//通过反射,来动态的创建对象
public class TestClass05 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获取class对象
        Class c1 = Class.forName("annotation.B");

        //构造一个对象
      /*  B b = (B)c1.newInstance();//本质是调用类的无参构造器
        System.out.println(b);*/

        //通过调用构造器,来创建对象
        /*Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);//本质是调用了有参的构造器
        B b1 = (B)constructor.newInstance("小明", 0001, 12);
        System.out.println(b1);*/

        //通过反射来操作方法
        B b2 = (B)c1.newInstance();
        Method setName = c1.getDeclaredMethod("setName", String.class);
        setName.invoke(b2,"小明");//invoke:激活(对象,方法参数列表的值)
        System.out.println(b2);

        //通过反射操作属性
        //不能直接操作私有属性,需要取消安全检测,setAccessible(true)
        B b3 = (B)c1.newInstance();
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true);//因为属性为private,需要取消安全检查,默认为false,为true时,取消安全检查
        name.set(b3,"小明");
        System.out.println(b3);


    }
}

class B{
    private String name;
    private int id;
    private int age;

    public B() {
    }

    public B(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.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;
    }

    @Override
    public String toString() {
        return "B{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }
}

性能比较
package annotation;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

//分析性能问题
public class TestClass06 {
    //普通方法调用
    public static void test01(){
        C c = new C();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            c.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("普通方法执行10亿次需要"+(endTime-startTime)+"ms");
    }

    //反射方式调用
    public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        C c = new C();
        long startTime = System.currentTimeMillis();
        Class c1 = c.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(c,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方式调用执行10亿次需要"+(endTime-startTime)+"ms");
    }

    //反射方式调用  关闭检测
    public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        C c = new C();
        long startTime = System.currentTimeMillis();
        Class c1 = c.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        getName.setAccessible(true);
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(c,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方式调用  关闭检测执行10亿次需要"+(endTime-startTime)+"ms");
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test01();
        test02();
        test03();
    }

}

class C{
    private String name;

    public C() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

运行结果:

所以,能关闭安全检测,就关闭安全检测,这样能加快程序的运行速度

反射操作泛型

空缺,需补齐

反射操作注解

ORM:Object relationship Mapping 对象关系映射(类生成的对象与数据库中的表对应)

package annotation;

import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Type;

//练习反射操作注解
public class TestClass07 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        //通过反射获得注解,同时获得注解的值
        Class c = Class.forName("annotation.Worker");
        AnnocationClass annocationClass = (AnnocationClass)c.getAnnotation(AnnocationClass.class);
        System.out.println(annocationClass.value());

        //获得类中指定的注解(获取特定注解,必须要获取特定的该元素)
        Field name = c.getDeclaredField("name");
        AnnocationField annotation = (AnnocationField)name.getAnnotation(AnnocationField.class);
        System.out.print(annotation.columnName()+" ");
        System.out.print(annotation.type()+" ");
        System.out.print(annotation.length()+" ");



    }
}

@AnnocationClass("db_table")
class Worker{
    @AnnocationField(columnName = "varchar",type = "String",length = 3)
    private String name;
    @AnnocationField(columnName = "id",type = "int",length = 10)
    private int id;
    @AnnocationField(columnName = "age",type = "int",length = 3)
    private int age;

    public Worker() {
    }

    public Worker(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.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;
    }

    @Override
    public String toString() {
        return "Worker{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }
}


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface AnnocationClass{
    String value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface AnnocationField{
    String columnName();
    String type();
    int length();
}
posted @ 2020-08-05 22:26  DannyBoy~  阅读(213)  评论(0编辑  收藏  举报