我是靠谱客的博主 闪闪小蚂蚁,最近开发中收集的这篇文章主要介绍java动态性之反射机制(Reflection),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

1、什么是动态语言?

2、反射机制(Reflection)?

3、Class类介绍?

4、如何获得Class对象?

5、使用Class对象来获取类的结构信息

6、通过反射动态操作:构造器、方法及属性

7、反射机制性能问题


​​​​​​​

1、什么是动态语言?

        程序运行时,可以改变程序运行结构或变量类型。典型的语言有Python、ruby、javascript等。另外,C,C++,Java并不是动态语言,但是Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。Java的动态性让编程的时候更加灵活!!!

2、反射机制(Reflection)?

        指的是可以用于运行时加载、探知、使用编译期间完全未知的类。

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

Class clazz= Class.forName("com.bjsxt.test.User");//动态加载User类,实时加载到程序
(class小写表示关键字,Class大写表示是一个类)

        加载完类之后,在堆内存中,就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。

3、Class类介绍?

        Class类是反射机制(Reflection)的根源。

        java.lang.Class类十分特殊,用来表示java中类型。

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

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

4、如何获得Class对象?

        存在三种方法:

        (1)运用getClass()

        (2)运用Class.forName() 【常用】

        (3)运用.class语法

//定义一个实体类User
public class User {
private int id;
private int age;
private String uname;
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;
}
//无参构造器
public User(){
}
}

        通过测试程序中注释的部分可以较好理解一下Class对象。 

        (1)被加载的每个类(所有类型),只会被加载一次,都会有这样一个对象,该对象唯一。         
        (2)Class对象可以比喻为建造汽车的图纸,图纸只有一张,但是可以创建许多汽车对象。
        (3)对象是表示或封装一些数据。一个类被JVM有组织的加载后,JVM会创建一个对应该类的Class对象,类的整个结构信息会放到对应的Class对象中。
        (4)这个Class对象就像一面镜子一样,通过这面镜子我们可以看到对应类的全部信息,故形象称之为:反射。

//测试各种类型对应的java.lang.Class对象的获取方式
public static void main(String[] args) {
String path = "com.bjsxt.test.bean.User";//User.java类所在的路径
try {
Class clazz = Class.forName(path);//实时动态加载User类
//被加载的每个类(所有类型),只会被加载一次,都会有这样一个对象,该对象唯一
//(Class对象可以比喻为建造汽车的图纸,图纸只有一张,但是可以创建许多汽车对象)
//对象是表示或封装一些数据。一个类被JVM有组织的加载后,JVM会创建一个对应该类的Class对象,类的整个结构信息会放到对应的Class对象中
//这个Class对象就像一面镜子一样,通过这面镜子我们可以看到对应类的全部信息
System.out.println(clazz.hashCode());//输出:class com.bjsxt.test.bean.User
Class clazz2 = Class.forName(path);//一个类只对应了一个Class对象
System.out.println(clazz2.hashCode());
Class strClazz = String.class;
Class strClazz2 = path.getClass();
System.out.println(strClazz == strClazz2);//true
Class intClazz = int.class;
int[] arr01 = new int[10];
int[] arr02 = new int[30];
int[][] arr03 = new int[30][30];
double[] arr04 = new double[10];
System.out.println(arr01.getClass().hashCode());//结果相同表示对象唯一
System.out.println(arr02.getClass().hashCode());
System.out.println(arr03.getClass().hashCode());
System.out.println(arr04.getClass().hashCode());
System.out.println(Class.class);
System.out.println(void.class);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

5、使用Class对象来获取类的结构信息

        应用反射的API,获取类的结构信息(类的名字,属性,方法,构造器等)。反射机制中用到的类:Class、Field、Method、Constructor。

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 应用反射的API,获取类的信息(类的名字,属性,方法,构造器等)
* @author WQ
*
*/
public class Demo02 {
public static void main(String[] args) {
//User.java类的路径
String path = "com.bjsxt.test.bean.User";
try {
//动态加载User类
Class clazz = Class.forName(path);
//获得类名
//获得包名+类名:com.bjsxt.test.bean.User
System.out.println(clazz.getName());
//获得类名:User
System.out.println(clazz.getSimpleName());
//获得属性信息
Field[] fields = clazz.getFields();//只能获取到public的属性field
System.out.println(fields.length);
Field[] fields2 = clazz.getDeclaredFields();//获得所有属性field
System.out.println(fields2.length);
System.out.println(Arrays.toString(fields2));
for(Field temp:fields2){
System.out.println("属性:"+temp);
}
Field f = clazz.getDeclaredField("uname");//获得指定的field
System.out.println(f);
//获得方法信息
Method[] methods = clazz.getMethods();//只能获得public的method
Method[] methods2 = clazz.getDeclaredMethods();//获得所有的method
//如果方法有参数,必须传递参数类型对应的Class对象
Method method = clazz.getDeclaredMethod("getUname", null);//第二个参数是参数类型(考虑方法重载override)
Method method2 = clazz.getDeclaredMethod("setUname", String.class);
for(Method m:methods2){
System.out.println("方法:"+m);
}
//获得构造器信息
Constructor[] constructors = clazz.getConstructors();//获得public构造器
Constructor[] constructors2 = clazz.getDeclaredConstructors();//获得所有的构造器
for(Constructor temp:constructors){
System.out.println("构造器:"+temp);
}
//获得指定构造器
Constructor constructor = clazz.getDeclaredConstructor(null);//获得无参构造器
Constructor constructor2 = clazz.getDeclaredConstructor(int.class,int.class,String.class);//获得有参构造器
System.out.println(constructor2);
} catch (Exception e) {
e.printStackTrace();
}
}
}

6、通过反射动态操作:构造器、方法及属性

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.bjsxt.test.bean.User;
/**
* 通过反射API动态操作:构造器、方法、属性
* @author WQ
*
*/
public class Demo03 {
public static void main(String[] args) {
//User.java类的路径
String path = "com.bjsxt.test.bean.User";
try {
//动态加载User类
Class<User> clazz = (Class<User>)Class.forName(path);
//通过反射API调用构造方法,构造对象
//调用无参构造器,构造对象
User u = clazz.newInstance();//其实是调用了User的无参构造器来创建User类对象
System.out.println(u);
//调用有参构造器,构造对象
Constructor<User> c = clazz.getDeclaredConstructor(int.class,int.class,String.class);
User u2 = c.newInstance(1001,18,"wmm");
System.out.println(u2.getUname());
//通过反射API调用普通方法
User u3 = clazz.newInstance();
//别人给传什么方法名,然后就可动态的调用什么方法,这就是反射的好处
Method method = clazz.getDeclaredMethod("setUname", String.class);
method.invoke(u3, "wem");	//u3.setUname("wem");
System.out.println(u3.getUname());
//通过反射API操作属性
User u4 = clazz.newInstance();
Field f = clazz.getDeclaredField("uname");
f.setAccessible(true);//这个属性不需要做安全检查了,可以直接访问(可以访问private属性)
f.set(u4, "cmz");//通过反射直接写属性,给User对象u4的uname设置为cmz
System.out.println(u4.getUname());//通过对象直接调用
System.out.println(f.get(u4));//通过反射直接读属性的值
} catch (Exception e) {
e.printStackTrace();
}
}
}

7、反射机制性能问题

        setAccessible
        启动和禁用访问安全检查的开关,值为true则指示反射的对象在使用时应该取消Java语言访问检查, 值为false则指示反射的对象应该实施Java语言访问检查。并不是为true就能访问,为false就不能访问。
        禁止安全检查,可以提高反射的运行速度。

最后

以上就是闪闪小蚂蚁为你收集整理的java动态性之反射机制(Reflection)的全部内容,希望文章能够帮你解决java动态性之反射机制(Reflection)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部