5、注解和反射

annotation

  • annotationvscomment。

内置注解

  • 内置注解:@override,@Depreated弃用,@SuppressWarnings
public class Test01 {
    @Override
    public String toString() {
        return super.toString();
    }
    @Deprecated //Java不推荐使用,但是可以使用
    public static void test(){
        System.out.println("Deprecated");
    }

    @SuppressWarnings("all")
    public void test2(){
        List list = new ArrayList();
    }

    public static void main(String[] args) {
        test();		//输出:Deprecated
    }
}

meta-annotation

  • 用在注解的注解
    • Target
    • Retention:生命周期source->class->runtime
    • Documented:用于生成javadoc解释文档
    • Inherited
@MyAnnotation
public class Test02 {
    public void test(){
    }
}

//用于什么类型,METHOD,TYPE
@Target({ElementType.METHOD,ElementType.TYPE})//tip:可以大写METHOD,idea会提示

//什么级别有效
@Retention(value = RetentionPolicy.RUNTIME)//tip:可以大写RUNTIME,idea会提示

//是否让注解生成在Javadoc中
@Documented

//子类可以继承父类注解
@Inherited

//自己定义一个注解
@interface MyAnnotation{	}

Myannotation

  • 实验
public class Test01 {
    @Myannotation1(name = "adair",age = 18)
    public void test(){}
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Myannotation1{
    String name() default "";		//没有default必须给出参数,有的话也可以重新赋值
    int id() default 1;
    int age();
    String[] school() default {"小学","大学"};
}

@interface Myannotation2{
    String value();		//只有一个参数必须用value
}

reflection

概述

  • 反射就是得到
  • 静态语言:不改变自身结构。Java、C、C++。Java利用反射机制拥有动态性
  • 动态语言:在运行时可以根据某些调节改变自身结构,新的函数、对象等可以被引进。例如JavaScript、PHP、Python、Object-C、C#
  • 一个类加载完后,生成一个class对象(一个类只生成一个对象),可以通过class对象看到类的结构。故称为反射

得到类方式

  • 三种方式
public class Test01{
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("com.test.User");

        Class c2 = User.class;

        User user = new User();
        Class c3 = user.getClass();

        System.out.println(c1.hashCode()==c2.hashCode());//true
        System.out.println(c1.hashCode()==c3.hashCode());//true
    }
}

class User{		}

各种Object.class

public class Test04 {
    public static void main(String[] args) {
        Class c1 = Object.class;
        System.out.println(c1);
        
        //int,void,int[][],String[],也可int.class
        //Override,Comparable,Class
        
        int[] a = new int[10];
        int[] b = new int[100];//只要元素类型和维度一样,即同一个class
        System.out.println(a.getClass().hashCode()==b.getClass().hashCode());//true
    }
}

类加载内存

  • 方法区、栈、堆
  • 加载的过程:加载 -> 链接 -> 初始化
    • 类的加载:将class文件加载到内存,并创立java.lang.class对象
    • 类的链接:将类的二进制合并到JRE
    • 类的初始化:JVM负责初始化。static
  • 输出的先后顺序
public class Test05 {
    public static void main(String[] args) {
        A a = new A();
        /**输出:
         * 静态代码块
         * 无参构造器
         */
        System.out.println(a.m);//输出:2。这个是有先后顺寻的
    }
}
class A{
    static {
        System.out.println("静态代码块");
        m = 1;
    }
    static int m = 2;
    public A() {
        System.out.println("无参构造器");
    }
}
  • 方法区():有class Test05、class A。加载就是方法区到堆(内存)
  • 堆:java.lang.class对象代表Test05类、java.lang.class对象代表 A类。new A()会指向java.lang.class对象,得到方法区的数据
  • 栈:方法的调用

类的初始化

  • 类的主动引用——类的初始化
    • new一个对象
    • 利用反射得到类
  • 类的被动引用——没有类的初始化
    • 子类用父类的属性,父类加载,子类未加载
    • 构造数组
    • 使用final属性
public class Test06 {
    static {
        System.out.println("main被加载");
    }
    public static void main(String[] args) throws ClassNotFoundException {
//        //主动引用
//        Son son = new Son();
//
//        //反射也会主动引用
//        Class.forName("com.adair.reflection.Son");

//        //不会主动引用
//        System.out.println(Son.b);//父类会加载,子类不会加载
//
//        Son[] sons = new Son[5];//不会加载父类和子类,仅有main加载
        System.out.println(Son.M);//由于M为final,父类和子类都不会加载

    }
}
class Father{
    static  int b = 2;
    static {
        System.out.println("父类被加载");
    }
}
class Son extends Father{
    static {
        System.out.println("子类被加载");
        m = 100;
    }
    static int m = 300;
    static final int M = 1;

}

类的加载器*

  • 引导类加载器(根加载器bootstrap)→ 扩展类加载器ext →系统类加载器app → 自定义类加载器app
  • ClassLoader.getSystemClassLoader()c1.getClassLoader()
public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //系统
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);//AppClassLoader

        //扩展
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);//ExtClassLoader

        //根
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);//null

        //自己的类
        ClassLoader classLoader = Class.forName("com.test.Test01").getClassLoader();
        System.out.println(classLoader);//AppClassLoader

        //jdk中的Objection
        ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader1);//null
        
        System.out.println(System.getProperty("java.class.path"));//jre中jar包的路径
    }
}
  • 双亲委派机制

获取类的组成

  • 获得类的:名字,构造器,属性,方法
public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = User.class;

        //得到类的名字
        System.out.println(c1.getName());//com.test.User
        System.out.println(c1.getSimpleName());//User

        //得到构造器
        Constructor[] constructors = c1.getConstructors();
        System.out.println(Arrays.toString(constructors));
        
        //得到属性
        Field value1 = c1.getField("value1");//指定属性。tip;declared区别
        System.out.println(value1);//public java.lang.String com.test.User.value1
        Field[] declaredFields = c1.getDeclaredFields();
        System.out.println(Arrays.toString(declaredFields));//得到类的所有属性

        int a =4;
        //得到方法
        Method test = c1.getMethod("test",int.class);
        System.out.println(test);//public void com.test.User.test()
        Method[] methods = c1.getMethods();
        System.out.println(Arrays.toString(methods));//不仅仅是test,还有许多自带的方法
    }
}
class User{
    public String value1;
    private String value2;
    public User(){
        this.value1 = "adair";
    }
    public void test(int a){    }
}

创建并操作对象

public class Test01 {
    public static void main(String[] args) throws Exception{
        Class c1 = User.class;

        //通过c1类创建一个对象
        User user1 = (User) c1.newInstance();//必须要有空的构造器

        //获取一个构造器,通过构造器创建对象
        Constructor constructor = c1.getConstructor(String.class);
        User user2 = (User)constructor.newInstance("adair");

        //获取方法,再给对象user1使用
        Method test = c1.getMethod("test", int.class);
        test.invoke(user1,1);

        //获取属性,再给对象user1使用
        Field value1 = c1.getDeclaredField("value1");
//        value1.setAccessible(true);  //安全检测,设置为不检测
        value1.set(user1,"zhangsan");
    }
}
class User{
    public String value1;
    public int value2;
    
    public User(){      }
    public User(String name){
        this.value1 = name;
    }
    
    public void test(int a){
        value2 = a;
    }
}
#总结
c1.newInstance():
constructor.newInstance()
test.invoke()
value1.set()
  • 属性,方法,构造器都有setaccessible()

分析性能

  • 分析三种性能
    • 普通:利用对象的方法
    • 反射:通过获得一个方法,进行操作对象
    • 反射:(关闭检查)
public class Test01 {
    public static void main(String[] args) throws Exception{//由于test1,2,3抛出异常
        test1();//7
        test2();//2845
        test3();//1622
    }

    //普通方法调用
    public static void test1(){
        User user = new User();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10_0000_0000; i++) {
            user.test(10);
        }
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }

    //反射方法调用
    public static void test2() throws Exception{
        Class c1 = User.class;
        User user =(User) c1.newInstance();
        Method test = c1.getMethod("test", int.class);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10_0000_0000; i++) {
            test.invoke(user,10);
        }
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }

    //反射方法调用,安全关闭
    public static void test3() throws Exception{
        Class c1 = User.class;
        User user =(User) c1.newInstance();
        Method test = c1.getMethod("test", int.class);
        test.setAccessible(true);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10_0000_0000; i++) {
            test.invoke(user,10);
        }
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }
}
class User{
    public void test(int a){    }
}

获取泛型信息

  • 通过反射获得方法,再通过方法获得test1.getGenericParameterTypes()的泛型
public class Test01 {
    public static void main(String[] args) throws Exception {
        Class c1 = Test01.class;
        Method test1 = c1.getMethod("test1", Map.class, List.class);

        //获得方法中泛型
        Type[] genericParameterTypes = test1.getGenericParameterTypes();
        System.out.println(Arrays.toString(genericParameterTypes));
        //输出:[java.util.Map<java.lang.String, com.test.User>, java.util.List<com.test.User>]

        //把泛型展开Map是一个数组,而List是一个数组
        for (Type genericParameterType : genericParameterTypes) {
            if(genericParameterType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                System.out.println(Arrays.toString(actualTypeArguments));
                //输出:[class java.lang.String, class com.test.User]
                //[class com.test.User]
            }
        }
    }
    
    public void test1(Map<String,User> map, List<User> list){   }
    public Map<String,User> test2(){ return null;  }
}

class User{
    public void test(int a){    }
}

获取注解的内容

  • 定义注解,利用注解修饰类。
public class Test01 {
    public static void main(String[] args) throws Exception{
        Class c1 = User.class;
        Annotation[] annotations = c1.getAnnotations();
        System.out.println(Arrays.toString(annotations));

        //获取User类Myannotation注解中的value值
        System.out.println(((Myannotation1) c1.getAnnotation(Myannotation1.class)).value());

        Class c2 = Student.class;
        Field id = c2.getField("id");
        Myannotation2 annotation = id.getAnnotation(Myannotation2.class);
        System.out.println(annotation.length());
    }
}
//一个类用一个注解
@Myannotation1(value = "user_db")
class User{     }

class Student{
    @Myannotation2(colunm = "id",type = "int[]",length = 10)
    public int id;
}

//定义两个注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Myannotation1{
    String value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Myannotation2{
    String colunm();
    String type();
    int length();
}
  • 拓展:ORM,object relationship mapping对象关系映射。对应关系: 类和表、属性和字段、对象和记录
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值