JavaSE|Java的反射技术(Class类,Constructor类,Method类, Field类)

【JavaSE|Java的反射技术(Class类,Constructor类,Method类, Field类)】Java编码时知道类和对象的具体信息,此时直接对类和对象进行操作即可,无需反射 如果编码时不知道类或者对象的具体信息,此时应该使用反射来实现
为什么要使用反射
  1. 反射就是把Java类中的各种成分映射成一个个的java对象。例如,一个类有:成员变量,方法,构造方法,包等等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。
反射技术常见于框架中。
比如类的名称放在XML文件中,属性和属性值放在XML文件中,需要在运行时读取XML文件,动态获取类的信息。
在编译时根本无法知道该对象或类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息。
反射的作用:创建对象、操作属性、调用方法
如何使用反射 掌握反射技术的要点在于:如何从一个class中反射出各个组成部分。反射出来的对象怎么用。
Class类 Class类:代表一个类,是Java反射机制的起源和入口,用于获取与类相关的各种信息
提供了获取类信息的相关方法(Class类继承自Object类)
Class类是所有类的共同的图纸
每个类有自己的对象,同时每个类也看做是一个对象,有共同的图纸Class,存放类的结构信息,能够通过相应方法取出相应的信息:类的名字、属性、方法、构造方法、父类和接口。
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int,void…
反射就是把Java类中的各种成分映射成一个个的java对象。例如,一个类有:成员变量,方法,构造方法,包等等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。
那么,既然反射的作用是创建对象、操作属性、调用方法,要实现以上3个作用,需要用到下面介绍的3个类:Constructor类,Method类, Field类
Constructor类 (1)Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
例子:
Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

得到某一个构造方法:
例子: //获得方法时要用到类型
Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

(2)创建实例对象:
通常方式:
String str = new String(new StringBuffer("abc"));

反射方式:
String str = (String)constructor.newInstance(new StringBuffer("abc"));

Class.newInstance()方法:
例子:
String obj = (String)Class.forName("java.lang.String").newInstance();

该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
Method类 Method类代表某个类中的一个成员方法
得到类中的某一个方法——
例子:
Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);

调用方法——
通常方式:
System.out.println(str.charAt(1));

反射方式:
System.out.println(charAt.invoke(str, 1));

如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!
jdk1.4和jdk1.5的invoke方法的区别:
Jdk1.5:public Object invoke(Object obj,Object… args)
Jdk1.4:public Object invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。
Field类 Field类代表某个类中的一个成员变量
问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义,而不是具体的x变量。(注意访问权限的问题)
示例代码:
ReflectPoint point = new ReflectPoint(1,7); Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y"); System.out.println(y.get(point)); //Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x"); Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x"); x.setAccessible(true); System.out.println(x.get(point));

实例演示 首先,我们自定义一个Person类,它是我们将要进行反射的目标。.
在这个类里面,我们定义了:
1.构造方法
2.实例方法
3.属性
package cn.itcast.reflect; import java.io.InputStream; import java.util.List; public class Person { public String name = "yaoer"; private int password = 123; private static int age = 23; public Person() { System.out.println("person"); } public Person(String name) { System.out.println(name); } public Person(String name, int password) { System.out.println(name + ":" + password); } private Person(List list) { System.out.println("list"); } public void aa1() { System.out.println("aaa1"); } public void aa1(String name, int password) { System.out.println(name + ":" + password); } public String aa1(String name, int[] password) { return new String("adad"); } private void aa1(InputStream in) { System.out.println(in); } public static void aa1(int num) { System.out.println(num); } public static void main(String[] args) { System.out.println("main!"); } }

反射:类的构造函数 ,创建类的对象
package cn.itcast.reflect; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; import org.junit.Test; //解剖(反射)类的构造函数 ,创建类的对象 public class Demo2 { // 1——反射构造函数:public Person() @Test public void test1() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Constructor c = clazz.getConstructor(null); Person p = (Person) c.newInstance(null); System.out.println(p.name); } // 2——反射构造函数:public Person(String name) @Test public void test2() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Constructor c = clazz.getConstructor(String.class); Person p = (Person) c.newInstance("xxxooo"); System.out.println(p.name); } // 3——反射构造函数:public Person(String name,int password) @Test public void test3() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Constructor c = clazz.getConstructor(String.class,int.class); Person p = (Person) c.newInstance("xxxooo",20); System.out.println(p.name); } // 4——反射构造函数:private Person(List list) @Test public void test4() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Constructor c = clazz.getDeclaredConstructor(List.class); c.setAccessible(true); //暴力反射 Person p = (Person) c.newInstance(new ArrayList()); System.out.println(p.name); }@Test public void test5() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Person p = (Person) clazz.newInstance(); } }

反射:类中的方法
/** * */ package cn.itcast.reflect; import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; import org.junit.Test; /** * 反射类中的方法 * */ public class Demo3 { // 反射类的方法: public void aa1(){ @Test public void test1() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method = clazz.getMethod("aa1", null); Object obj = clazz.newInstance(); method.invoke(obj, null); } // 反射类的方法: public void aa1(String name,int password){ @Test public void test2() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method = clazz.getMethod("aa1", String.class, int.class); Object obj = clazz.newInstance(); method.invoke(obj, "yaoer", 24); } // 反射类的方法: public void aa1(String name,int[] password){ @Test public void test3() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method = clazz.getMethod("aa1", String.class, int[].class); int[] a = new int[] { 1, 2, 3 }; Object obj = clazz.newInstance(); System.out.println(method.invoke(obj, "yaoer", a)); } // 反射类的方法:private void aa1(InputStream in) @Test public void test4() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method = clazz.getDeclaredMethod("aa1", InputStream.class); // private method.setAccessible(true); Object obj = clazz.newInstance(); System.out.println(method.invoke(obj, new FileInputStream("c://1.txt"))); // 对应目录下需要存在此文件 } // 反射类的方法:public static void aa1(int num) { @Test public void test5() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Object obj = clazz.newInstance(); Method m = clazz.getMethod("aa1", int.class); m.invoke(obj, 23); } // 反射类的方法: public static void main(){ @Test public void test6() throws Exception {Class clazz = Class.forName("cn.itcast.reflect.Person"); Method method = clazz.getMethod("main", String[].class); // method.invoke(null, new Object[] {new String[] {"aa","bb"}}); method.invoke(null, (Object) new String[] { "aa", "bb" }); }}

反射:类中的字段(属性)
/** * */ package cn.itcast.reflect; import java.lang.reflect.Field; import org.junit.Test; /** * 反射字段 * */ public class Demo5 { // 反射字段:public String name = "yaoer"; @Test public void test1() throws Exception { Class clazz = Class.forName("cn.itcast.reflect.Person"); Object obj = clazz.newInstance(); Field f = clazz.getField("name"); // 获取字段的值 Object val = f.get(obj); // 获取字段的类型 Class type = f.getType(); if (type.equals(String.class)) { String sval = (String) val; System.out.println(sval); }// 设置字段的值 f.set(obj, "zhuzhu"); System.out.println(f.get(obj)); } // 反射字段:private int password; ; @Test public void test2() throws Exception { Class clazz = Class.forName("cn.itcast.reflect.Person"); Object obj = clazz.newInstance(); Field f = clazz.getDeclaredField("password"); f.setAccessible(true); // 改变访问权限System.out.println(f.get(obj)); } // 反射字段:private static int age = 23; @Test public void test3() throws Exception { Class clazz = Class.forName("cn.itcast.reflect.Person"); Object obj = clazz.newInstance(); Field f = clazz.getDeclaredField("age"); f.setAccessible(true); // 改变访问权限System.out.println(f.get(obj)); }}

反射技术优缺点
  • 优点
反射提高了Java程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提高硬编码目标类
反射是其他一些常用语言,如C、C++、Fortran或者Pascal等不具备的
Java反射技术应用领域很广,如软件测试、JavaBean等
许多流行的开源框架例如Struts、Hibernate、Spring在实现过程中都采用了该技术
  • 缺点
性能问题:使用反射基本上是一种解释操作哦,用于字段和方法接入时要远慢于直接代码。因此Java反射机制只要应用在对;灵活性和扩展性要求很高的系统框架上,普通程序不建议使用
使用反射会模糊程序内部逻辑:程序员希望在代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂
参考文章:https://blog.csdn.net/Elias94/article/details/80361035

    推荐阅读