java的反射机制速度很慢_java反射机制Reflection浅析

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

以上的总结就是什么是反射

反射就是把java类中的各种成分映射成一个个的Java对象

例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)

如图是类的正常加载过程:反射的原理在与class对象。

熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。

目录

Reflection 反射

反射的定义

反射机制:

在程序运行时可以加载,探知,使用编译期间完全未知的类

程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个加载的类,都能够知道这个类的所有属性和方法;同时任意一个对象也都能够调用它的任意一个方法和属性。同时一个类只有一个反射对象,比如多次调用Class.forName得到的也是相同对象

形象的说:

使用以下反射代码来获取一个类的对象

Class c = Class.forName("com.company.project.ClassName");

当加载完成后,堆内存中就产生了一个ClassName类型的对象,通过这个对象我们就可以看到类的结构,这个就时反射

反射的作用

动态加载类、动态获取类的信息(属性、方法、构造器)

动态构造对象

动态调用类和对象的任意方法、构造器

动态调用和处理属性

获取泛型信息

处理注解

Class类

public final class Class

Class类的类表示正在运行的Java应用程序中的类和接口。 枚举是一种类,一个注解是一种接口。 每个数组也属于一个反映为类对象的类,该对象由具有相同元素类型和维数的所有数组共享。 原始Java类型( boolean , byte , char , short , int , long , float和double ),和关键字void也表示为类对象。Class没有公共构造函数。 相反, Class对象由Java虚拟机自动构建,因为加载了类,并且通过调用类加载器中的defineClass方法。

简单的说就是:

Class类十分特殊,用来表示java中类型 (class/interface/enum/annotation/primitive type/void)本身。

Class类的对象包含了某个被加载类的结构。一个被加载的类对应一个 Class对象

JVM来创建Class对象,当加载器(class loader)的defineClass()被 JVM调用,JVM 便自动产生一个Class 对象

Class类是Reflection反射的基础,任何要动态加载,运行的类,都必须先获得对于的Class对象

Class类的对象获取

.getClass()方法

Class.forName()方法–使用最多

.class语法

package JavaCore.Reflection;

/*******************************************************************************

* @Description: 获取Class对象

* @Aha-eureka: Class类是Reflection反射的基础,任何要动态加载,运行的类,都必须先获得对于的Class对象

******************************************************************************/

public class Reflection_GetClass {

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

String path = "JavaCore.Reflection.User_Demo";

//获取Class的几种方式

{

//一个类只有一个Class对象

Class clazz1 = Class.forName(path);

Class clazz11=Class.forName(path);

System.out.println(clazz1.hashCode());//相同hashcode

System.out.println(clazz11.hashCode());//相同hashcode

}

{

User_Demo user_demo = new User_Demo();

Class clazz2 = user_demo.getClass();

Class clazz3 = User_Demo.class;

System.out.println(clazz2 == clazz3);//true

}

}

}

获取基本数据类型的Class对象

Class类可以直接获取基本数据类型的Class对象,但是在数组中,多维的数组就是不同的class对象,不同类型的数组也是不同的class对象

int[] arr0 = new int[5];

int[] arr01 = new int[15];

long[] arr02 = new long[15];

int[][] arr1 = new int[5][5];

System.out.println(arr0.getClass() + " " + arr0.getClass().hashCode());//class [I 920011586

System.out.println(arr01.getClass() + "   " + arr01.getClass().hashCode());//class [I   920011586

System.out.println(arr02.getClass() + "   " + arr02.getClass().hashCode());//class [J   2017354584

System.out.println(arr1.getClass() + " " + arr1.getClass().hashCode());//class [[I 2017354584

Class API

方法含义备注public String getName()返回由类对象表示的实体的名称(类,接口,数组类,原始类型或void),作为String返回由类对象表示的实体的名称(类,接口,数组类,原始类型或void),作为String

public Field getField(String name)获取指定属性名的属性注意只能获得public属性

public Field[] getFields()获取所有的公共方法的属性数组

public Field getDeclaredField(String name)返回指定的名字的属性包括私有属性

public Field[] getDeclaredFields()返回所有的属性数组包括私有的

同理…Method/Constructor

同理…DeclaredMethods/Constructors

public Mehod getDeclaredMethod(String name,Class>…parameterTypes返回指定参数类型的方法,Class>…parameterTypes可变参数参入的是对于类型的Class类针对方法的多态性(重载)进行针对的获取,即对于方法有传参则必须传入对于的Class对象

public Constructor获取指定传参的构造器

package JavaCore.Reflection;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

public class Reflection_Dynamic {

static Class clazz;

static{

String path = "JavaCore.Reflection.User_Demo";

try {

clazz=Class.forName(path);

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

public static void useReflection() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

//这里newInstance实际就是在调用对于类的无参构造器,如果对于的类没有无参构造器则会抛出InstantiationException

User_Demo demo = (User_Demo) clazz.newInstance();

//使用特定的构造器新建对象

Constructor constructor = User_Demo.class.getDeclaredConstructor(String.class, int.class);

User_Demo demo1 = (User_Demo) constructor.newInstance("Swagger", 26);

System.out.println(demo1);

/**

* 使用反射调用普通方法

* 1.先获取到Class对象,并获取一个新的对象A

* 2.然后通过Class对象获得方法对象Method

* 3.使用Method.invoke(Object A,args...)方法调用类的方法

*/

User_Demo A = (User_Demo) clazz.newInstance();

Method method = clazz.getDeclaredMethod("setName", String.class);

method.setAccessible(true);

method.invoke(A, "Swagger1");

System.out.println(A);

/**

* 通过反射操作属性

*

*/

User_Demo fDemo = (User_Demo) clazz.newInstance();

Field f = clazz.getDeclaredField("name");

f.setAccessible(true);//使用这个setAccessible(true)来设置可以访问私有方法和属性

f.set(fDemo, "Ranger");//

System.out.println(fDemo);

}

}

反射操作泛型

Java采用泛型擦除的机制来引入泛型。Java中的泛型仅仅是给编译器javac使用的,确保数据 的安全性和免去强制类型转换的麻烦。但是,一旦编译完成,所有的和泛型有关的类型全部 擦除。

为了通过反射操作这些类型以迎合实际开发的需要,Java就新增了ParameterizedType, GenericArrayType,TypeVariable 和WildcardType几种类型来代表不能被归一到Class 类中的类型但是又和原始类型齐名的类型

反射操作注解

public static void main(String[] args) {

try {

Class clazz = Class.forName("类的相对路径和类名");

//获得类的所有有效注解

Annotation[] annotations=clazz.getAnnotations();

for (Annotation a : annotations) {

System.out.println(a);

}

//获得类的指定的注解SxtTable就是一个注解

SxtTable st = (SxtTable) clazz.getAnnotation(SxtTable.class);

System.out.println(st.value());

//获得类的属性的注解,columnName(),type(),length()就是SxtTable第一的注解方法或者属性,因为注解就是一种特殊的接口,他的属性值就是调用其方法

Field f = clazz.getDeclaredField("studentName");

SxtField sxtField = f.getAnnotation(SxtField.class);

System.out.println(sxtField.columnName()+"--"+sxtField.type()+"--"+sxtField.length());

//根据获得的表名、字段的信息,拼出DDL语句,然后,使用JDBC执行这个SQL,在数据库中生成相关的表

} catch (Exception e) {

e.printStackTrace();

}

}

反射的性能问题

反射访问相对正常的访问大概要慢30倍

setAccessible

setAccessible设为true:取消反射时的对象安全检查,false则进行安全检查;

当禁止安全检查时就能:

1.访问私有属性

2.同时也能提高反射的运行速度

如果setAccessible(true)禁用安全检查则能将反射访问效率提升4倍,所以当频繁的调用反射时可以禁用安全检查来提升效率

853f24a3de4e9f76e21c90aae0bc3ba6.png

作者:

喜欢围棋和编程。查看的所有文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值