一:反射机制
在程序的运行时期,通过Class类的内部结构,并可实例化类,并修改值域,调用方法等。
二:反射包含的内容
2.1 所有的类的对象都是Class的实例
2.2 通过对象获得对应的包,类,以及类加载器
包:class.getClass().getPackage();
类:class.getClass().getName();
类加载器:class.getClass().getClassLoader();
2.3 获得java对象的三种方式(class代表需要实例的对象)
2.3.1 class = Class.forName("classpath");//反射
2.3.2 class = new class();
2.3.3 classname = classname.class;
2.4 反射得到对象代码示例
Class<?> cla = null;
Person per = null;
cla = Class.forName("personpath");//注意这里可能抛出ClassNotFoundException的异常
per = (Person)cla.newInstance();//注意这里可能抛出InstantiationException和IllegalAccessException异常
per.setName("jack");
在这里需要注意,当person中有一个有参的构造函数时,一定要保证这个类里面有一个无参的构造函数
class.froName调用的是无参的构造函数
2.5 通过反射的构造方法获得对象
Class<?> cla = null;
Person per = null;
cla = Class.forName("personpath");//注意这里可能抛出ClassNotFoundException的异常
这里反射处对象不同:
Constructor<?> cons[]=demo.getConstructors();
person = (Person)cons[i].newInstace();
person1 = (Person)cons[i].newInstace(arrayMap);
2.6 通过反射获得对象的实现接口
Class<?> cla = null;
cla = Class.forName("classpath");
Class<?> cls[] = cla.getInterfaces();//获得类继承的所有的接口
for(int i=0;i<cls.length;i++)
cls[i].getName();
2.7 通过反射获得对象的字段
Field[] fields = cla.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
int mod = field.getModifiers();
Class<?> types = field.getType();
System.out.println(Modifier.toString(mod)+" "+types.getName()+" "+field.getName());
}
2.8 通过反射调用方法
People people = (People)cla.newInstance();
Method method = cla.getMethod("setName", String.class);//获得setName方法,且setName的参数是String类型
method.invoke(people, "java ck");//调用people的setName方法,传递java ck参数到setName方法中
System.out.println(people);
2.9 通过反射来修改类的值域
try{
System.out.println("--------测试修改域的值----------");
Field fx = cla.getDeclaredField("age");
People people = (People)cla.newInstance();
System.out.println("修改前age值:"+fx.get(people));
fx.set(people, 20);
System.out.println("修改后age值:"+fx.get(people));
System.out.println(people.age);
}catch(Exception e){
e.printStackTrace();
}
三:在实际中哪里用到了java的反射
3.1 jdbc连接数据库
通过jdbc连接数据库的代码如下:
Class.forName("com.mysql.jdbc.Driver");
DriverManager.getConnection("jdbc:mysql://192.168.1.200:3306/test", "root", "root");
第一步生成一个mysql提供的Driver实例,因为Driver是实现了sql的DrvierManager接口,所以第二步其实是调用了通过反射得到的
mysql的Driver包连接数据库。
3.2 spring中的bean配置,也是通过java的反射实现的,这里有一个动态代理的概念,大家可以看spring的源码了解反射在spring中的
使用。
3.3 struts和hibernate中也同样的使用到了反射
四:反射同工厂模式结合
首先我们来看一个简单工厂(转载自 http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html)
在这个工厂中,通过字符串来生成不同的产品(如if("Apple".equals(fruitName)){ f=new Apple();}),这样做的不好之处就是违反了
开闭的原则,因为如果要是新增加一个产品,那么需要修改工厂类,添加一个新的判断生成产品的代码。
传入不同的类路径,再通过工厂的反射生成想要的产品,这样,即使新增加了产品,但只要在使用的时候传入新增加的产品类路径,同样
可以产生新增加的产品,这样就不用去修改工厂的具体实现,这样就符合了开闭的原则
五:反射的优缺点
5.1 反射的优点:
反射可以在运行期间创建实例
5.2 反射的缺点:
5.2.1 反射的效率比一般的低,一般是10~20倍,且java版本越低,反射的效率越低
5.2.2 反射的代码的可读性差,一般都不是很规范,大家可以参看前面的PeopleReflectDemon
在程序的运行时期,通过Class类的内部结构,并可实例化类,并修改值域,调用方法等。
二:反射包含的内容
2.1 所有的类的对象都是Class的实例
2.2 通过对象获得对应的包,类,以及类加载器
包:class.getClass().getPackage();
类:class.getClass().getName();
类加载器:class.getClass().getClassLoader();
2.3 获得java对象的三种方式(class代表需要实例的对象)
2.3.1 class = Class.forName("classpath");//反射
2.3.2 class = new class();
2.3.3 classname = classname.class;
2.4 反射得到对象代码示例
Class<?> cla = null;
Person per = null;
cla = Class.forName("personpath");//注意这里可能抛出ClassNotFoundException的异常
per = (Person)cla.newInstance();//注意这里可能抛出InstantiationException和IllegalAccessException异常
per.setName("jack");
在这里需要注意,当person中有一个有参的构造函数时,一定要保证这个类里面有一个无参的构造函数
class.froName调用的是无参的构造函数
2.5 通过反射的构造方法获得对象
Class<?> cla = null;
Person per = null;
cla = Class.forName("personpath");//注意这里可能抛出ClassNotFoundException的异常
这里反射处对象不同:
Constructor<?> cons[]=demo.getConstructors();
person = (Person)cons[i].newInstace();
person1 = (Person)cons[i].newInstace(arrayMap);
2.6 通过反射获得对象的实现接口
Class<?> cla = null;
cla = Class.forName("classpath");
Class<?> cls[] = cla.getInterfaces();//获得类继承的所有的接口
for(int i=0;i<cls.length;i++)
cls[i].getName();
2.7 通过反射获得对象的字段
Field[] fields = cla.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
int mod = field.getModifiers();
Class<?> types = field.getType();
System.out.println(Modifier.toString(mod)+" "+types.getName()+" "+field.getName());
}
2.8 通过反射调用方法
People people = (People)cla.newInstance();
Method method = cla.getMethod("setName", String.class);//获得setName方法,且setName的参数是String类型
method.invoke(people, "java ck");//调用people的setName方法,传递java ck参数到setName方法中
System.out.println(people);
2.9 通过反射来修改类的值域
try{
System.out.println("--------测试修改域的值----------");
Field fx = cla.getDeclaredField("age");
People people = (People)cla.newInstance();
System.out.println("修改前age值:"+fx.get(people));
fx.set(people, 20);
System.out.println("修改后age值:"+fx.get(people));
System.out.println(people.age);
}catch(Exception e){
e.printStackTrace();
}
2.10 实例代码参看PeopleReflectDemon和People类
接口China和English
public interface China {
public static final String name="Rollen";
public static int age=20;
public void sayChina();
public void sayHello(String name, int age);
}
public interface English {
}
People类
public class People implements China,English{
private int id;
private String name;
public static int age;
public final String address="1";
public People(){}
public People(String name){
this.name = name;
}
public People(int id,String name){
this.id = id;
this.name = name;
}
@Override
public void sayChina() {
System.out.println("说普通话");
}
@Override
public void sayHello(String name, int age) {
System.out.println(name+" "+age);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private int getCount(int a){
return 2;
}
public String getString(int a,String b){
return "abc";
}
public String toString(){
return "id:"+id+" name:"+name+" age:"+age;
}
}
PeopleReflectDemon类
public class PeopleReflectDemon {
static Class cla = null;
static{
try{
cla = Class.forName("flymoke.reflect.People");
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
public PeopleReflectDemon() throws Exception{
System.out.println("people类");
this.getExtends();
this.getInterface();
this.getConstructors();
this.getField();
this.getMethod();
this.getPeople();
this.invokMethods();
this.setFields();
}
public void getInterface(){
System.out.println("--------获得People的所有接口----------");
Class<?>[] inter = cla.getInterfaces();
for (int i = 0; i < inter.length; i++) {
System.out.println(inter[i].getName());
}
}
public void getExtends(){
System.out.println("--------获得People的所有父类----------");
Class<?> ext = cla.getSuperclass();
System.out.println(ext);
}
/**
* 获得People的构造方法
*/
public Constructor<?>[] getConstructors(){
System.out.println("--------获得People的所有构造方法----------");
Constructor<?>[] con = cla.getConstructors();
for (int i = 0; i < con.length; i++) {
System.out.println(con[i]);
}
return con;
}
public void getField(){
System.out.println("--------获得People的所有字段定义----------");
Field[] fields = cla.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
int mod = field.getModifiers();
Class<?> types = field.getType();
System.out.println(Modifier.toString(mod)+" "+types.getName()+" "+field.getName());
}
}
public Method[] getMethod(){
System.out.println("--------获得People的所有方法----------");
Method[] methods = cla.getDeclaredMethods();
StringBuffer methodDefine = new StringBuffer();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
int mod = method.getModifiers();
Class<?> returnType = method.getReturnType();
methodDefine.append(Modifier.toString(mod)+" "+returnType+" "+method.getName()+"(");
Class<?> para[]=methods[i].getParameterTypes();
for(int j=0;j<para.length;++j){
methodDefine.append(para[j].getName()+" "+"arg"+j);
if(j<para.length-1){
methodDefine.append(",");
}
}
methodDefine.append(");\n");
}
System.out.println(methodDefine.toString());
return methods;
}
public void getPeople() throws IllegalArgumentException, InvocationTargetException{
System.out.println("--------获得People----------");
try {
People p1 = (People) cla.newInstance();
System.out.println("p1"+p1);
//通过构造方法获得类
Constructor<?>[] con = this.getConstructors();
People p2 = (People) con[2].newInstance();
People p3 = (People) con[0].newInstance(1,"jack");
People p4 = (People) con[1].newInstance("jack");
System.out.println("p2:"+p2);
System.out.println("p3:"+p3);
System.out.println("p4:"+p4);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void invokMethods() throws Exception{
System.out.println("--------测试调用方法----------");
People people = (People)cla.newInstance();
Method method = cla.getMethod("setName", String.class);
method.invoke(people, "java ck");
System.out.println(people);
}
public void setFields(){
try{
System.out.println("--------测试修改域的值----------");
Field fx = cla.getDeclaredField("age");
People people = (People)cla.newInstance();
System.out.println("修改前age值:"+fx.get(people));
fx.set(people, 20);
System.out.println("修改后age值:"+fx.get(people));
System.out.println(people.age);
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
new PeopleReflectDemon();
}
}
三:在实际中哪里用到了java的反射
3.1 jdbc连接数据库
通过jdbc连接数据库的代码如下:
Class.forName("com.mysql.jdbc.Driver");
DriverManager.getConnection("jdbc:mysql://192.168.1.200:3306/test", "root", "root");
第一步生成一个mysql提供的Driver实例,因为Driver是实现了sql的DrvierManager接口,所以第二步其实是调用了通过反射得到的
mysql的Driver包连接数据库。
3.2 spring中的bean配置,也是通过java的反射实现的,这里有一个动态代理的概念,大家可以看spring的源码了解反射在spring中的
使用。
3.3 struts和hibernate中也同样的使用到了反射
四:反射同工厂模式结合
首先我们来看一个简单工厂(转载自 http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html)
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
// 构造工厂类
// 也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了
class Factory{
public static fruit getInstance(String fruitName){
fruit f=null;
if("Apple".equals(fruitName)){
f=new Apple();
}
if("Orange".equals(fruitName)){
f=new Orange();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("Orange");
f.eat();
}
}
在这个工厂中,通过字符串来生成不同的产品(如if("Apple".equals(fruitName)){ f=new Apple();}),这样做的不好之处就是违反了
开闭的原则,因为如果要是新增加一个产品,那么需要修改工厂类,添加一个新的判断生成产品的代码。
下面来看下使用发射后的工厂模式
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
class Factory{
public static fruit getInstance(String ClassName){
fruit f=null;
try{
f=(fruit)Class.forName(ClassName).newInstance();
}catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("Reflect.Apple");
if(f!=null){
f.eat();
}
}
}
传入不同的类路径,再通过工厂的反射生成想要的产品,这样,即使新增加了产品,但只要在使用的时候传入新增加的产品类路径,同样
可以产生新增加的产品,这样就不用去修改工厂的具体实现,这样就符合了开闭的原则
五:反射的优缺点
5.1 反射的优点:
反射可以在运行期间创建实例
5.2 反射的缺点:
5.2.1 反射的效率比一般的低,一般是10~20倍,且java版本越低,反射的效率越低
5.2.2 反射的代码的可读性差,一般都不是很规范,大家可以参看前面的PeopleReflectDemon