Java反射的基本理解

1 篇文章 0 订阅
1 篇文章 0 订阅

在了解Java的反射之前,先理解一下Java的动态性

一、动态语言:

程序运行的时候,可以改变程序的结构或变量的类型。

1、典型的动态语言有:Python,ruby,JavaScript

2、C,C++,Java都不是动态语言,但是Java有一点不同,Java虽然不是动态语言,但是Java具有一定的动态特性,我们可以利用Java的反射机制,字节码操作获得类似动态语言的特性。

二、反射机制

1、反射机制指的是可以于运行时加载,探知,使用编译期间完全未知的类

2、程序在运行状态中,可以动态加载一个只有名称的类,对于任何一个已加载的类,都能知道这个类的所有属性和方法,对于任意一个对象都能够调用它的任何一个属性和方法

3、加载完类之后,在堆内存中,就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结果信息。可以通过这个对象看到类的结果。

4、一个类被加载后,JVM会创建一个对应类的Class对象,类的整个结构信息会放在对应的Class对象中。

简单实例:

package com.silence.bean;


/**
 * 创建一个Javabean
 * @author zhuxiang
 *
 */
public class User {


private int id;
private int age;
private String uname;

//一个Javabean必须要有无参构造器
public User(){

}

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public User(int id, int age, String uname) {
super();
this.id = id;
this.age = age;
this.uname = uname;
}


}


通过另一个类来测试

package com.silence.test;


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;


import com.silence.bean.User;


/**
 * 通过反射动态调用构造器
 * @author Silence
 *
 */
@SuppressWarnings("all")
public class Test02 {


public static void main(String[] args) {


String path = "com.silence.bean.User";
try {
Class<User> clz = (Class<User>) Class.forName(path);

//通过反射API调用构造器,构造对象
User user = clz.newInstance();//调用User的无参构造器实例化一个User对象
System.out.println(user);

//通过指定构造器构造对象
Constructor<User> constructor = clz.getDeclaredConstructor(int.class,int.class,String.class);
User user2 = constructor.newInstance(1210322,22,"studentname");
System.out.println(user2.getUname());


//通过反射API动态调用普通方法
User user3 = clz.newInstance();

Method method = clz.getDeclaredMethod("setUname", String.class);

method.invoke(user3, "长江");//这两行相当于user3.setUname("长江");

//此处应注意一个问题,那就是如果调用某个类的main方法的时候,由于main方法是静态的以及参数是String数组(String[] args)

//调用时invoke()函数的参数应该这样写:invoke(null,(object)new String[]{})。

//调用静态方法时第一个参数为null即可,第二个参数必须强制转换为object类型


System.out.println(user3.getUname());


//通过反射API动态调用属性
User user4 = clz.newInstance();
Field field = clz.getDeclaredField("uname");
field.setAccessible(true);  //该句代码表示不检查私有的变量,让反射机制可以访问私有变量,
//没有该句代码会出现异常,提示不能操作private修饰的变量
field.set(user4, "大海");//通过反射写入属性
System.out.println(user4.getUname());
System.out.println(field.get(user4));//通过反射读取属性


} catch (Exception e) {
e.printStackTrace();
}
}


}


三、反射机制的常见的作用

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

2、动态构造实例

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

4、动态调用和处理类的属性

5、获取泛型信息

6、获取处理注解


四、反射机制的性能问题

1、setAccessible

1)启用和禁用访问安全检查的开关,值为true则指示反射的对象在使用时应取消Java语言访问检查;值为false时,则指示反射的对象应该实施Java语言的访问检查。并不是值为true时就能访问,值为false时就不能访问。

2)禁止安全访问检查,可以提高反射的运行速度。一般来说,不用反射的(普通调用)比反射(setAccessible=false)效率高30倍左右,比反射(setAccessible=true)效率高7倍左右。当然只是一般来说。。。

2、反射操作泛型

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

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

ParameterizedType:表示一种参数化的类型,比如Collection<String>

GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

TypeVariable:是各种类型变量的公共接口

WildcardType:代表一种通配符类型 比如  ? , ? extends Number, ? super Integer


下面以第一个parameterizedType为例,获取泛型参数和泛型类型返回值的方法:

package com.silence.test;


import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;


import com.silence.bean.User;


/**
 * 通过反射来操作泛型
 * @author zhuxiang
 *
 */
public class RefGeneric {


public void test01(Map<String, User> map, List<User> list){
System.out.println("RefGeneric.test01()");
}

public Map<Integer, User> test02(){
System.out.println("RefGeneric");
return null;
}

public static void main(String[] args) {


try {
//获得指定方法参数泛型信息
Method method = RefGeneric.class.getMethod("test01", Map.class,List.class);
Type[] types = method.getGenericParameterTypes();
for (Type paramType : types) {
System.out.println("#" + paramType);
if (paramType instanceof ParameterizedType) {
Type[] genericTypes = ((ParameterizedType)paramType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("泛型类型:" + genericType);
}
}
}

//获得指定方法返回值泛型信息
Method method2 = RefGeneric.class.getMethod("test02", null);
Type returnType = method2.getGenericReturnType();
if (returnType instanceof ParameterizedType) {
Type[] genericTypes = ((ParameterizedType)returnType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("返回值,泛型类型:" + genericType);
}
}


} catch (Exception e) {
}
}


}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值