用反射方式执行某个类中的main方法
写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。用普通方式调用后,为什么要用反射的方式去调用?
//反射方式调用ReflectPoint类中的额main方法
Method method =
ReflectPoint.class.getMethod("main", Object[].class);
//传入的字符串数组参数封装成一个Object
method.invoke(null,
new Object[]{new String[]{"ffff","1111","2222"}});
//传入的字符串数组参数封装成一个Object
method.invoke(null,
(Object)new String[]{"ffff","1111","2222"});
数组反射
int[] a = new int[]{1,2,3,4};
reflectArray(a);
reflectArray("fdsfdsfd");
private static void reflectArray(Object a) {
Class array = a.getClass();
if(array.isArray()){
int len = Array.getLength(a);
for(int i = 0 ;i<len;i++){
System.out.println(Array.get(a, i));
}
}else{
System.out.println(a);
}
}
在执行reflectArray(a)的时候有这样一个过程,由于目标方法接收的是一Object类型的参数,而传入的是一个int类型的数组,此时存在一个装箱的过程,现将int[]的数组封装成Object类型的对象,new Object[]{new int[]{1,2,3,4}}等价于new Object[]{a},此处的a为int数组类型的对象。这个动作是编译器执行的。为什么会执行这个动作 ?在调用方法的时候传入的是一个int数组,而形参接收的是一个Object对象,而在java中每一个Array都是一个Object对象。
用类加载器的方式管理资源和配置文件
加载资源的时候总是有路径的问题出现:
绝对路径和相对路径
对于java中类加载器有两种方式,
绝对路径加载实现config.properties
ClassName.class.getClassLoad().getResourceAsStream(文件的绝对路径);此处文件的绝对路径是相对于ClassName这个类来说的 ,如果你的ClassName存放在com.reflect下面,那么绝对路径为:com/reflect/config.properties同时要保证该目录下面有config.properties这个配置文件存在。
例如:InputStreaminput = ClassLoadDemo.class.getClassLoader().getResourceAsStream(
"com/reflect/demo/config.properties");
相对路径加载config.properties
ClassName.class.getResourceAsStream(“文件的相对路径”);此处文件的绝对路径是相对于ClassName这个类来说的 ,如果你的ClassName存放在com.reflect下面,那么绝对路径为:config.properties同时要保证该目录下面有config.properties这个配置文件存在。
例如:InputStream input =ClassLoadDemo.class.getResourceAsStream("config.properties");
有内省引出的JavaBean
JavaBean的概念
IntroSpectoràJavaBeanà特殊的Java类。主要是对JavaBean进行操作 。javaBean是一个特殊的java类。有一些约定规则的java类。
一个javabean可以当作一个java类来操作 ,但是一个java类不一定能当作javabean来操作。
PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。
PropertyDescriptorpd = new PropertyDescriptor(String propertyName,Class beanClass);
该类中有以下两个方法:
MethodgetReadMethod() 获得应该用于读取属性值的方法。
Method getWriteMethod() 获得应该用于写入属性值的方法。
例:
//内省操作javaBean,获取成员X的值
PropertyDescriptor dp1 = new PropertyDescriptor("x", rp.getClass());
Method methodGetX = dp1.getReadMethod();
Object x = methodGetX.invoke(rp);
System.out.println("x="+x);
//内省操作javaBean,设置成员x的值
Method methodSetX = dp1.getWriteMethod();
methodSetX.invoke(rp, 1);
System.out.println(rp.getX());
使用BeanUtils工具包操作JavaBean
BeanUtils是第三方提供的工具包,它可以很方便的操作javaBean。
例:
//使用BeanUtils获取属性值
System.out.println(BeanUtils.getProperty(rp,"x"));
//使用BeanUtils设置值并打印出来
BeanUtils.setProperty(rp, "x", 1000);
System.out.println(BeanUtils.getProperty(rp,"x"));
java5的泛型
泛型中的参数信息是给编译器看的
Collection<String>collection = new ArrayList<String>();
"text");
"add", Object.class).invoke(collection,123);
System.out.println(collection);
在实例化容器collection的时候指定容器中装入的对象的类型是String型的,也就是说向容器中添加非String类型的数据的时候编译器在变异阶段的额时候就会报错 ,如编译此举代码的时候就会报错collection.add(123);但是通过反射技术在将文件编译成class文件的字节码的时候添加则可以顺利的通过。由此可以证明,泛型是在编译阶段,在声称字节码文件的时候会被擦除。
泛型中的术语:
整个成为ArrayList<E>泛型类
ArrayList<E>中的E成为类型变量或类型参数
ArrayList<Integer>中的Integer成为类型参数的实际类型参数
ArrayList<Integer>中的<>念typeof
ArrayList成为原是类型
3、泛型中的?通配符
?表示任意类型
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用任何与参数化无关的方法,不能调用与参数化有关的方法。
例:
public void genericMethod(Collection<?> collection){
//能通过编译和正确执行
//collection.add("fsdfds");//不能通过编译,添加元素的类型与参数化类型有关系
}
限定通配符的上边界
Vector<? extends Number> x = newVector<Integet>();
限定通配符的下边界
Vector<? super Integer> x = newVector<Number>()
泛型应用示例:
public static void main(String[] args) throws Exception {
Map<String, Integer> maps = new HashMap<String, Integer>();
maps.put("zhangsan", 30);
maps.put("lisi", 10);
maps.put("wangwu", 10);
Set<Map.Entry<String, Integer>> entrySet = maps.entrySet();
Iterator<Entry<String, Integer>> it = entrySet.iterator();
while (it.hasNext()) {
String key = it.next().getKey();
Integer keyVal = maps.get(key);
System.out.println(key + "::" + keyVal);
}
}
自定义泛型:如果一个类中的多个方法需要使用泛型,那么此泛型定义为类级别的泛型 。
静态方法不能使用类级别的泛型,因为,类级别的泛型是在对象建立之后确定哪个对象的泛型,而静态方法是不依赖于对象的就可以使用的,在泛型对象没有确定之前就使用这是错误的。
如果静态方法要使用泛型,那么必须给静态方法定义一个泛型。就像这样:
Public static <E> void method(E obj){}
通过反射技术获取泛型方法中参数的实际类型:(难)
public class Test extends Thread{
public static void main(String[] args) throws Exception {
/*
*思路:
*首先获取到方法的名,然后通过ParameterizedType获取方法参数的类型和获取泛型的真实类型
* */
Method method = Test.class.getDeclaredMethod("applyGeneric", Vector.class);
Type[] type = method.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType)type[0];
System.out.println(pType.getActualTypeArguments()[0]);
System.out.println(pType.getRawType());
}
public static <E> void applyGeneric(Vector<Date> v){
}
}