------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
反射
1、Class 2、反射 3、Constructor 4、Filed 5、Method
6、调用主函数 7、数组 8、文件加载 9、集合 11、内省
反射
1、Class
Java中的所有类属于同一事物,描述该事物的类就是Class。Class反射的基石.
Class创建的实例是内存中字节码。字节码就是我们平常所说的类。
获得字节码有三种方式:
Person.class
new Person().getClass()
Class.forName("")
String s="abc";
//获得字节码有三种方式
Class s1=s.getClass();//从内存中获得
Class s2=String.class;//知道类名去加载class文件,然后从内存中获得
Class s3=Class.forName("java.lang.String");//不知道类名,传一个类名,然后去加载class文件,然后从内存中获得
System.out.println(s1==s2);
System.out.println(s2==s3);//三种方式获得为同一字节码
System.out.println(String.class.isPrimitive());
System.out.println(int.class.isPrimitive());
System.out.println(int[].class.isArray());
System.out.println(Integer.TYPE);//基本类型的TYPE字段
2、反射
反射就是把java类中的各种成分映射成java类。
java类中的成分,对应的类有:Field,Method,Contructor,Package...
3、Constructor
类代表某个类中的一个构造方法。获得的方式,一个类中很多个构造方法,怎么获得自己想要的那一个呢?
用参数类型来区分。
构造方法的获得比较耗性能,反射会引起性能下降。
//用反射实现new String(new StringBuffer("abc"));
Constructor constructor1=String.class.getConstructor(StringBuffer.class);
//得到String的一个构造函数,有一个参数,类型为StringBuffer
String ss=(String)constructor1.newInstance(new StringBuffer("abc"));
System.out.println(ss.charAt(1));
4、Filed
表示类中字段这类事物。通过getField方法获得类中的成员,然后获得具体对象中的值。权限不同,获取成员及成员在对象上的值的操作不同。举例如下:
public class ReflectPoint {
public int x;
private int y;
public ReflectPoint(int x, int y) {
this.x = x;
this.y = y;
}
}
非私有成员:
//获得rp对象上的x值
ReflectPoint rp=new ReflectPoint(3,5);
Field fx=ReflectPoint.class.getField("x");//返回的是成员
System.out.println(fx.get(rp));
私有成员:
//获得rp对象上的y值
Field fy=ReflectPoint.class.getDeclaredField("y");//只要你声明了 ,我就能拿到
fy.setAccessible(true);//暴力反射,强制访问
System.out.println(fy.get(rp));
练习:
<span style="white-space:pre"> </span>// 一个修改字符串的小程序
// 将字符值中得b修改为a
public static void changeStrigValue(Object object) throws Exception {
Field[] fields = object.getClass().getFields();
for (Field field : fields) {
if (field.getType() == String.class) {
String oldValue = (String) field.get(object);
String newValue = oldValue.replace('b', 'a');
field.set(object, newValue);
// System.out.println(newValue);
}
}
System.out.println(object);
}
5、Method
//s.charAt(0);
Method methodcharAt=String.class.getMethod("charAt", int.class);
System.out.println(methodcharAt.invoke(s, 0));
System.out.println(methodcharAt.invoke(s, new Object[]{0}));
6、调用主函数
//TestArgs.main(new String[]{"111","222","333"});
String startClassName=args[0];
Method mainMethod=Class.forName(startClassName).getMethod("main", String[].class);
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
class TestArgs{
<span style="white-space:pre"> </span>public static void main(String[] args){
<span style="white-space:pre"> </span>for(String s:args)
<span style="white-space:pre"> </span>System.out.println(s);
<span style="white-space:pre"> </span>}
}
7、数组
//数组的反射
public static void arrayReflet(Object obj){
Class clazz=obj.getClass();//反射的前提是得到字节码,根据字节码进行相关的操作
if(clazz.isArray()){
int length=Array.getLength(obj);
for(int i=0;i<length;i++){
System.out.println(Array.get(obj, i));
}
}else{
System.out.println("obj");
}
}
8、文件加载
A.从PC加载不是用硬编码,而是生成的目录(用户配置的选择)+在项目中得位置:FileInputStream("相对 :因为无法得知用户的选择,故只是相对用户选择的一个路径")
B.从classPath加载
(1):用类加载器:*.class.getLoader().getResourcesAs("classPath下的绝对路径");
(2):用类直接加载:*.class.getLoader().getResourcesAs("classPath下的绝对路径");
(3):用类直接加载:*.class.getLoader().getResourcesAs("classPath下的绝对路径");
public class ReflectTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
/*getRealPath();//金山词霸/内部
一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的。*/
//InputStream ips = new FileInputStream("config.properties");
//InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");
//InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
Properties props = new Properties();
props.load(ips);
ips.close();
String className = props.getProperty("className");
Collection collections = (Collection)Class.forName(className).newInstance();
//Collection collections = new HashSet();
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(5,5);
ReflectPoint pt3 = new ReflectPoint(3,3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);
//pt1.y = 7;
//collections.remove(pt1);
System.out.println(collections.size());
}
}
9、集合
Hashcode()的作用:
修改Hash值
对象默认的Hash值,与对象在内存中的地址有关,Hash值是为了Hash集合检索方便,使用Hash算法,把Hash集合内部分成若干区域,每个区域的给一个Hash值与对象的Hash值对应;
所以,只有使用Hash集合它才有价值;
所以,要使两个对象在Hash集合中的引用是同一个,就的用Hashcode()方法修改Hash值;
注意:已存入Hash集合的对象,不能再修改Hash值有关的字段值,会引起内存泄露。
String className = (String) props.getProperty("className");
Collection collection = (Collection) Class.forName(className)
.newInstance();
// Collection collection=new HashSet();
collection.add(pt1);
collection.add(pt2);
collection.add(pt3);
collection.add(pt4);
// pt1.x=6;
// collection.remove(pt1);
System.out.println(collection.size());
10、内省
intorspection内省,用来操作javaBean。
编写Person的javaBean:
public class Person(){
public int age;
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
获取javaBean属性的方法:
如果第二个字母是小写,则把set&get后第一个字母变成小写;
如果第二个字母是大写,则把保持大写;
eg: settime-->time(??)
setTime-->time
setTIME-->TIME
}
//主要用到PropertyDescriptor,来操作javaBean的set&get方法
private static void setObject(Object rp, String propertyName, Object object)
throws Exception
{
PropertyDescriptor pd2= new PropertyDescriptor(propertyName, rp.getClass());
Method methodSetX=pd2.getWriteMethod();
methodSetX.invoke(rp,object);
}
private static Object getObject(Object rp, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
PropertyDescriptor pd= new PropertyDescriptor(propertyName, rp.getClass());
Method methodGetX=pd.getReadMethod();
Object retValue=methodGetX.invoke(rp);
return retValue;
}
// 复杂的内省
public static Object getObject2(Object rp,String propertyName) throws Exception{
Object retValue = null;
PropertyDescriptor[] pds = Introspector.getBeanInfo(rp.getClass())
.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
if (pd.getName().equals(propertyName)) {
Method methodGet = pd.getReadMethod();
retValue = methodGet.invoke(rp);
break;
}
}
return retValue;
}