什么是类反射
☆什么是反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
反射(Reflection)是Java程序开发语言的特征之一,它允许运行中的Java程序对自身进行检查, 也称自审,并能直接操作程序的内部属性。例如,使用它能获得Java类中各成员的名称并显示出来。
Java的这一能力在实际应用中应用得很多,在其它的程序语言中根本就不存在这一特性。例如,Pascal、C或者C++中就没有办法在程序中获得函数定义相关的信息。
JavaBean是类反射的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过类反射动态的载入并取得Java组件(类)的属性。后面学习的各种框架,基本上都会有反射的使用。
☆反射引例(HelloWorld、USB)
HelloWorld:
初识类反射,通过Class.forName("类名")获得一个Class对象,通过这个对象获得成员变量,构造方法和普通方法。
<span style="font-family:Times New Roman;font-size:14px;color:#000000;">package cn.hncu.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectionHelloWorld {
public static void main(String[] args) {
//UserModel user = new UserModel();
try {
Class c = Class.forName("cn.hncu.reflect.UserModel");
//c.getFields()
//c.getConstructors();
//Method ms[] = c.getMethods();
Method ms[] = c.getDeclaredMethods();
for(int i=0;i<ms.length;i++){
System.out.println(ms[i].toString());
}
System.out.println("-------------");
Constructor cons[] = c.getConstructors();
for(Constructor con: cons){
System.out.println(con.toString());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
</span>
USB:
通过Usb.config配置文件和类反射来实现不用修改源代码就可以更改用的类。
<span style="font-family:Times New Roman;font-size:14px;color:#000000;">package cn.hncu.reflect.usb;
public interface USB {
public abstract void work();
}
</span>
<span style="font-family:Times New Roman;font-size:14px;color:#000000;">package cn.hncu.reflect.usb;
import java.util.Properties;
public class USBFactory {
public static USB getUSB() {
// return new UsbOne();
USB u = null;
Properties p = new Properties();
try {
p.load(USBFactory.class.getResourceAsStream("usb.config"));
String name = p.getProperty("name");
Class c = Class.forName(name);
u= (USB) c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return u;
}
}
</span>
<span style="font-family:Times New Roman;font-size:14px;color:#000000;">package cn.hncu.reflect.usb;
public class UsbOne implements USB {
@Override
public void work() {
System.out.println("UsbOne is working....");
}
}
</span>
<span style="font-family:Times New Roman;font-size:14px;color:#000000;">package cn.hncu.reflect.usb;
public class UsbTwo implements USB {
@Override
public void work() {
System.out.println("UsbTwo is working....");
}
}
</span>
usb.config的内容如图所示:
如果想让UsbTwo工作,只需把UsbOne改成UbsTwo即可,此方法灵活且符合了Java中“开闭原则”。
反射最大的好处是解耦
反射使用的三个步骤
用于反射的类,如Method,可以在java.lang.reflect包中找到。使用这些类的时候必须要遵循三个步骤:
第一步:获得你想操作的类的java.lang.Class对象。在运行中的Java程序中,用java.lang.Class类来描述类和接口等。
第二步:调用诸如getDeclaredMethods的方法,取得该类中定义的所有方法的列表。
第三步:使用反射的API来操作这些信息。
如下面这段代码:
Class c = Class.forName("java.lang.String");
Method ms[] = c.getDeclaredMethods();
System.out.println(ms[0].toString());
它将以文本方式打印出String中定义的第一个方法的原型。
☆反射示例(模拟instanceof的功能)
<span style="font-family:Times New Roman;font-size:14px;color:#000000;">package cn.hncu.reflect;
public class SimulateInstanceof {
public static void main(String[] args) {
try {
Class c = Class.forName("cn.hncu.reflect.UserModel");
//boolean boo = c.isInstance( new Integer(30) ); //false
//boolean boo = c.isInstance( new String("abc") ); //false
boolean boo = c.isInstance( new UserModel() ); //true
System.out.println(boo);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
</span>
获取Class对象的三种方式
★ 方式一
通过对象的getClass方法进行获取。这种方式需要具体的类和该类的对象,以及调用getClass方法。
★ 方式二
任何数据类型(包括基本数据类型)都具备着一个静态的属性class,通过它可直接获取到该类型对应的Class对象。这种方式要使用具体的类,然后调用类中的静态属性class完成,无需调用方法,性能更好。
★ 方式三
通过Class.forName()方法获取。这种方式仅需使用类名,就可以获取该类的Class对象,更有利于扩展。
具体代码:
<span style="font-family:Times New Roman;font-size:14px;color:#000000;">package cn.hncu.reflect;
import org.junit.Test;
//获取Class对象的三种方式
public class ReflectGetClass {
@Test//法1:通过 对象.getClass()
public void getClass1() {
Person p = new Person("Jack",22);
Class c = p.getClass();
System.out.println(c);
}
@Test//法2:通过类型---任何数据类型(包含基本数据类型)都拥有一个静态变量class
public void getClass2() {
Class c = Person.class;
System.out.println(c);
Class c2 = int.class;
System.out.println(c2);
}
@Test//法3:通过Class.forName直接获取---不依赖具体的类或对象(仅仅依赖String类,而我们做项目时通常把使用API中的类看成不是依赖的!)
public void getClass3() {
try {
Class c = Class.forName("cn.hncu.reflect.Person");//“类全名”的字符串形式
System.out.println(c);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//※法3是不依赖于被反射类或对象的,能够完全达到解藕的效果,是我们以后开发当中的首选策略
}
</span>
类的解剖(获取类的定义信息)
★ 获取类的方法
找出一个类中定义了些什么方法,这是一个非常有价值也非常基础的反射用法。
★ 获取类的构造器
找出一个类中定义的构造方法,构造器没有返回类型。
★ 获取类的属性字段
找出一个类中定义了哪些属性字段。
代码实现:
<span style="font-family:Times New Roman;font-size:14px;color:#000000;">package cn.hncu.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.junit.Test;
//类的解剖:把一个类中的所有方法、属性、构造方法全部获取出来
public class ReflectDecompose {
private static final String className="cn.hncu.reflect.Student";
//private static final String className="cn.hncu.reflect.Person";
//1 c.getMethods()----获取的是当前类及其父类的公开方法---无法获取到私有方法
//2 c.getDeclaredMethods()----获取的是当前类自己定义的那些方法---包括私有的 但不包括父类中的方法
@Test//获取方法
public void fetchMethods() throws Exception{
Class c = Class.forName(className);
//Method ms[] = c.getMethods();//所能访问的方法和一个“Person p=new Person()”中的p对象一样
Method ms[] = c.getDeclaredMethods();
for(int i=0;i<ms.length;i++){
Method m = ms[i];
System.out.println("name: "+m.getName());
System.out.println("declaringClass: "+ m.getDeclaringClass());
Class paramTypes[] = m.getParameterTypes();
for(int j=0;j<paramTypes.length;j++){
System.out.println("param#"+j+": "+ paramTypes[j]);
}
Class returnType = m.getReturnType();
System.out.println("returnType: "+returnType);
Class excepts[] = m.getExceptionTypes();
for(int j=0;j<excepts.length;j++){
System.out.println("excepts#"+j+": "+ excepts[j]);
}
int modifiers = m.getModifiers();
System.out.println("modifiers: "+modifiers);
System.out.println("--------------");
}
}
//注意,构造方法都不包含父类的
//1 c.getConstructors()----获取的是当前类(注意不包含父类的)的公开构造方法---无法获取到私有方法
//2 c.getDeclaredConstructors()----获取的是当前类自己定义的构造方法---包括私有的
@Test//获取方法
public void fetchConstructors() throws Exception{
Class c = Class.forName(className);
//Constructor cons[] = c.getConstructors();//所能访问的方法和一个“Person p=new Person()”中的p对象一样
Constructor cons[] = c.getDeclaredConstructors();
for(int i=0;i<cons.length;i++){
Constructor con = cons[i];
System.out.println("name: "+con.getName());
System.out.println("declaringClass: "+ con.getDeclaringClass());
Class paramTypes[] = con.getParameterTypes();
for(int j=0;j<paramTypes.length;j++){
System.out.println("param#"+j+": "+ paramTypes[j]);
}
Class excepts[] = con.getExceptionTypes();
for(int j=0;j<excepts.length;j++){
System.out.println("excepts#"+j+": "+ excepts[j]);
}
int modifiers = con.getModifiers();
System.out.println("modifiers: "+modifiers);
System.out.println("--------------");
}
}
//1 c.getFields()----获取的是当前类和父类的公开属性---无法获取到私有属性
//2 c.getDeclaredFields()----获取的是当前类自己定义的属性---包括私有的
@Test//获取方法
public void fetchFields() throws Exception{
Class c = Class.forName(className);
//Field flds[] = c.getFields();
Field flds[] = c.getDeclaredFields();
for(int i=0;i<flds.length;i++){
Field fld = flds[i];
System.out.println("name: "+fld.getName());
System.out.println("declaringClass: "+ fld.getDeclaringClass());
Class type = fld.getType();
System.out.println("type: "+ type);
int modifiers = fld.getModifiers();
System.out.println("modifiers: "+Modifier.toString(modifiers) );
System.out.println("--------------");
}
}
}
</span>
Student类:
<span style="font-family:Times New Roman;font-size:14px;color:#000000;">package cn.hncu.reflect;
public class Student extends Person{
public int a;
private String spec;
public Student(){
}
}
</span>
Person类:
<span style="font-family:Times New Roman;font-size:14px;color:#000000;">package cn.hncu.reflect;
public class Person {
private String name;
private int age;
public static final double PI=3.14;
public Person() {
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
private Person(String name) {
this.name = name;
}
private int sum( int n){
int s=0;
for(int i=1;i<=n;i++){
s +=i;
}
return s;
}
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;
}
@Override
public String toString() {
return name + ", " + age;
}
}
</span>