注解与反射_1 - 小记

1. 自定义注解  @interface

@interface MyAnno {
    //注解类型:   参数类型  参数名()  defult  默认值;    
    String name() default "";
    int age() default 0;
    int id() default -1;
    String[] schools();  //无默认值,那外部写这个注解时就必须带参数!

}
//测试类
public class Test {
    @MyAnno(name = "jiaxin")
    public void test () {
        ....
    }
}

2.元注解

//表示我们的注解可以用在哪些地方
@Target(value = {ElementType.METHOD , ElementType.ANNOTATION_TYPE})

//表示我们的注解在什么地方还有效   runtime > class > sources
@Retention(value = RetentionPolicy.RUNTIME)

//表示是否将我们的注解生成在java doc中
@Documented

//子类可以继承父类的注解
@Inherited
@interface MyAnno {

}

3.注解种类:

内置注解+元注解+自定义注解

反射  Reflection

1.反射机制是Java被视为动态语言的关键,在框架Spring、Mybatis代码中有所体现。

2.如何创建对象? new    或者    clone()克隆   或者   反射!!

3.反射与注解相结合。 反射可以获取类的内部信息,动态化(运行时刻可以查看、改变其结构的)。

4.比较:

正常方式:引入包类名-new-获取实例化对象

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

5.反射机制提供的功能:

判断任一对象所属的类
构造任一类的对象
判断任一类所具有的属性和方法
获取泛型信息
处理注解
调用任一个对象的成员变量及方法
生成动态代理
....

6.优缺点:

优:实现动态创建对象和编译+灵活性

缺:影响性能

package com.tencent.reflection;

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

public class Test8 {

    public static void t1() {
        User user = new User();
        long startTime = System.currentTimeMillis();
        for(int i = 0; i < 1000000000 ; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime + "ms");  //5-6ms
    }

    public static void t2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName" , null);
        getName.setAccessible(false);
        long startTime = System.currentTimeMillis();
        for(int i = 0; i < 1000000000 ; i++) {
            getName.invoke(user , null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime + "ms");  //5-6ms
    }

    public static void t3() 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 < 1000000000 ; i++) {
            getName.invoke(user , null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime + "ms");  //5-6ms
    }

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        System.out.print("普通调用getName():");
        Test8.t1();

        System.out.print("开启安全检测,调用getName():");
        Test8.t2();

        System.out.print("关闭安全检测,调用getName():");
        Test8.t3();

        /*
        普通调用getName():6ms
        开启安全检测,调用getName():1917ms
        关闭安全检测,调用getName():1295ms

        ---说明反射消耗性能,费时.
        * */
    }
}

7.获取Class类的几种方法

package com.tencent.reflection;

public class Test2 {

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

        //1.通过对象 调用getClass()获取
        User user = new User("jx" , 21);
        Class c1 = user.getClass();
        System.out.println(c1.hashCode());

        //2.通过类的class属性获取
        Class c2 = User.class;
        System.out.println(c2.hashCode());

        //3.通过类路径获取 forName()
        Class c3 = Class.forName("com.tencent.reflection.User");
        System.out.println(c3.hashCode());

        //4.内置基本数据类型 包装类
        Class c4 = Integer.TYPE;
        System.out.println(c4);   //int

        //5.获得对象所属类的父类类型
        System.out.println(c1.getSuperclass());

    }
}

8.哪些类型具有Class对象(or 属性)?

package com.tencent.reflection;

import sun.reflect.generics.scope.ClassScope;

import java.lang.annotation.ElementType;

public class Test3 {

    public static void main(String[] args) {

        Class c1 = Object.class;    //类

        Class c2 = Comparable.class; //接口

        Class c3 = String[].class;   //数组

        Class c4 = Override.class;   //注解

        Class c5 = ElementType.class; //枚举

        Class c6 = Integer.class; //基本数据类型

        Class c7 = void.class;  //void

        Class c8 = 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);

        //元素类型相同,则获取对应的Class类型都相同
        int[] a = new int[10];   //1163157884
        int[] b = new int[100];  //1163157884
        System.out.println(a.getClass().hashCode());
        System.out.println(b.getClass().hashCode());

    }
}

9.Java内存分析

栈:存放基本数据类型+引用对象的变量地址

堆:存放对象+数组,可被所有线程共享,注:存放Class对象!

方法区:被所有线程共享,存放 static静态变量

10.类加载过程

分三步

类加载Load + 类链接Link + 类初始化Initialize

a.加载: class文件字节码,加载到内存中,将静态数据转换成方法区的运行时数据结构,在堆中生成Class对象

b.链接:

验证:检查类信息符合JVM规范,有无安全问题;

准备:为类变量,即:静态变量,分配内存,设置默认初始值;

解析:虚拟机常量池,符号引用 替换为 直接引用地址 的过程。

c.初始化:

执行类构造器clinit()的过程;

初始化一个类,要检查其父类,先初始化父类;

虚拟区要确保一个类的构造器clinit()在多线程环境下,加锁及同步的进行。

11.什么情况发生类的初始化?

主动引用会发生;被动引用不会。

主动引用:略;

引言:主动引用中,当前程序执行的Main方法一定会初始化。

被动引用:
a. 访问静态域的话,是真正声明这个域的类才会初始化!例如:
通过子类引用父类的静态变量,则不会引起子类的初始化!只会引起父类的初始化。

b. 通过数组定义类访问时,不会加载当前定义类的初始化!

c. 引用常量。  不会引起当前定义类的初始化!
因为常量在链接的第三步解析步骤下,就会调入常量池中了。

 

你可能感兴趣的:(java)