转载

JAVA 反射机制....

PS:最近数据库算是学完了,总算是有时间回头复习一下以前学的东西了...最近这几天好好复习了一下反射机制,顺便也做个总结...JAVA的学习基本都没有去写...慢慢补上吧...

学习内容:

1.反射机制的概念...

2.反射机制的作用...

3.如何去使用反射机制...

4.反射机制的优势...

1.反射机制:

反射机制,想必大家都不陌生,但是估计大家也就是知道个概念...那么到底什么是反射机制,估计大家对这个概念有点模糊不清...简单的概念就是:对于我们定义的每一个类,在任何的时刻,我们都能够知道这个类里面的属性和方法...对于任何一个对象,都能够调用这个类中的方法...这就是反射机制的基本概念..

2.反射机制实现的功能:

在运行时判断任意一个对象所属的类,在运行时构造任意一个类的对象,在运行时判断任意类所具有的方法和属性,在运行时调用任意一个对象的方法

生成动态代理...

3.如何使用反射机制:

我们如何去使用反射机制呢?

反射机制里一个特点就是实例化class对象,因为任意一个类对象都是class的实例...那么如何实例化class对象呢?三种方法:

i.通过forname()方法...

ii.对象.getclass();

iii.类.class;

在程序运行时通过实例化的对象,然后对象使用反射来调用类内的方法或者是属性...这样就实现了动态的获取信息...

package Fanshe; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Scanner; class person{  private String name;  private String sex;  private int age;  person(){  }  public person(String name,String sex,int age){   super();   this.name=name;   this.sex=sex;   this.age=age;  }  private void setname(String name){   this.name=name;  }  public String getsex(){   return sex;  }  public void setsex(String sex){   this.sex=sex;  }  public int getage(){   return age;  }  public void setage(){   this.age=age;  }  public String toString(){   return "姓名 :"+name+"年龄: "+age;  } } class reflectdemo{    reflectdemo(){    Scanner cin=new Scanner(System.in);    String classpath=cin.nextLine();//需要输入类的完整路径...我的路径是Fanshe.person    try {       //三种方式实现对象的实例化    Class cla=Class.forName(classpath); //   Class cla_1=person.class; //   person p=new person(); //   Class cla_2=p.getClass();    Method [] method=cla.getDeclaredMethods();//定义一个数组来保存类中所有的方法...    System.out.println("=====类中的方法有=====");    for(Method meth:method){     System.out.println(meth.toString());    }    System.out.println("=====方法获取结束=====");    Field [] field=cla.getDeclaredFields(); //保存类中所有属性    System.out.println("=====类中内部的属性=====");    for(Field fie:field){     System.out.println(fie.toString());    }    System.out.println("=====属性获取结束=====");    Constructor [] con=cla.getDeclaredConstructors();//类中所有的构造函数...    System.out.println("=====获取构造函数=====");    for(Constructor c:con){     System.out.println(c.toString());    }   } catch (Exception e) {    // TODO Auto-generated catch block    e.printStackTrace();    System.out.println("路径输入错误");   }    } } public class fanshe_2 {  public static void main(String[] args) {   // TODO Auto-generated method stub   reflectdemo ref=new reflectdemo();  } } 

上述代码通过使用反射机制来获取类中的方法和属性...反射这东西我还是用代码说话更好一些,所以我还是都使用代码来让大家理解的更深刻一些...

package Fanshe_cll; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.annotation.Annotation;   class reflectdemo{  //私有构造函数  private reflectdemo(String name,int age){  }  reflectdemo(){  }  //公有构造函数  public reflectdemo(String name){  }  public void info(){  } public void info(String str){  } private void set(){ }  class inner{  }//内部类... } import Fanshe_cll.reflectdemo.inner; public class clear1 {  public static void main(String[] args) throws Exception {   // TODO Auto-generated method stub   reflectdemo r=new reflectdemo();   Class claz_1=r.getClass();   System.out.println(claz_1.toString());   Class<reflectdemo> cla=reflectdemo.class;  //使用泛型,用class来实例化对象..   System.out.println(cla.toString());   Class claz=Class.forName("Fanshe_cll.reflectdemo");   System.out.println(claz.toString());   System.out.println("=====类中的构造函数=====");   //获取全部的构造函数....   Constructor []constructor=cla.getDeclaredConstructors();//返回类中所有的构造函数,无论是公有的还是私有的...并且这个保存是按照倒序保存的..
就是constructor[0]保存的是最后一个构造函数...而constructor[length-1]保存的是第一个构造函数...比如说我们有一个person类,类中有四个构造方法...
public Person(){}
public Person(String name){this.name=name;}
public Person(int age){this.age=age;}
public Person(String name,int age){this.age=age;this.name=name;}
我们在主函数来调用这几种方法...
Class<?> cla=Person.class;
Constructor []con=cla.getDeclaredConstructors();
Person per_1=(Person) con[0].newInstance("剑神",20);
Person per_2=(Person) con[1].newInstance(20);
Person per_3=(Person) con[2].newInstance("剑圣");
Person per_4=(Person) con[3].newInstance(); 必须这样传参才行,如果把他们倒过来,那么必定会出现java.lang.illegalArgumentException非法参数异常..
for(Constructor con:constructor){ System.out.println(con.toString()); } System.out.println("公有构造函数"); //获取公有的构造函数.... Constructor []constructor_1=cla.getConstructors();//这个就和上面不同了,这个保存着类中所有的公有构造函数 for(Constructor con_1:constructor_1){ System.out.println(con_1.toString()); } System.out.println("获取全部方法"); //获取全部的方法.... Method [] method =cla.getDeclaredMethods(); for(Method meth:method){ System.out.println(meth.toString()); } //获取公有的方法.... System.out.println("获取公有方法"); Method [] method_1=cla.getMethods(); for(Method meth_1:method_1){ System.out.println(meth_1.toString());//这个输出异常处理的函数..这说明有些方法是带有异常的... } //获取指定的某个方法.... System.out.println("获取某个指定的方法"); Method method_2=cla.getMethod("info",null);//获取参数为空的info方法.. System.out.println(method_2.toString()); Method method_3=cla.getMethod("info", String.class);//获取指定参数为字符串的方法... System.out.println(method_3.toString()); // Method method_4=cla.getMethod("info", reflectdemo.class); System.out.println("-----------------"); // System.out.println(method_4.toString()); System.out.println("-----------------"); //获取注释 System.out.println("获取注释"); Annotation []annotations =cla.getAnnotations(); for(Annotation ant:annotations){ System.out.println(ant.toString()); } //获取包信息 System.out.println("获取包信息"); Package package_1=cla.getPackage(); System.out.println(package_1.toString()); //获取内部类 System.out.println("获取内部类"); Class [] cla_1=cla.getDeclaredClasses(); for(Class clazz : cla_1){ System.out.println(clazz.toString()); } //调用父类 System.out.println("调用父类"); Class cla_2=cla.getSuperclass(); System.out.println(cla_2.toString()); //内部类对象... Class cla_3=Class.forName("Fanshe_cll.reflectdemo$inner"); // Class cla_4=inner.class; //获取内部类的外部类 System.out.println("使用内部类来获取外部类信息"); System.out.println(cla_3.getDeclaringClass()); System.out.println("--------------"); System.out.println(cla_3.getPackage()); System.out.println(cla_3.getSuperclass()); } }

我们上面只是返回类中的方法...基本没有进行调用,那么下面就对上面的那些方法进行调用...

package Fanshe_c; import java.lang.reflect.Method; class person{   //这个类大家基本不用看,是一个很普通的类,之所以粘出来是因为自己定义了好几个person类,怕产生混淆....  private String name;  private String sex;  private int age;  person(){  }  public person(String name,String sex,int age){   super();   this.name=name;   this.sex=sex;   this.age=age;  }  public void setname(String name){   this.name=name;  }  public String getname(){   return name;  }  public String getsex(){   return sex;  }  public void setsex(String sex){   this.sex=sex;  }  public int getage(){   return age;  }  public void setage(int age){   this.age=age;  }  public String toString(){   return "姓名 :"+name+"年龄: "+age;  } } public class cll_2 {  public static void main(String[] args) throws Exception{   // TODO Auto-generated method stub   Class cla=person.class;   person p=new person();//定义一个对象..使用new关键字..   Method method=cla.getMethod("setname",String.class);   method.invoke(p, "剑神");//这句话还可以写成 method.invoke(cla.newInstance(),"剑神");下面凡是和这句话类似的都可以使用这种方法,使用newInstance()的默认构造函数去实例化一个对象..   Method method_1=cla.getMethod("setage",int.class);   method_1.invoke(p, 20);   Method method_2=cla.getMethod("setsex", String.class);   method_2.invoke(p, "男");   //调用输出方法...   Method method_3=cla.getMethod("getname", null);   System.out.println((method_3.invoke(p, null)).toString());   Method method_4=cla.getMethod("getsex", null);   System.out.println((method_4.invoke(p,null)).toString());   Method method_5=cla.getMethod("getage", null);   System.out.println((method_5.invoke(p, null)).toString());  } } 

通过上面的代码,大家难免会产生一个疑问,就是使用new和newInstance去创建对象到底有什么区别呢??这个我也在这里进行下解释...

new与newInstance()的区别

首先一个是关键字,一个是方法...new是一个关键字,使用关键字来新建一个对象的时候没有过多的限制...而newInstance()是一个方法,使用newInstance()创建对象的时候,类一定要有一个默认的无参构造方法...并且这个类必须要被加载,否则的话JVM首先会将这个类进行加载后,然后我们才能使用newInstance()来新建一个对象...那么大家就会问了,那给出两个创建对象的方法,是不是有点多此一举了呢?这个当然是否定的...使用newInstance()...其实在一定情况下是很有好处的...大家来看:

Class c = Class.forName("darker"); factory = (AInterface)c.newInstance(); 其中AInterface是darker的接口,在看下面 String className = "darker"; Class c = Class.forName(className); factory = (AInterface)c.newInstance(); 进一步的进行扩展... String className = readfromXMlConfig;//从xml 配置文件中获得字符串 Class c = Class.forName(className); factory = (AInterface)c.newInstance(); 上面代码把类名darker彻底的去掉了,这个优点估计大家都看出来了,这样当我们的darker类做怎样的修该,我们这句话永远保持不变...如果使用new就没办法了吧??             

这就是newInstance()在一定的地方使用的好处...

简单的介绍一下setAccessible()函数...

package Fanshe_fuzhi; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.util.Calendar; class Person {   //这个代码目的是为了简单的介绍一下setAccessible()函数。。  private String name;  private String gender;  private int age;  public String getName() {   return name;  }  public void setName(String name) {   this.name = name;  }  public String getGender() {   return gender;  }  public void setGender(String gender) {   this.gender = gender;  }  public int getAge() {   return age;  }  public void setAge(int age) {   this.age = age;  }  public String getSay(){   return"姓名:"+this.name+" /t性别:"+this.gender+"/t年龄:"+this.age;  } } public class Fanshe_quanxian {  public static void main(String[] args) throws Exception{   // TODO Auto-generated method stub   Class<?> cla=Person.class;   Field name=cla.getDeclaredField("name");   System.out.println(name);   name.setAccessible(true);   //这个函数的参数是boolean类型,当值为true的时候,那么JVM将忽略访问时的权限...如果为false,那么就不进行忽略...   name.set(cla.newInstance(),"三丰");   Field gender=cla.getDeclaredField("gender");   gender.setAccessible(true);   gender.set(cla.newInstance(),"重阳");   Field age=cla.getDeclaredField("age");   age.setAccessible(true);   age.setInt(cla.newInstance(), 20);   Method getsay=cla.getMethod("getSay");   Object obj=getsay.invoke(cla.newInstance());   System.out.println(obj.toString());  } } 

Modifyers函数...很简单,没什么东西...

package Fanshe_modifier; import Fanshe_Person.Person; import java.lang.reflect.Field; import java.lang.reflect.Modifier; public class Modify {  public static void main(String[] args) {   // TODO Auto-generated method stub   Class<?> cla = Person.class;   Field[] field = cla.getDeclaredFields();   for (int i = 0; i < field.length; i++) {    int mo = field[i].getModifiers();    System.out.println(mo);    String priv = Modifier.toString(mo);    System.out.println(priv);    Class<?> type =field[i].getType();    System.out.println(type.getName());    System.out.println(field[i].getName());    /*     * 直接toString就可以返回方法的名字...     * field[i].toString     * */   }  } } 

动态创建和访问数组...

package Array; import java.lang.reflect.Array; public class Array_1 {      public static void main(String[] args) {         // TODO Auto-generated method stub         Object obj=Array.newInstance(int.class,3);         /*          *一维数组的创建与赋值..          */         Array.set(obj, 0, 20);         Array.set(obj, 1, 30);         int obj_1=Array.getLength(obj);         System.out.println(obj_1);         Object obj_2=Array.get(obj, 0);         System.out.println(obj_2);         Array.set(obj, 2, 40);         int obj_3=Array.getLength(obj);         System.out.println(obj_3);           Object two_arr=Array.newInstance(int.class, 10,10);         /*          * 二维数组的赋值:先找到第一维的下标值..然后再传参..          * */         Object firstindex=Array.get(two_arr, 0);         Array.set(firstindex, 0, 20);              }  }

动态修改数组的大小...

package Array; import java.lang.reflect.Array; public class Array_xiugailength {  public static void main(String[] args) {   // TODO Auto-generated method stub   int temp[]={0,1,2,3,4,5,6,7,8,9};   int newtemp[]=(int [])arrayinc(temp,15);   for(int i=0;i<newtemp.length;i++){    System.out.println(newtemp[i]);   }  }  public static Object arrayinc(Object obj,int len){   Class<?>arr=obj.getClass().getComponentType();   Object newArr=Array.newInstance(arr, len);   return newArr;  } } 

4.反射机制的应用场合:

大家不禁会这样问,什么时候能够使用到反射机制呢,并且它的应用场合是什么...并且它的优势到底在哪里呢?

package Fanshefactory; interface factory_1{  public abstract void show(); } class A implements factory_1{  public void show(){   System.out.println("A");  } } class B implements factory_1{  public void show(){   System.out.println("B");  } } /*  * 当增添类去实现接口的时候,我们就需要改变factory,当我们添加的类过多的时候  * 我们的修改量就会很大...可以使用反射进行解决...  * */ class Factory{  public static factory_1 getInstance(String fname){   factory_1 f=null;   if("A".equals(fname)){    f=new A();   }   if("B".equals(fname)){    f=new B();   }   return f;  } } public class Fanshe_factory_1 {  public static void main(String[] args) {   // TODO Auto-generated method stub   factory_1 f=Factory.getInstance("A");   f.show();  } } package Fanshe_factory1; interface factory_2{  public abstract void show(); } class AA implements factory_2{  public void show(){   System.out.println("A");  } } class BB implements factory_2{  public void show(){   System.out.println("B");  } }  class Factory_1{  public static factory_2 getInstance(String fname){     factory_2 f=null;     try {    Class cla=Class.forName(fname);    f=(factory_2)cla.newInstance();   } catch (Exception e) {    // TODO Auto-generated catch block    e.printStackTrace();   }     return f;  } } public class Fanshe_factory_2 {  public static void main(String[] args) throws Exception{   // TODO Auto-generated method stub   factory_2 f=Factory_1.getInstance("Fanshe_factory1.AA");     if(f!=null){      f.show();     }  } } 

这两个代码形成对比,一个是未使用反射机制的工厂模式,一个是使用了反射机制的工厂模式...估计大家看完没什么过多的感觉...但是这里比如说我们要添加更多的类去实现我们暴露出的接口,那么我们Factory类里的判断部分也要进行大量的修改...这么做会代码冗余...那么用了反射的我们就没必要进行修改了,因为我们是使用class实例化的对象,class是字节码文件,无论类如何变,这个字节码文件只有一个,那么这样就可以直接实例化对象....我们没必要进行一个一个判断了....这就是反射的优势,在一定程度上解决代码冗余,并且可以动态的去获取类的信息...这样我们就感觉java就像动态语言一样..因此反射机制是很强大的一个东西...

正文到此结束
Loading...