Java中的反射
Posted Beans_bag
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的反射相关的知识,希望对你有一定的参考价值。
1、反射技术简介
Java反射技术应用广泛,它能够配置:类的全限定名、方法和参数,完成对象的初始化,甚至可以反射某些方法。这样就大大增强了Java的可配置性,Spring IOC的基本原理也是如此。
2、Java反射机制的定义
Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的属性和方法。对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用方法的功能成为Java的反射机制。用一句话总结就是Java的反射机制可以在运行状态中知道任意一个类的属性和方法。
优点
通过配置就可以生成对象,可以解除程序的耦合性,非常灵活。而且在项目上线后,后期可以很方便的对项目功能进行更新。
缺点
运行慢,对程序的性能有一定的影响。因为使用反射基本上是一种解释性操作。这类操作总是慢于直接执行相同的操作。
3、Java类和类类型
类是java.lang.Class类的实例对象,而Class是所有类的类。对于普通的对象,我们一般都会这样创建和表示:
Person p = new Person();
上面说了,所有的类都是Class的对象,那么如何表示呢,可不可以通过如下方式呢:
Class clazz = new Class();
但是我们查看Class的源码时,是这样写的:
private Class(ClassLoader loader) { // Initialize final field for classLoader. The initialization value of non-null // prevents future JIT optimizations from assuming this final field is null. classLoader = loader;
}
可以看到构造器是私有的,只有JVM可以创建Class的对象,因此不可以像普通类一样new一个Class对象,虽然我们不能new一个Class对象,但是却可以通过已有的类得到一个Class对象,共有三种方式,如下:
//这说明任何一个类都有一个隐含的静态成员变量class,这种方式是通过获取类的静态成员变量class得到的 Class clazz1 = Person.class; //这种方式是通过一个类的对象的getClass()方法获得的 Person p = new Person(); Class<? extends Person> clazz2 = p.getClass(); //这种方法是Class类调用forName方法,通过一个类的全量限定名获得 Class<?> clazz3 = Class.forName("cn.zhuangxp.reflect.Person");
这里的clazz1、clazz2、clazz3都是Class对象,他们是完全一样的,而且有个学名,叫做Person的类类型。类类型就是类的类型,就是描述一个类是什么,有那些属性和方法。所以我们可以通过类的类型,来获取一个类属性和方法,并且调用它的属性和方法,这就是反射的基础。
举个简单的例子
Person类
package cn.zhuangxp.reflect; /** * @author BEAN_BAG * @date 2018年4月29日 * @description Person实体类 */ public class Person { private String name; private int age; private String hobby; public String msg = "HelloWorld"; public String phone = "13066612345"; private String email = "[email protected]"; public Person() { } public Person(String name, int age){ this.name = name; this.age = age; } private Person(String name, int age, String hobby) { this.name = name; this.age = age; this.hobby = hobby; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getHobby() { return hobby; } public void setHobby(String hobby) { this.hobby = hobby; } @Override public String toString() { return "Person{" + "name=‘" + name + ‘‘‘ + ", age=" + age + ", hobby=‘" + hobby + ‘‘‘ + ‘}‘; } public void say(String name, int age) { System.out.println("我叫:" + name + ",今年:" + age); } private void play(String hobby) { System.out.println("我的爱好是:" + hobby); } }
测试类
public class Demo01 { public static void main(String[] args) throws ClassNotFoundException { //这说明任何一个类都有一个隐含的静态成员变量class,这种方式是通过获取类的静态成员变量class得到的 Class clazz1 = Person.class; System.out.println(clazz1.getName()); //这种方式是通过一个类的对象的getClass()方法获得的 Person p = new Person(); Class<? extends Person> clazz2 = p.getClass(); System.out.println(clazz2.getName()); //这种方法是Class类调用forName方法,通过一个类的全量限定名获得 Class<?> clazz3 = Class.forName("cn.zhuangxp.reflect.Person"); System.out.println(clazz3.getName()); } }
结果
cn.zhuangxp.reflect.Person
cn.zhuangxp.reflect.Person
cn.zhuangxp.reflect.Person
4、Java反射的相关操作
获取指定成员方法Method
public class Demo02 { public static void main(String[] args) throws Exception { Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person"); Object instance = clazz.newInstance(); /** * 返回某个类的指定的公共(public)成员方法 */ Method method1 = clazz.getMethod("say",String.class,int.class); method1.invoke(instance,"BEAN_BAG",23); /** * 返回某个类的指定已声明方法 */ Method method2 = clazz.getDeclaredMethod("play", String.class); //取消Java权限控制检查 method2.setAccessible(true); method2.invoke(instance,"乒乓球"); } }
结果
我叫:BEAN_BAG,今年:23
我的爱好是:乒乓球
获取所有方法
public class Demo03 { public static void main(String[] args) throws ClassNotFoundException { Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person"); /** * 返回某个类的所有公共(public)方法,,包括其继承类的公共方法, * 也包括它所实现的接口的方法。 */ Method[] methods = clazz.getMethods(); for (Method m : methods) { System.out.println(m.getName()); } System.out.println("================================================="); /** * 返回某个类的所有方法,包括公共、保护、默认访问和私有的方法。 * 但是不包括继承的方法,当然也包括它所实现的接口的方法。 */ Method[] methods1 = clazz.getDeclaredMethods(); for (Method m : methods1){ System.out.println(m.getName()); } } }
结果
toString getName setName setMsg say setHobby getMsg setAge getHobby getAge wait wait wait equals hashCode getClass notify notifyAll ================================================= toString getName setName play setMsg say setHobby getMsg setAge getHobby getAge
获取成员变量Field
public class Demo04 { public static void main(String[] args) throws Exception { Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person"); Object instance = clazz.newInstance(); /** * 获得该类中指定的public成员变量,包括其父类变量 */ Field field = clazz.getField("msg"); Object msg = field.get(instance); System.out.println(msg.toString()); System.out.println("==============================================="); /** * 获得该类中所有的自身声明的变量,不包括其父类的变量 */ Field field1 = clazz.getDeclaredField("email"); field1.setAccessible(true); Object email = field1.get(instance); System.out.println(email.toString()); } }
结果
HelloWorld =============================================== [email protected]163.com
获取所有的成员变量
public class Demo05 { public static void main(String[] args) throws Exception { Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person"); Object instance = clazz.newInstance(); /** * 获得该类所有的public成员变量,包括其父类变量 */ Field[] fields = clazz.getFields(); for (Field f : fields){ Object o = f.get(instance); System.out.println(o.toString()); } System.out.println("==========================================="); /** * 获得该类自身声明的所有变量,不包括其父类的变量 */ Field[] fields1 = clazz.getDeclaredFields(); for (Field f : fields1){ System.out.println(f.getName()); } } }
结果
HelloWorld 13066612345 =========================================== name age hobby msg phone email
获取构造器
public class Demo06 { public static void main(String[] args) throws Exception { Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person"); Object instance = clazz.newInstance(); /** * 获得该类的public构造器 */ Constructor<?> constructor = clazz.getConstructor(String.class,int.class); Object o = constructor.newInstance("BEAN_BAG", 23); System.out.println(o); System.out.println("========================================="); /** * 获得该类所有的构造器 */ Constructor<?> constructor1 = clazz.getDeclaredConstructor(String.class,int.class,String.class); constructor1.setAccessible(true); Object o1 = constructor1.newInstance("mm",22,"English"); System.out.println(o1); } }
结果
Person{name=‘BEAN_BAG‘, age=23, hobby=‘null‘} ========================================= Person{name=‘mm‘, age=22, hobby=‘English‘}
获取所有的构造器
public class Demo07 { public static void main(String[] args) throws Exception { Class<?> clazz = Class.forName("cn.zhuangxp.reflect.Person"); Object instance = clazz.newInstance(); /** * 获得该类所有的public构造器 */ Constructor<?>[] constructors = clazz.getConstructors(); for (Constructor c : constructors){ System.out.println(c.getName()); } System.out.println("===================================="); /** * 获得该类所有的构造器 */ Constructor<?>[] constructors1 = clazz.getDeclaredConstructors(); for (Constructor c : constructors1){ System.out.println(c.getName()); } } }
结果
cn.zhuangxp.reflect.Person cn.zhuangxp.reflect.Person ==================================== cn.zhuangxp.reflect.Person cn.zhuangxp.reflect.Person cn.zhuangxp.reflect.Person
5、通过反射了解泛型的本质
Java中集合的泛型,是防止错误输入的,只在编译阶段有效。如果绕过编译期,到运行期就无效了。所以,我们可以通过Java的反射绕过泛型检查,完整代码如下:
public class Demo08 { public static void main(String[] args) throws Exception { List<String> list = new ArrayList<String>(); list.add("zhuang14");//允许添加 //list.add(25);//添加int类型报错,因为泛型为String //获取list的类类型 Class<? extends List> clazz = list.getClass(); //获取list集合的add方法 Method addMethod = clazz.getMethod("add", Object.class); addMethod.invoke(list,25); //结果 System.out.println(list);//[zhuang14, 25] } }
以上是关于Java中的反射的主要内容,如果未能解决你的问题,请参考以下文章