------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一.理解。
1.概述:
应用程序已经写好,后期出现的接口子类无法直接在该应用程序中用new创建对象。
既然子类不确定,可以通过对外提供配置文件的形式,将不确定的信息存储到配置文件中即可。
该应用程序只要之前写好如何读取配置文件信息即可。
如果存储了指定的子类名,就根据具体的名称找该类并进行加载和对象的创建,这些动作都在前期定义软件时写好的。就是在没有类之前就将创建对象的动作完成了。动态的获取指定的类,并使用类中的功能。
(配置文件:把具体实现的子类的名称定义到配置文件中。)
2.反射技术:
其实就是动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。简单说:反射技术可以对一个类进行解剖。
3.好处:反射技术大大提高了程序的扩展性。
二.Class类。
1.Class类:
描述字节码文件的对象。
Class类是Java程序中各个Java类的总称。它是反射的基石,通过Class类来使用反射。
Class类中就包含属性有field(字段)、method(方法)、construction(构造函数)。
2.获取这个Class对象,有三种方式:
1)、通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。
例子:
Person p1 = new Person();
Class clazz = p1.getClass();
System.out.println(clazz.getName());//获取类的名字。
2)、任何数据类型都具备着一个静态的属性class,这个属性直接获取到该类型的对应Class对象。不用new对象,但是要使用具体的类。
例子:
Class clazz = Person.class;
3)、使用的Class类中的方法,静态的forName方法。通过给定的类名来获取字节码文件对象。
例子:
String className = "Person";//来自配置文件。
Class clazz = Class.forName(className);//此对象代表Person.class
以上两行代码其实就是完成三个步骤:
1,通过给定的类名称,加载对应的字节码文件,并封装成字节码文件对象Class。
2,通过new创建给定的类的实例。
3,调用该类的构造函数。
第三种方式好处:指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。
这就是反射技术使用的获取字节码文件对象的方式。
通常被反射的类都会提供空参数的构造函数。没有对应的构造函数,会报InstantiationException。如果有提供,但权限不够,会报IllegalAccessException异常。
3.获取了字节码文件对象后,最终都需要创建指定类的对象:
1)、通过newInstance()就可以创建字节码文件对象所表示的类的实例。
调用空参数的构造函数:使用了Class类中的newInstance()方法。
(接上面方式3代码):
Object obj = clazz.newInstance();
System.out.println(obj);
2)、如果被反射的类没有空参数的构造函数:(Constructor类)
(接上面方式3代码):
//获取指定的构造器。获取Person类中两个参数String,int的构造函数。
Constructor cons = clazz.getConstructor(String.class,int.class);
//有了构造器对象后,通过构造器对象来初始化该类对象。
Object obj = cons.newInstance("wangwu",23);
4.获取字段:(Field类)
(代码 GetField.java):
class Person
{
private String name;
private int age;
Person()
{
super();
}
Person(String name,int age)
{
super();
this.name=name;
this.age=age;
}
public String toString()
{
return name+":"+age;
}
public void show(String name,int age)
{
System.out.println("show run name="+name+",age="+age);
}
public static void staticshow()
{
System.out.println("static run name");
}
}
//获取Person对象的成员变量
import java.lang.reflect.*;
class GetField
{
public static void main(String[] args) throws Exception
{
//通过配置文件获取类名(获取字节码文件对象):
String className = "Person";
Class clazz = Class.forName(className);
//获取字段:
String fieldName = "age";
//Field field = clazz.getField(fieldName);//获取的是公共字段。
Field field = clazz.getDeclaredField(fieldName);//获取的是已有的字段。
//创建指定的类的对象:
Object obj = clazz.newInstance();
//设置字段:(对其进行值的设置,必须先有对象)
field.setAccessible(true);//取消权限检查。暴力访问。
field.set(obj,30);//IllegalAccessException异常:age字段是私有的。
System.out.println(field.get(obj));
}
}
5.获取方法:(Method类)
(代码 GetMethod.java):
import java.lang.reflect.*;
class GetMethod
{
public static void main(String[] args) throws Exception
{
String className = "Person";
Class clazz = Class.forName(className);
//获取带参数的方法
/*
Object obj = clazz.newInstance();
String methodName = "show";
Method method = clazz.getMethod(methodName,String.class,int.class);
method.invoke(obj,"lisi",20);
*/
//获取不带参数的静态方法
String methodName = "staticshow";
Method method = clazz.getMethod(methodName,null);
method.invoke(null,null);//第一个null是因为静态,不用new对象。
}
}