码迷,mamicode.com
首页 > 编程语言 > 详细

黑马程序员_java反射的简单使用

时间:2015-04-14 22:51:58      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:

反射概述:

一个已经写好的应用程序,后期要添加新功能,但一般无法获取该应用程序的源码,无法直接在该应用程序中用new创建对象,该怎么办?既然子类不确定,可以通过对外提供配置文件的形式,将不确定的信息存储到配置文件中即可。该应用程序需要在设计时写好如何读取配置文件信息?怎么做呢,先存储指定的子类名,根据具体的名称找该类并进行加载和对象的创建,这些动作都在前期定义软件时写好。
没有类之前就将创建对象的动作完成了。这就是动态的获取指定的类,并使用类中的功能,这就是反射技术。反射技术的出现大大的提高了程序的扩展性。提供什么类就可以使用什么类。
 

反射的使用:

/*
 *创建对象
 * 以前的做法:
 * Person p = new Person();
 * p.show();
 * 
 * 反射:其实就是通过class文件的内容去使用这个类本身的成员。
 * 成员:成员变量,构造方法,成员方法。
 * 反射其实就是说,我们通过字节码文件对象去使用类的成员变量,构造方法,成员方法。
 * 字节码文件对象是什么呢?
 *  张三,李四,王五,他们有共同的东西,所以,我们抽取出来了一个Person类。它们都是Person类的对象。
 *  在看看:
 *  Person.class,Student.class,Teacher.class
 *  把这些class文件的内容给抽取出来,最终形成了一个类:Class类。而这个类的对象就被成为字节码文件对象。
 * 我们如何获取到字节码文件对象呢?
 * A:通过Object类的getClass()方法。
 * Person p = new Person();
 * Class c = p.getClass();
 * B:数据类型的class静态数据。
 *              Class c3 = Person.class;
 * System.out.println(c == c3);
 * C:Class类的一个静态方法:
 *  forName(String className)
 *              Class c4 = Class.forName("cn.itcast_01.Person");
 * 
 * 开发为什么使用第三种呢?
 *  第三种方式可以通过配置文件提供路径。
 */
/*
 * 通过反射获取构造方法并使用。
 * 
 * 在反射里面,它已经把构造方法,成员变量,以及成员方法都封装成了对象。
 * 
 * Constructor:构造方法对象
 * Field:成员变量对象
 * Method:成员方法对象  
 * 
 * Person p = new Person();
 * System.out.println(p);
 * null---0
 */
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
 
// 获取构造方法 -- 所对应的对象
// Constructor[] cons = c.getConstructors(); // 所有公共构造方法
// Constructor[] cons = c.getDeclaredConstructors(); // 所有构造方法
// for (Constructor con : cons) {
// System.out.println(con);
// }
 
//如何获取单个的构造方法对象呢?
//public Constructor getConstructor(Class... parameterTypes)
//Class... 其实就是多个构造方法的形式。你传递几个参数,我对应得到的就是几个参数的构造器对象。
//传递的不是对应的数据类型,而是该类型对应的class文件对象。
Constructor con = c.getConstructor(); //无参构造方法
//System.out.println(con);
 
//public T newInstance(Object... initargs)
//返回的T其实就是根据该构造器创建的对象。
//Object... 其实就是实际的参数。
Object obj = con.newInstance(); //通过无参构造器对象创建对象。
 
System.out.println(obj); //null---0
}
}
/*
 * 通过反射获取成员变量并使用。
 * 
 * Person p = new Person();
 * p.name = "武鑫";
 * System.out.println(p);
 * 武鑫---0
 */
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
 
// 获取所有成员变量对象
// Field[] fields = c.getFields(); // 获取公共的成员变量
// Field[] fields = c.getDeclaredFields(); // 获取所有的成员变量
// for (Field field : fields) {
// System.out.println(field);
// }
 
// 通过无参构造方法创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
System.out.println(obj); // null---0
 
// 我们要获取一个
// Field nameFiled = c.getField("name"); // 通过字节码文件对象获取名称为name的成员变量对象
Field nameFiled = c.getDeclaredField("name"); // 通过字节码文件对象获取名称为name的成员变量对象
 
//如何是公共成员变量的获取,采用getField(),如果不是公共的,就要采用getDeclaredField()。
//如果获取到的成员变量对象是公共的,使用就直接用。如果不是公共的,不能直接用。这个时候,通过暴力反射。
nameFiled.setAccessible(true);
 
// obj.nameField = "武鑫";
// 如何实现这个效果呢?
// public void set(Object obj,Object value)
nameFiled.set(obj, "武鑫"); //给obj的nameFiled赋值为"武鑫"
 
System.out.println(obj); // 武鑫---0
 
 
//继续给age赋值
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj, 18);
System.out.println(obj); //武鑫---18
}
}
/*
 *反射获取成员方法
 * 反射的使用步骤:
 * 
 * 构造方法:获取字节码文件对象, 通过字节码文件对象获取构造器对象,通过构造器对象创建对象。
 * 
 * 成员变量:获取字节码文件对象,通过字节码文件对象获取成员变量对象,通过成员变量对象调用方法给对象赋值。
 * 
 * 成员方法:获取字节码文件对象,通过字节码文件对象获取成员方法对象,通过成员方法对象调用方法。
 * 通过反射获取成员方法并使用。
 */
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
 
// 获取成员方法
// Method[] methods = c.getMethods(); // 除了自己还有父类中的公共方法
// Method[] methods = c.getDeclaredMethods(); // 自己的所有方法
// for (Method method : methods) {
// System.out.println(method);
// }
 
// 创建一个对象
Constructor con = c.getConstructor();
Object obj = con.newInstance(); // 通过无参构造方法创建对象
 
// 使用方法
Method m1 = c.getMethod("show");
// obj.m1();
// public Object invoke(Object obj,Object... args)
// Object是返回值
// Object obj是调用该方法的对象
// Object... args 是该方法的实际参数
m1.invoke(obj); // 调用obj对象的m1方法
 
System.out.println("----------------------------");
// public void print(String name)
Method m2 = c.getMethod("print", String.class);
m2.invoke(obj, "haha");
 
System.out.println("----------------------------");
// public String getString()
Method m3 = c.getMethod("getString");
Object o = m3.invoke(obj);
System.out.println(o);
 
System.out.println("----------------------------");
// public String returnString(String name, int age)
Method m4 = c.getMethod("returnString", String.class, int.class);
Object oo = m4.invoke(obj, "hello", 100);
System.out.println(oo);
 
System.out.println("----------------------------");
//private void function()
Method m5 = c.getDeclaredMethod("function");
m5.setAccessible(true);
m5.invoke(obj);
}
}
用反射方式执行某个类中的main方法
普通调用方式
TestArguments.main(new String[]("11","22","33"));
用反射的方式
Object[] 与String[]没有父子关系,Object与String有父子关系,所以new Object[]{“aaa”,”bb”}不能强制转
 
换成new String[]{“aaa”,”bb”};,Object x = “abc”能强制转换成String x = “abc”。
main.invoke(null, (Object)(new Object[]{“aaa”,“xxx”}));
不能调用public static void main(String [] args)
 
StartingClassName =args[0];
MeThod mainMethod=Class.forName(startingClassName).getMethod("main",String[].class);
mainMathod.invoke(null,new Object[](new String[]{"11","22","33"}));
//简化形式
mainMathod.invoke(null,(Object)new String[]{"11","22","33"});
 
 
 
class TestArguments{
publics static void main(String[] args){
for(String arg:args){
System.out.println(arg);
}
}
}
-----------------------------------------------------------------------------------
1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。
String[] a1 = new String[8];
String[] a2 = new String[9];
System.out.println(a1.getClass() == a2.getClass());//true
 
String[][] a3 = new String[6][4];
System.out.println(a1.getClass() == a3.getClass());//编译报错
 
2、代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
System.out.println(a1.getClass().getSuperclass().getName());
 
3、基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以
 
当做Object类型使用,又可以当做Object[]类型使用。
 
4、Arrays.asList()方法处理int[]和String[]时的差异。
int[] a = new int[3];
Object obj = a;
//Object[] obj1 = a //有错!
Object[] obj3 = a1
Object obj4 = a3;
if(obj4 instanceof String[][]){
System.out.println(obj1.getClass().isArray());
}
**在这里分析研究Arrays.asList()方法处理int[]和String[]时的差异,以及Arrays.deepToString()方法不能处理
 
int[],但能处理String[]的原因。
 
5、Array工具类用于完成对数组的反射操作。
private static void printObject(Object obj) {
if(obj.getClass().isArray()){
int len = Array.getLength(obj);
for(int i=0;i<len;i++) {
System.out.println(Array.get(obj, i));
}
} else {
System.out.println(obj);
}
}
 
6、怎么得到数组中的元素类型?
需要取出每个元素对象,然后再对各个对象进行判断,因为其中每个具体元素的类型都可以不同,例如Object[] x 
 
= new Object[]{“abc”,Integer.Max}。
 
Object[] a=new Object[]{"a",1};
a[0].getClass().getName();
综合案例:反射在框架中的应用
/*
先直接用new  语句创建ArrayList和HashSet的实例对象,演示用eclipse自动生成ReflectPoint类的equals和hashcode方法,比较两个集合的运行结果差异。
然后改为采用配置文件加反射的方式创建ArrayList和HashSet的实例对象,比较观察运行结果差异。
*/

public static void main(String[] args) throws Exception{

//应该先直接用ArrayList和HashSet,然后才引入从配置文件读,这样便于学员学习。

Properties props = new Properties();

//先演示相对路径的问题

//InputStream ips = new FileInputStream("config.properties");

/*一个类加载器能加载.class文件,那它当然也能加载classpath环境下的其他文件,既然它有如此能力,它没有理由不顺带提供这样一个方法。它也只能加载classpath环境下的那些文件。注意:直接使用类加载器时,不能以/打头。*/

//InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/javaenhance/config.properties");

//Class提供了一个便利方法,用加载当前类的那个类加载器去加载相同包目录下的文件

//InputStream ips = ReflectTest2.class.getResourceAsStream("config.properties");

InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/javaenhance/config.properties");

props.load(ips);

Ips.close();

 

String className = props.getProperty("className");

Class clazz = Class.forName(className);

 

Collection collection = (Collection)clazz.newInstance();

//Collection collection = new ArrayList();

ReflectPoint pt1 = new ReflectPoint(3,3);

ReflectPoint pt2 = new ReflectPoint(5,5);

ReflectPoint pt3 = new ReflectPoint(3,3);

collection.add(pt1);

collection.add(pt2);

collection.add(pt3);

collection.add(pt1);

System.out.println(collection.size());

}

黑马程序员_java反射的简单使用

标签:

原文地址:http://www.cnblogs.com/shujin/p/4426240.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!