反射之二
生成对象
一般可以用new关键字来创建我们想要的对象。但在特殊情况下,可能只有在程序运行时才知道要常见的对象
所对应的类名称,这时就需要java反射了,分两种情况来讨论用反射创建对象的方式。
1.用无参构造方法
调用这个类对应的Class对象的newInstance()方法:
Class c=Class.forName(“java.util.ArrayList”);
List list=(List)c.newInstance();
说明:若指定名称的类没有无参构造方法,在调用newInstance()方法是会抛出会抛出一个NoSuchMethodException
异常。
import java.util.Date; /*使用反射调用无参构造方法创建指定名称类的对象*/ public class NoArgsCreateInstanceTest{ public static void main(String[] args) { Date currentDate=(Date)newInstance("java.util.Date"); System.out.println(currentDate); } public static Object newInstance(String className){ Object obj=null; try{ /*加载指定名称的类并获取对应的Class对象, 再调用无参构造方法创建出一个对象*/ obj=Class.forName(className).newInstance(); }catch (InstantiationException e) { e.printStackTrace(); }catch (IllegalAccessException e) { e.printStackTrace(); }catch (ClassNotFoundException e) { e.printStackTrace(); } return obj; } }
2.用带参构造方法
获取名称的类对应的Class对象(Class a 中的类,而a本身就是一个类),然后通过反射获取指定的参数类型的要求的构造方法信息类对象,
调用它的newInstance方法来创建对象。
具体分三步:
1)获取指定类的Class对象 (获得类的对象)
2)通过Class对象获取满足指定参数类型要求的构造方法类对象 (通过类的对象获得对象的构造器)
3)调用指定Constructor对象的newInstance方法传入对应的参数值,创建出对象。(再通过类的构造器中的值的集合来获取整个对象的相关的信息)
//创建对象的示例: import java.lang.reflect.Constructor; import java.lang.reflect.IncocationTargetException; import java.util.Date; /**用反射对指定的带参数的构造方法创建指定类的对象*/ import java.lang.reflect.Constructor; import java.lang.reflect.IncocationTargetException; import java.util.Date; /**用反射对指定的带参数的构造方法创建指定类的对象*/ public class ArgsCreateIntanceTest{ @SuppressWarnings("unchecked") public static void main(String[] args) { try{ //1.加载指定名称的类,获取对应的Class对象 Class clazz=Class.forName("java.util.Date"); //2.获取具有指定参数的构造方法 Constructor constructor=clazz.getConstructor(long.class); //3.给指定的构造方法传入参数值,创建出一个对象 Date date=(Date)constructor.newInstance(1234567890L); System.out.println(date); }catch (ClassNoFoundException e) { e.printStackTrace(); }catch(SecurityException e){ e.printStackTrace(); }catch (NoSuchMethodException e) { e.printStackTrace(); }catch (IllegalArgumentException e) { //此异常表明向方法传递了一个不合法或不正确的参数或JDK版本不兼容。 e.pringStackTrace(); }catch (InstantiationException e) { //不在类的加载的时候,所以就会报这样的错误。 e.printStackTrace(); }catch(IllegalAccessException e){ e.printStackTrace(); }catch(InvocationTatgetException e){ //一种包装由调用方法或构造方法所抛出异常的受查异常 e.printStackTrace(); } } }
调用方法
用反射可以取得指定类中指定方法对象代表,方法对象代表就是java.lang.reflect.lang类的实例,通过Method类的
invoke()方法可以动态调用这个方法。
method类的invoke()方法完整签名是:
public Object invoke(Object obj, object…args)
throws IllegaAccessException , IllegalArgumentException,InvocationTargetException
//invoke()的返回值代表的是指动态地调用指定方法后实际返回值
说明:若要通过反射调用类的某个私有方法,可以在这个私有方法对应的Method对象上,先调用setAccessible(true)
来取消java对于本方法的访问检查,然后再调用invoke()方法来真正执行这个私有方法。(方法调用方法,前一个方法
是对象,后一个方法是具体的方法,方法(Method对象)的方法(invoke方法)去调用方法对象);
iimport java.lang.reflect.InvocationTargetException;
import java.lang.reflect.menthod;
/*用反射来动态地调用指定类的指定方法*/ @SuppressWarnings("unchecked") public class ReflectInvokeMethodTest{ public static void main(String[] args) { try{ Class clazz=Clazz.forName("com.qiujy."); //利用无参构造函数创建一个Product的对象?? ??? Product prod=(Product)clazz.newInstance(); //获取名为setName,带一个类型为String的成员方法所对应的对象代表 Method menthod1=clazz.getDeclaredMethod("setName",String.class); //在prod对象上调用setName,并传值给它,返回值为空 Object returnValue=method1.invoke(prod,"哇"); System.out.println("返回值:"+returnValue); //获取名为displayInfo,不带参数的成员方法所对应的对象代表 Method method2=clazz.getDeclaredMethod("displayInfo"); method2.setAccessible(true); //取消访问调查??setAccessible不是意思为可接近的,可理解的吗?true不是表示真的意思吗? //在prod对象上的勇士以的displayInfo方法 method2.invoke(prod); }catch (ClassNoFoundException e) { e.printStackTrace(); }catch(SecurityException e){ e.printStackTrace(); }catch (NoSuchMethodException e) { e.printStackTrace(); }catch (IllegalArgumentException e) { e.pringStackTrace(); }catch (InstantiationException e) { e.printStackTrace(); }catch(IllegalAccessException e){ e.printStackTrace(); }catch(InvocationTatgetException e){ e.printStackTrace(); } } } class Product{ private static long count=0; private long id; private String name="无名氏"; public Product(){ System.out.println("默认构造方法"); id=++count(); } public long getId(){ return id; } public void setId(long id){ this.id=id; } public String getName(){ return name; } private void displayInfo(){//私有方法 System.out.println(getClass().getName+"[id="+id+",name="+name+"]"); } }
感觉反射的思维,比较跳跃,自己就是对象,任何东西都是对象,都可以调用其它的东西,其实很多东西,都是按照规则编排出来的,而至于那个东西本身其实不重要,重要的是原理和应用,
就像是椅子,第一个人把椅子命名为椅子所以它就叫椅子,它也可以叫其它,但是它的作用和性质包括原理,不会随着这个名称的改变而改变,这个概念还有应用好像有些哲学;
理解了还要多练习;不然还是不能融会贯通,不能应用;
更基础的可以参看自己的“反射之一”博客;
什么是类类型?