反射就是把Java类中各种成分,映射成相应的java类。
关键字:Class 代表一类事物。点击打开链接 点击打开链接 点击打开链接 点击打开链接 点击打开链接
getName();getPackage(); getMethod() getInterfaces() .....
语法:Class cls1 = 字节码;
三种方式得到字节码:
(1)类名.class 例如 System.class
(2)对象.getClass 例如 new Date().getClass
(3)Class.forName("类名") ; 例子 Class.forName(" java.util.Date");
九个预定义对象: 八个基本类型+ void
方法:isPrimitive()来判断是否是基本类型。
int.class ==Integer.TYPE true
数组类型Class实例对象 isArray()判断是否是数组。
在源程序中出现的类型都有各自的Class实例对象,例如 int[ ] ...
Filed, Method,constructor package
constructor 代表某个类中的一个构造方法
getConstructors 得到所有的构造方法
getConstructor 得到一个构造方法
例子:
Constructor constructors[ ] = ClassforName("java.lang.String").getConstructors();
Constructor constructor = ClassforName("java.lang.String").getConstructor(StringBuffer.class);
简单的描述来区分new关键字和newInstance()方法的区别:
newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。
创建实例对象:
通常方式:
String str = new String (new StringBuffer("abc"));
反射方式:
String str = (String)constructor.newInstance(new StringBuffer("abc"));
(1) //先获得构造方法
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
//注意类型的强转
(2) String str2 =(String) constructor1.newInstance(new StringBuffer("abc"));
调用获得的方法时,要用到上面相同类型的实例对象。
Class.newInstance()方法
例子:
String obj = (String) Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造函数,然后用该构造方法创建实例对象。
package cn.itcast.day1;
publicclass ReflectPoint {
privateintx;
publicinty;
public ReflectPoint(int x,int y) {
super();
this.x = x;
this.y = y;
}
}
Filed 代表某个类中的成员变量,
字节码.getField("str");
打印成员变量具体的值,getField("str").get("对象");
获取声明的变量
getDeclaredField
暴利反射
fieldx.setAccessible(true);
//得到所有的成员变量
Field[] fields = obj.getClass().getFields();
字节码的比较用“==”
ReflectPoint rp1 = new ReflectPoint(3,5);
//获得成员变量对应的类
Field fieldy = rp1.getClass().getField("y");
//打印具体对象的值
System.out.println(fieldy.get(rp1));
//x是私有的方法变为getDeclaredField();
Field fieldx = rp1.getClass().getDeclaredField("x");
//暴力反射
fieldx.setAccessible(true);
System.out.println(fieldx.get(rp1));
privatestaticvoid changeStringValue(Object obj)throws Exception{
//得到所有的成员变量
Field[] fields = obj.getClass().getFields();
//遍历找到
for(Field field :fields){
//如果类型是String类型
if(field.getType()==String.class){
//得到值,
String oldValue = (String)field.get(obj);
//进行替换
String newValue = oldValue.replace('b','a');
//设置新的值
field.set(obj, newValue);
}
}
}
Method类:
Method类代表某个类的方法成员。
得到类中的某一个方法:
Method chaAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
字节码.getMethod(name, parameterTypes)
Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
invoke();
public Object invoke (Object obj, Object . . . args)
obj 调用底层方法的对象,
args用于方法调用的参数。
返回使用参数args 在obj上使用该对象所表示方法的结果
调用方式:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke( str, 1 ));
如果传递给Method对象的invoke()方法一个参数为null,这说明该Method对象对应一个静态方法。
mainMethod().invoke(null , new Object [ ] { new String [ ] { " "," ". . . } });
mainMethod( ).invoke(null , (Object) new String [ ] { " "," ". . . });
用反射的方式执行某个类中的main方法。
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
//main接收一个字符串数组,一个参数。需要进行处理。两种方式:
mainMethod.invoke(new TestArguments(),new Object[] {new String[ ]{"111","222","333"}});
//强转成一个对象
mainMethod.invoke(null, (Object)new String[ ] {"1","2","3"});
Arrays工具类用于完成对数组的反射操作。
具有相同的维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperClass( )方法返回的父类为Object类对应的Class
基本类型的以为数组可以被当做Object类型使用,不能当做Object [ ]使用
非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[ ]类型使用。
Arrays.asList( )方法处理 int[ ]和String [ ]时的差异。
先将数组转成List对象
String [ ] a4 = new String[ ]{"a","b","c"};
System.out.println(Arrays.asList(a4));
printObject(a4); a b c
printObject("xyz"); xyz
构造方法printObject打印数组。
private static voidprintObject(Object obj) {
Class cla1 = obj.getClass();
if(cla1.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);
}
}
hashCode()是用来产生哈希码的,而哈希码是用来在散列存储结构中确定对象的存储地址的,
hashCode()方法使用来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的
区域段里面,Map在搜索一个对象的时候先通过hashCode()找到相应的区域段,然手再根据
equals()方法找到相应的对象。
两个相等对象的equals方法一定为true,但两个hashcode相等的对象不一定是相等的对象。
所以hashcode相等只能保证两个对象在一个Hash表里的同一条hash链上,继而通过equals方法才能确定
是不是同一个对象,如果结果为true,则认为是同一对象不再插入,否则认为是不同对象
继续插入。
只有类的实例对象要被采用哈希算法进行存储和检索是,这个类才需要按要求覆盖hashCode
方法。即使程序可能暂时不会用到当前类的hashCode方法,但是为它提供一个hashCode
方法也不会有什么不好,只是未雨绸缪。所以,通常要求hashCode方法和equals方法一并被
同时覆盖。
提示
(1)通常来说,一个类的两个实例对象用equals( )方法比较的结果相等时,他们的哈希码也
必须相等,但反之则不成立,即equals方法比较不相等的对象可以有相同的哈希码,或者说哈希
码相同的两个对象的equals方法比较的结果可以不等,例如,“BB”和“AA”的equals
方法比较结果肯定不相等,但他们的hashCode方法返回值却相等。
(2)当一个对象被存储进HashSet集合以后,就不能修改这个对象中那些参与计算哈希值的字段了
,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下
即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回
找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。
反射的作用:实现框架功能。
房子 门 锁
(框架) (客户) (工具类)
工具类被用户的类调用,
框架则是调用用户提供的类。
例子:
(1)设置一个 . properties文件
(2)读取配置文件中类的名字
(3)利用上一步结果,创建新的实例,这样整个程序中不会有new()
//读取配置文件
//InputStream is = new FileInputStream("config.properties");
类加载器,加载资源
//InputStream is = ReflectTest2.class.getClassLoader().getResourceAsStream("cn\\itcast\\day1\\config.properties");
//InputStream is = ReflectTest2.class.getResourceAsStream("Resourse\\config.properties");
InputStream is = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/Resourse/config.properties");
//问:" \ " 和 " / " 在路径表示的时候有什么区别
//创建Properties对象
Properties prop = new Properties();
//加载配置文件
prop.load(is);
is.close();
//指定字符串classname为类名
String classname = prop.getProperty("classname");
//创建实例对象。无参构造方法,创建实例对象。
Collection collections =(Collection) Class.forName(classname).newInstance();
在MyEclipse中如果源文件目录中有非. java文件 那么会自动复制到classpath下
未来学习的框架:配置文件都是放在classpath路径下
config.properties
name value
classname java.util.HashSet
---------------------- android培训、java培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net/heima