注解与反射

注解(Annotation)

内置注解

  1. 类似于@overrided

元注解

  1. @Target 表示注解我们可以用在哪些地方

  2. @Retention 表示我们的注解在什么地方还有效 (runtimes>class>sources) 定义了runtime,就在任意地方都有效

  3. @Documengted 表示是否将我们的注解生成在JAVAdoc中

  4. @Inherited 表示子类可以继承父类的注解

自定义注解

使用@interface可以自定义注解 public @interface 注解名 {注解的参数:参数类型 +参数名();【如果定义的参数没有默认值,那么必须给注解赋值,否则报错;如果默认值为-1,代表不存在】};

一般自定义注解都是先将元注解:

@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)进行定义

 

 

反射(Reflection)

  1. 通过反射获取class类

    //通过反射获取类的class对象
    Class c1=Class.forName("User");
    System.out.println(c1);

    //定义多个class类指向同一个包
    Class c2=Class.forName("User");
    Class c3=Class.forName("User");
    Class c4=Class.forName("User");

    //一个类在内存中只有一个class对象,都是一个hashcode地址
    //一个类被加载之后,类的整个结构都会被封装在class对象中
    System.out.println(c2.hashCode());
    System.out.println(c3.hashCode());
    System.out.println(c4.hashCode());

 

  1. class类的创建方式

Person person = new Student();
System.out.println("这个人是:"+person.name);

//方式一:通过对象,获取class类
Class c1=person.getClass();
System.out.println(c1.hashCode());
//方式二:通过forName获取
Class c2=Class.forName("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);
//可以获取父类得类型
Class c5=c1.getSuperclass();
System.out.println(c5);

 

  1. 那些类型有class对象

Class c1=Object.class;    //类
Class c2=Comparable.class;  //接口
Class c3=String[].class;    //一维数组
Class c4=int[][].class;    //二维数组
Class c5=Override.class;    //注解
Class c6= ElementType.class;  //枚举
Class c7=Integer.class;      //基本数据类型
Class c8=void.class;    //void
Class c9=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().hashCode());
System.out.println(b.getClass().hashCode());
System.out.println(a.hashCode());

 

  1. 类加载内存分析对象

    (1)java文件通过jdk编译成class文件,然后通过类加载器将class文件加载在内存中,在堆中生成一个这个类对应的class对象

    (2)链接,链接回在方法去中将类对象中的静态方法和常量进行初始值的赋值,然后进行分配

    (3)初始化(clinit),会将数据进行加载和相同代码的合并

  2. 如何类才会进行初始化

    1.主动引用(Son s1=new Son();)

    2.反射也会产生主动引用(class.forName(包名))

    3.调用父类的静态变量不会引起之类的初始化

    4.常量的引用不会引起子类与父类的引用

  3. 类加载器

     //获取系统类的加载器
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

    //获取系统类加载器的父类加载器-->扩展类加载器
    ClassLoader parent = systemClassLoader.getParent();

    //获取扩展类加载器的父类加载器-->根加载器(用C、C++编写的)
    ClassLoader parent1 = systemClassLoader.getParent();

    //测试当前类是那个加载器加载的
    ClassLoader classLoader = Class.forName("Test").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"));
  4. 如何通过反射获取类的信息

    Class c1 = Class.forName("Person");
    //获取类的名字
    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);

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

    //获取指定的方法
    //因为方法有重载的机制,所以如果方法有参数,就需要传递参数
    Method method=c1.getMethod("toString");

    //获取指定类的构造器
    Constructor[] constructors=c1.getConstructors();
    constructors=c1.getDeclaredConstructors();

    //获取指定有参的构造器
    Constructor constructor=c1.getDeclaredConstructor(String.class);
  5. 通过class对象可以干什么?

 

//获得class对象
 Class c1 = Class.forName("Person");
 Person person = (Person)c1.newInstance();//本质上是调用了类的无参构造器;没有数据
 System.out.println(person);

 //通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class);
 Person person1 = (Person) constructor.newInstance("quchaunming");
 System.out.println(person1);

 //通过反射调用方法
 Person person = (Person) c1.newInstance();
 //通过反射获取一个方法
 Method method = c1.getDeclaredMethod("setName",String.class);
 //激活该对象中的方法
 method.invoke(person,"quchuanming");
 System.out.println(person.getName());

 //通过反射调用属性
 Person person1 = (Person) c1.newInstance();
 Field field = c1.getDeclaredField("name");
 //私有的属性你可以获得到,但是不能直接操作,需要关闭程序的安全检测。属性或者方法的setAccessible(true)
 field.setAccessible(true);
 field.set(person1,"qu2");
 System.out.println(person1.getName());
  1. 创建对象的正常方法和反射方法的性能对比

       //普通方式调用
       public static void testprofile1() {
           Person p1 = new Person();
           long starttime=System.currentTimeMillis();
           for (int i = 0; i < 10000000; i++) {
               p1.getName();
          }
           long enddtime = System.currentTimeMillis();
           System.out.println("普通方法执行花费:"+(enddtime-starttime));
      }

       //反射方式调用
       public static void testprofile2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
           Class c1 = Class.forName("Person");
           Person p1 = (Person)c1.newInstance();
           Method method = c1.getDeclaredMethod("getName",null);
           long starttime=System.currentTimeMillis();
           for (int i = 0; i < 10000000; i++) {
               method.invoke(p1,null);
          }
           long enddtime = System.currentTimeMillis();
           System.out.println("反射方式调用花费:"+(enddtime-starttime));
    }
    //反射方式调用 关闭检测
    public static void testprofile3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
       Class c1 = Class.forName("Person");
       Person p1 = (Person)c1.newInstance();
       Method method = c1.getDeclaredMethod("getName",null);
       method.setAccessible(true);
       long starttime=System.currentTimeMillis();
       for (int i = 0; i < 10000000; i++) {
           method.invoke(p1,null);
      }
       long enddtime = System.currentTimeMillis();
       System.out.println("反射方式调用 关闭检测:"+(enddtime-starttime));
    }
  2. 反射操作泛型

    Method method = Test.class.getDeclaredMethod("Test1",Map.class,List.class);
    Type[] types = method.getGenericParameterTypes();
    for (Type type : types) {
        System.out.println("||"+type);
        if(type instanceof ParameterizedType){
           Type[] actural = ((ParameterizedType)type).getActualTypeArguments();
            for (Type type1 : actural) {
                System.out.println(type1);
            }
        }
    }

    Method method2 = Test.class.getDeclaredMethod("Test2",null);
    Type genericReturnType = method2.getGenericReturnType();
        System.out.println("||"+genericReturnType);
        if(genericReturnType instanceof ParameterizedType){
            Type[] actural = ((ParameterizedType)genericReturnType).getActualTypeArguments();
            for (Type type1 : actural) {
                System.out.println(type1);
            }

    }
    /////////////////////////////////////////////////////////////////////////////////////////////////////////
       //通过反射获取泛型
       public void Test1(Map<String,Person> map, List<String> list){
           System.out.println("Test1");
      }
       public Map<String,Person> Test2(){
           System.out.println("Test1");
           return null;
      }
  3. 反射操作注解

    Class c1 = Class.forName("Person");
    Annotation[] annotations =  c1.getAnnotations();//获取完整注解名字
     for (Annotation annotation : annotations) {
         System.out.println(annotation);
     }
     //获取指定注解中的值
     Tablequ tablequ = (Tablequ) c1.getAnnotation(Tablequ.class);
     System.out.println(tablequ.value());
    
    Field field =  c1.getDeclaredField("name");
     Fieldqu fieldqu = field.getAnnotation(Fieldqu.class);
     System.out.println(fieldqu.columnName());
     System.out.println(fieldqu.length());
     System.out.println(fieldqu.type());
    
    
    //定义一个实体类
    @Tablequ("db_person")
    class Person{
        @Fieldqu(columnName = "db_name",type = "varchar",length = 200)
      public String name;
    }
    
    //类名的注释
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Tablequ{
        String value();
    }
    //类名的注释
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Fieldqu{
        String columnName();
        String type();
        int length();
    }
posted @ 2021-03-25 16:08  HOTCOLD  阅读(143)  评论(0)    收藏  举报