欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

反射和注解

时间:2023-08-09
反射和注解! 注解:Annotation 注解 Annotation 作用:

不是程序本身,可以对程序作出解释;

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

常用的内置注解:

@Override 零一在java.lang.Override ; 重写

@Deprecated 定义在java.lang.Deprecated 过时

@SuppressWarnings java.lang.SuppressWainings 镇压警告

等等;

元注解

元注解 就是负责去注解其他注解的;Java中一共定义了 4个标准的 meta-annotation类型,元注解被用来提供对其他annotation 类型做说明

@Target:用于描述注解的适用范围(就是 限定被他注解 的 注解可以用在什么地方)

@Retention:表示需要在什么级别保存注解的信息(其实就是表示我们的注解在什么时候还有小),用于描述注解的生命周期(SOURCE(源码时有效)

@documented:说明该注解被包含在javadoc中(表示是否将我们的注解生成在Javadoc中)

@Inherited:说明子类可以继承父类中的注解

反射

java是静态语言,因为反射让Java有了动态性;

动态:可以在运行时 代码通过某些条件改变自身结构;

反射是十分耗费性能的;

第一个思想:开闭原则:尽量通过扩展来实现,不要去修改源码;

框架的灵魂:反射;

想要了解反射 首先要了解他的Class;它的内存;它的结构体系;

反射初体验

package com.yaohua.reflect;import java.io.FileInputStream;import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Properties;//通过 反射 读取配置文件 调用Cat的hi方法public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException, IOException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { //读取配置文件 Properties properties = new Properties(); //加载配置文件 properties.load(new FileInputStream("src\main\resources\re.properties")); String classfullpath = properties.get("classfullpath").toString(); //获得Cat的全限定名称 System.out.println(classfullpath); String method = properties.get("method").toString(); System.out.println(method); Class aClass = Class.forName(classfullpath); //通过 Class对象 实例化对象 Object o = aClass.newInstance(); //获取该对象的全限定路径 看下啥类型的 System.out.println(o.getClass()); //通过Class .getMethod(); 通过方法名获取一个方法对象 Method method1 = aClass.getMethod(method); //传统调用是 对象.方法(); //反射是 方法对象.invoke(对象); method1.invoke(o); }}

反射机制

Java Reflection

1.反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息(成员变量,构造器,成员方法等;),并能操作任意对象的内部属性及方法,反射在设计模式和框架的底层都会用到;

Class class =Class.forName(“java.lang.String”);

Class class =对象名.getClass();

Class class =数据类型.class;

2.加载完类后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构,这个Class对象可以得到类的完整结构,这个Class对象就像是一面镜子, 所以新城故乡的称之为 反射;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P4U6sdhq-1644027390150)(反射.assets/image-20220117161003829.png)]

那些数据类型可以有Class 对象?

class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类;interface 接口[] :数组enum :枚举annotation:注解@interfacecprimitive type :基本数据类型void 类的加载

.java文件-----(前端编译)---->.class文件;这里为什么说前端编译因为 我们的JVM执行引擎还会 JIT 和 解释器执行;

然后就要走类加载子系统了;

加载Loading:

通过一个类的全限定名称 获取这个类的 二进制字节流.class文件将这个字节流 .clss字节码文件的静态储存结构转化为方法区的运行时数据结构在内存中生成一个代表这个类的 java.lang.Class对象,该对象作为方法区的各种数据访问入口 链接linking

验证(Verify):目的就是确保class字节流中包含信息符合JVM虚拟机要求,保证被加载类的正确性,没有安全问题准备(prepare):为类的变量分配内存并且设置该变量的默认初始值,即为零值;这里不包含 final修饰的static,这些内存都将在方法区内分配;解析(Resolve):将常量池内的引用转换为 直接引用的过程; 初始化(initialization)

初始化阶段就是执行类构造器方法clinit()过程jvm去做。是java编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来,类构造器是构造的类信息的,不是构造该类对象的构造器;若该类有父类,JVM会保证子类的clinit()执行前,父类的clinit()已经执行完毕;虚拟机必须保证一个类的clinit()方法在多线程下同步加锁;

加载完成后 会在堆内生成一个该类的Class对象,(一个类只生成一个Class对象);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5oCfPOaS-1644027390151)(反射.assets/image-20220117164649632.png)]

什么时候会发生一个类的初始化

看清了 是初始化 不是加载;

类的主动引用(一定会发生类的初始化);

当jvm虚拟机启动时,先初始化main方法所在的类new一个对象的时候调用类的静态成员 和静态方法java.lang.reflect 的api对类进行反射当初始化一个类 如果父类没有被初始化,则先初始化它的父类

类的被动引用(不会发生类初始化)

当访问一个静态域时,只有真正声明这个域的类才会被初始化 例如:当通过子类引用父类的静态变量,子类不会初始化;通过数组定义类 引用时,不会触发类的加载初始化引用常量不会引发此类的初始化,(常量在linking阶段就存入调用类的常量池了) 类加载器

类加载器

引导类加载器 :用C++编写的,在java中无法实例化,用来加载 java的核心类库的;

扩展类加载器:负责加载jre/lib/ext 目录下的jar包

应用/系统类加载器:我们写的类一般都是用这个加载器

自定义类加载器

package com.qfyaohua.chapter01;public class ClassLoaderDemo { public static void main(String[] args) { //获取一下系统/应用类加载器APPClassLoader ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2 //通过系统类加载器APPClassLoader 获取他的上层加载器 ClassLoader extClassLoader = systemClassLoader.getParent(); System.out.println(extClassLoader); //sun.misc.Launcher$ExtClassLoader@7f31245a ClassLoader bootStrapClassLoader = extClassLoader.getParent(); System.out.println(bootStrapClassLoader); //null ClassLoader classLoader = ClassLoaderDemo.class.getClassLoader(); System.out.println(classLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2 //获取一下String类的类加载器 null 说明java的核心类库使用的是引导类加载器 ClassLoader classLoader1 = String.class.getClassLoader(); System.out.println(classLoader1); //null }}

动态创建对象

通过Class 调用 newInstance();

需要满足两点要求:1.该类必须有无参构造器;2.该类的无参构造器的访问权限要足够

思考:难道没有无参构造器,就不能通过反射去创建对象了吗?

我们还可以 通过Class对象getDeclaredConstructor(Class …parameterTypes)取得本类的指定形参类型的构造器

向构造器形参中传递一个对象数组进去,里面包含了构造器所需要的各个参数

通过Constructor实例化对象;

public class ConstructorDemo { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Class<?> aClass = Class.forName("com.yaohua.reflect.User"); Constructor<?> constructor = aClass.getDeclaredConstructor(String.class, int.class); Object hello = constructor.newInstance("耀华", 25); System.out.println(hello); }}class User{ private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "User{" + "name='" + name + ''' + ", age=" + age + '}'; }}

性能检测

setAccessible作用是启动和禁用访问安全检查开关;

参数值设置为true则指示反射的对象在使用时java语言访问检查;

​ 提高反射效率,如果代码中必须用到反射,而该语句代码频繁被调用,请设置为true

​ 是的原本无法访问的私有方法也可以被访问

参数值false则 指示反射的对象应该实施Java语言访问检查;

做一个普通调用 ,反射调用 ,反射调用关闭检测 的性能测试;可以发现反射是十分耗费性能的

//10亿次的方法调用循环; 普通 3ms , 反射 2415ms 关闭检测反射1012mspackage com.yaohua.reflect;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;//分析性能问题public class Test { //普通方式调用 public static void test01(){ User user =new User("耀华",18); long l = System.currentTimeMillis(); for (int i=0;i<1000000000;i++){ user.getName(); } long l1 = System.currentTimeMillis(); System.out.println(l1-l); } //反射方式调用 public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { long l = System.currentTimeMillis(); User user = new User("华仔",18); Class<? extends User> aClass = user.getClass(); Method getName = aClass.getDeclaredMethod("getName",null); for (int i=0;i<1000000000;i++){ getName.invoke(user,null); } long l1 = System.currentTimeMillis(); System.out.println(l1-l); } //反射 关闭检测调用 public static void text03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { long l = System.currentTimeMillis(); User user = new User("阿华",18); Class<? extends User> aClass = user.getClass(); Method getName = aClass.getDeclaredMethod("getName", null); getName.setAccessible(true); for (int i=0;i<1000000000;i++){ getName.invoke(user,null); } long l1 = System.currentTimeMillis(); System.out.println(l1-l); } public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { test01(); test02(); text03(); }}class User{ private String name; private int age; public String getName() { return name; } public int getAge() { return age; } public User(String name, int age) { this.name = name; this.age = age; }}

test02(); text03();}

}

class User{
private String name;
private int age;

public String getName() { return name;}public int getAge() { return age;}public User(String name, int age) { this.name = name; this.age = age;}

}

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。