根据李兴华的视频整理的
大致是先得到Class的类的对象,然后在用这个对象调用newInstance方法创建实例,就可以对实例进行操作了
Java反射的源头是Class这个类:
public final class Classextends implements , , ,
Class
类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class
对象。基本的 Java 类型(boolean
、byte
、char
、short
、int
、long
、float
和 double
)和关键字 void
也表示为 Class
对象。
Class
没有公共构造方法。Class
对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass
方法自动构造的。
以下示例使用 Class
对象来显示对象的类名:
void printClassName(Object obj) { System.out.println("The class of " + obj + " is " + obj.getClass().getName()); }
实例化Class对象有3中方法:
1、Class.forName()
public static forName( className) throws
返回与带有给定字符串名的类或接口相关联的 Class
对象。
这个最常用啦,比如说java连接数据库加载驱动时:Class.forName("com.mysql.jdbc.Driver") ; 字符串为 包名.类名
2、类名.class
3、对象.getClass()
得到Class类的对象后就可以调用newInstance方法创建实例啦
public newInstance() throws ,
- 创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的
new
表达式实例化该类。如果该类尚未初始化,则初始化这个类。
注意:类中必须提供无参构造函数(如果不写构造函数,那么类本身就提供无参构造函数,如果写了构造函数,那么那个默认的就没有了),而且那个构造函数还得是可以访问的,如果是私有的话,那就不行啦
1 package yxy; 2 3 class Person{ 4 private String name; 5 public String getName() { 6 return name; 7 } 8 9 public void setName(String name) {10 this.name = name;11 }12 private Person(){13 this.setName("crane");14 }15 16 public String toString(){17 return "name= "+this.getName();18 }19 }20 21 public class Test {22 23 public static void main(String[] args) {24 // TODO Auto-generated method stub25 try {26 System.out.println(Class.forName("yxy.Person").newInstance());27 } catch (InstantiationException e) {28 // TODO Auto-generated catch block29 e.printStackTrace();30 } catch (IllegalAccessException e) {31 // TODO Auto-generated catch block32 e.printStackTrace();33 } catch (ClassNotFoundException e) {34 // TODO Auto-generated catch block35 e.printStackTrace();36 }37 }38 39 40 }
java.lang.IllegalAccessException: Class yxy.Test can not access a member of class yxy.Person with modifiers "private" at sun.reflect.Reflection.ensureMemberAccess(Unknown Source) at java.lang.Class.newInstance(Unknown Source) at yxy.Test.main(Test.java:26)
如果把12行改为public Person(){
则运行结果为:name= crane
如果是带参的可访问的构造函数也是不行的,
不过可以用getConstructors来整(有点儿像病句哇)
()
返回一个包含某些 Constructor
对象的数组,这些对象反映此 Class
对象所表示的类的所有公共构造方法。
1 package yxy; 2 3 import java.lang.reflect.Constructor; 4 5 class Person{ 6 private String name; 7 public String getName() { 8 return name; 9 }10 11 public void setName(String name) {12 this.name = name;13 }14 public Person(){15 this.setName("crane");16 }17 public Person(String name){18 this.setName(name);19 }20 public String toString(){21 return "name= "+this.getName();22 }23 }24 25 public class Test {26 27 public static void main(String[] args) throws Exception {28 // TODO Auto-generated method stub29 Class c=null;30 c=Class.forName("yxy.Person");31 Constructor [] cons=null;32 cons=c.getConstructors();33 Person person=null;34 //输出所有公有构造函数,私有的是不能得到的35 for(Constructor con:cons){36 System.out.println(con);37 }38 person=(Person) cons[1].newInstance("crane");39 System.out.println(person);40 }41 }
运行结果:
public yxy.Person()public yxy.Person(java.lang.String)name= crane
呃,震惊了,私有属性和方法的也可以通过反射被看到:
呃,原来这个人写的都有啦: 这是个好文章
还有个好文章哇::
禁止反射:
反射的应用场景:
第一讲 反射的应用场景 一、概述 反射技术: Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 简单一句话:反射技术可以对类进行解剖。 二、应用场景 一个已经可以使用的应用程序,因为程序已经做好可以运行使用,不能再进行代码的加入了。而当后期我们新的功能加入程序时,该怎么做呢?就如我们的电脑一样,后期我们可能会鼠标、键盘等,所以电脑给我们预留了usb接口,只要符合这个接口规则的设备,电脑就可以通过加载驱动等操作来使用。 那这个程序能用了,如何使用后期出现的功能类呢? 常用的作法,会提供一个配置文件,来供以后实现此程序的类来扩展功能。对外提供配置文件,让后期出现的子类直接将类名字配置到配置文件中即可。该应用程序直接读取配置文件中的内容。并查找和给定名称相同的类文件。进行如下操作: 1)加载这个类。 2)创建该类的对象。 3)调用该类中的内容。 应用程序使用的类不确定时,可以通过提供配置文件,让使用者将具体的子类存储到配置文件中。然后该程序通过反射技术,对指定的类进行内容的获取。 好处:反射技术大大提高了程序的扩展性。 |
更加详细的:
crane:SSH框架中都用到了反射机制(读配置文件获得类名,然后进行反射操作)
《Effective Java》中文版第2版第53条中有说到反射机制的注意事项,
反射是在运行时执行的,丧失了编译时类型检查的好处,包括异常检查,如果程序反射的调用不存在的方法,在运行时会失败,除非采取了特别的预防措施。
详情参看那本书