Java注解和反射

注解(Annotation)

注解入门

  • 注解是从jdk5.0开始引入

  • 注解的作用:

    可以对程序作出解释

    可以被其他程序读取

  • 注解的格式:@注解名

  • 注解可以在package,class,method等上面,相当于给他们添加了额外的辅助信息

内置注解

  1. @Override,用于修饰方法,表示该方法重写

  2. @Deprecated,用于修改方法,属性,类,表示不建议使用这样的元素,已过时

  3. @SuppressWarnings,用来抑制编译时的警告信息,需要添加一个参数

    @SuppressWarnings("all") @SuppressWarnings("unchecked")等等

元注解

//定义一个注解
//Target表示注解可以用在那些地方  方法,类和接口
@Target(value = {ElementType.METHOD,ElementType.TYPE})
​
//Retention表示注解在什么地方有效
//routime>class<sources
@Retention(value = RetentionPolicy.RUNTIME)
​
//表示我们的注解生成在javadoc中
@Documented
​
//子类可以继承父类的注解
@Inherited
@interface MyAnnoation{
​
}

 

自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
​
public class Test01 {
​
    //显式赋值name,不赋值默认为"",如果没用默认值则必须要给name赋值
    @MyAnnotation(name="dd",school = {"zha","xer"})
    public void test(){}
​
    //可以不用写参数名,默认为value
    @MyAnnoation2("空间")
    public void test2(){}
}
​
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
​
    //注解的参数:参数类型+参数名()
    String name() default "";
    int age() default 0;
    String[] school();
}
​
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnoation2{
    String value();
}

 

反射(Reflection)

反射是java被视为动态语言的关键

反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能给直接和操作对象的内部属性及方法

正常方式:引入需要的包---new实例化----取得实例化对象

反射方式:实例化对象---getClass()方法---得到完整的包类名称

package com.henry.reflect;
​
public class TestReflect {
    public static void main(String[] args) throws ClassNotFoundException {
​
        //通过反射获取类的class对象
        Class c1 = Class.forName("com.henry.reflect.User");
        Class c2 = Class.forName("com.henry.reflect.User");
​
        //一个类在内存中只有一个class对象,c1和c2的hashcode相同
        //一个类被加载后,类的整个结构都会被封装在class对象中
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
    }
}
​
//实体类
class User{
    private String name;
    private int id;
    private int age;
​
    public User() {
    }
​
    public User(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 "User{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }
}

 

获取Class类的实例

  1. Class c1 = Person.class

  2. Class c2 = person.getClass()

  3. Class c3 = Class.forName("demo.Person")

//测试class类的创建方式
public class TestGetClass {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println(person.name);
​
        //方式1,通过对象获得class
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());
​
        //方式2,forname
        Class c2 = Class.forName("com.henry.reflect.Student");
        System.out.println(c2.hashCode());
​
        //方式3 类名.class
        Class c3 = Student.class;
        System.out.println(c3.hashCode());
​
        //获得父类类型
        System.out.println(c1.getSuperclass());
    }
}
​
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对象

  1. class,类

  2. interface 接口

  3. 数组

  4. enum 枚举

  5. annotation 注解

  6. 基本数据类型

  7. void

Class c1 = Object.class; //类
Class c2 = Runnable.class; //接口
Class c3 = int[].class; //数组
Class c4 = Override.class; //注解
Class c5 = ElementType.class; //枚举
Class c6 = Integer.class; //基本数据类型
Class c7 = void.class;

只要元素类型一样,就是同一个Class

类加载内存分析

 

 

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

    static int m = 100;
    public A(){
        System.out.println("A的无参构造初始化");
    }
}

 

 

类初始化

public class Test06 {
    static {
        System.out.println("主类被加载");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        //主动引用
        //Son son = new Son();//主类被加载,父类被加载,子类被加载
//反射也会产生主动引用
        //Class.forName("com.henry.reflect.Son");
//不会产生类的引用的方法
        //System.out.println(Son.f);//调用父类的静态方法或者变量,不会初始化子类  //主类被加载,父类被加载,1
//Son[] array = new Son[5]; //主类被加载
        System.out.println(Son.S);  //主类被加载,2
    }
}
​
class Father{
    static int f = 1;
    static {
        System.out.println("父类被加载");
    }
}
​
class Son extends Father{
    static {
        System.out.println("子类被加载");
    }
​
    static int m = 100;
    static final int S = 2;
}

 

类加载器的作用

类加载的作用:将class字节码加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后再堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口

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++编写)无法获取
        System.out.println(parent.getParent());
​
        //测试当前类是哪个加载器加载的
        System.out.println(Test07.class.getClassLoader());//系统类加载器
​
        System.out.println(Class.forName("java.lang.Object").getClassLoader());//根加载器
//获得系统类加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
    }
}

 

通过反射获取类的完整结构

Class c1 = Class.forName("User");
//获得类的名字
System.out.println(c1.getName()); //获得包名+类名
System.out.println(c1.getSimpleName());//获得类名
//获得类的属性
Field[] fields = c1.getFields();//只能找到public属性的
fields = c1.getDeclaredFields(); //找到全部属性
for (Field field : fields) {
    System.out.println(field);
}
​
//获得指定属性的值
Field name = c1.getDeclaredField("name");//因为是私有的,不能getField
System.out.println(name);
​
//获得类的方法
Method[] methods = c1.getMethods();//获得本类和父类的public方法
c1.getDeclaredMethods();//获得本类的所有方法
//获得指定方法
Method getName = c1.getMethod("getName", null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
​
//获得构造器
Constructor[] constructors = c1.getConstructors();//获得public构造器
for (Constructor constructor : constructors) {
    System.out.println(constructor);
}
c1.getDeclaredConstructors();//获得所有的构造器
//获得指定的构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
System.out.println(declaredConstructor);

 

动态的创建对象

public class Test09 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得class对象
        Class c1 = Class.forName("com.henry.reflection.User");
​
        //构造一个对象
        User user = (User) c1.newInstance();//本质上调用了类的无参构造器
        System.out.println(user);
​
        //通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class);
        User user2 = (User) constructor.newInstance("张虎", 12);
        System.out.println(user2);
​
        //通过反射调用普通方法,如果方法为私有的需要关闭安全检测 setName.setAccessible(true);
        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());
    }
}

 

性能对比分析

public class Test10 {
    //普通方式调用
    public static void u1(){
        User user1 = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            user1.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("用的时间:"+(endTime-startTime)+"ms");
    }
​
    //反射方式调用
    public static void u2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            getName.invoke(user, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("用的时间:"+(endTime-startTime)+"ms");
    }
​
    //反射方式调用,关闭检测,能够提高效率
    public static void u3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        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 < 100000; i++) {
            getName.invoke(user, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("用的时间:"+(endTime-startTime)+"ms");
    }
​
​
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        u1();
        u2();
        u3();
    }
}

 

 

通过反射获取泛型信息

//通过反射获取泛型
public class Test11 {
    public void t1(Map<String,User> map, List<User> list){
        System.out.println("t1");
    }
​
    public Map<String,User> t2(){
        System.out.println("t2");
        return null;
    }
​
    public static void main(String[] args) throws NoSuchMethodException {
        //参数
        Method method = Test11.class.getDeclaredMethod("t1", Map.class, List.class);
        Type[] genericExceptionTypes = method.getGenericParameterTypes();
        for (Type genericExceptionType : genericExceptionTypes) {
            System.out.println(genericExceptionType);
            if(genericExceptionType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) genericExceptionType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
​
        System.out.println("---------------------------");
        //返回值
        Method method2 = Test11.class.getDeclaredMethod("t2", null);
        Type genericReturnType = method2.getGenericReturnType();
        System.out.println(genericReturnType);
        if(genericReturnType instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }
}

 

获取注解信息

ORM:Object relationship mapping 对象关系映射

public class Test12 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.henry.reflection.Student2");
        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
​
        //获得注解的value值
        TableYD tableYD = (TableYD)c1.getAnnotation(TableYD.class);
        System.out.println(tableYD.value());
​
        //获得类指定的注解
        Field name = c1.getDeclaredField("name");
        FieldYD annotation = name.getAnnotation(FieldYD.class);
        System.out.println(annotation);
        System.out.println(annotation.columnName());
        System.out.println(annotation.length());
        System.out.println(annotation.type());
    }
}
​
@TableYD("db_student")
class Student2{
    @FieldYD(columnName = "db_id",type = "int",length = 10)
    private int id;
    @FieldYD(columnName = "db_age",type = "int",length = 10)
    private int age;
    @FieldYD(columnName = "db_name",type = "varchar",length = 10)
    private String name;
​
    public Student2() {
    }
​
    public Student2(int id, int age, String name) {
        this.id = id;
        this.age = age;
        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;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    @Override
    public String toString() {
        return "Student2{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
​
//类名的注解 Target注解的使用范围,retention描述注解的声明周期(SOURCE<CLASS<RUNTIME)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableYD{
    String value();
}
​
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldYD{
    String columnName();
    String type();
    int length();
}

 

 

 

posted @ 2020-10-13 14:35  Henry829  阅读(197)  评论(0编辑  收藏  举报