17_张孝祥_Java基础加强_透彻分析反射的基础_Class类
l 如何得到各个字节码对应的实例对象(Claass类型)
Ø 类名.class,例如System.class
Ø 对象.getClass,例如:new Data().getClass();
Ø Class forName(“类名”),例如:ClassforName(“java utile Date”);
l 九个预定义Class实例对象:
Ø 8种基本数据类型(boolean
、byte
、char
、short
、int
、long
、float
、double
)和void。
Ø 基本数据类型.class == 基本数据包装类.TYPE。例如,int.class == Integer.TYPE;
l 数组类型的Class实例对象。
Ø Class isArray()
² 总之,只要在源程序中出现类型,都有各自的Class实例对象,例如int[],void。
代码演示:
String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
System.out.println(cls1 ==cls2);//true
System.out.println(cls1 ==cls3);//true
System.out.println(cls1.isPrimitive());//false
System.out.println(int.class.isPrimitive());//true
System.out.println(int.class == Integer.class);//false
System.out.println(int.class == Integer.TYPE);//true
System.out.println(int[].class.isPrimitive());//false
System.out.println(int[].class.isArray());//true
18_张孝祥_Java基础加强_理解反射的概念
l 反射就是把Java类中的各种成分映射成相应的java类。一个类中的组成部分:成员变量,方法,构造方法,包等等。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
19_张孝祥_Java基础加强_构造方法的反射应用
l Constructor类代表某个类中的一个构造方法
l 得到某个类所有的构造方法:
Ø 例子:Constructor [] constructors=Class.forName("java.lang.String").getConstructors();
l 得到某一个构造方法:
Ø 例子:Constructor constructor =
Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
l 创建实例对象:
Ø 通常方式:String str = new String(newStringBuffer("abc"));
Ø 反射方式: String str = (String)constructor.newInstance(newStringBuffer("abc"));
代码演示:
package day25reflect;
public class Person {
private int num;
private Stringname;
public Person(String name){
this.name = name;
}
public Person(String name,int num){
this.name = name;
this.num = num;
}
}
package day25reflect;
import java.lang.reflect.Constructor;
public class ReflectTest {
public static void main(String[] args)throws Exception {
Class<Person> cls = (Class<Person>)Class.forName("day25reflect.Person");//注意包名省略会报错
Constructor<Person> constructor1 =(Constructor<Person>)cls.getConstructor(String.class,int.class);
Person p1 = constructor1.newInstance("李某某",24);
System.out.println(p1);
Constructor<Person> constructor2 =(Constructor<Person>)cls.getConstructor(String.class);
Person p2 = constructor2.newInstance("李某某");
System.out.println(p2);
Constructor constructor3 =
Class.forName("java.lang.String").getConstructor(StringBuffer.class);
String str = (String)constructor3.newInstance(new StringBuffer("abc"));
System.out.println(str);
Constructor constructor4 =
Class.forName("java.lang.String").getConstructor(char[].class);
String str2 = (String)constructor4.newInstance(newchar[]{'a','b','c'});
System.out.println(str2);
}
}
打印结果:
day25reflect.Person@c17164
day25reflect.Person@1fb8ee3
abc
abc
//通过newInstance方法返回的结果都是指定类型的实例对象。
20_张孝祥_Java基础加强_成员变量的反射
/*ReflectPoint.java*/
import java.util.Date;
public class ReflectPoint {
private Datebirthday =new Date();
private int x;
public int y;
public Stringstr1 ="ball";
public Stringstr2 ="basketball";
public Stringstr3 ="itcast";
public ReflectPoint(int x,int y) {
super();
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj ==null)
return false;
if (getClass() != obj.getClass())
return false;
final ReflectPoint other = (ReflectPoint) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
@Override
public String toString(){
returnstr1 +":" +str2 +":" +str3;
}
/*成员变量的set和get方法省略*/
}
l 成员变量的反射示例
ReflectPoint pt1 = newReflectPoint(3,5);
Field fieldY =pt1.getClass().getField("y");
//fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上,要用它去取某个对//象上对应的值
System.out.println(fieldY.get(pt1));
Field fieldX =pt1.getClass().getDeclaredField("x");//受保护或私有成员变//量须调用此方法。
fieldX.setAccessible(true);
System.out.println(fieldX.get(pt1));
21_张孝祥_Java基础加强_成员变量反射的综合案例
l 改变字段的函数:
private static void changeStringValue(Object obj)throws Exception {
Field[] fields = obj.getClass().getFields();
for(Field field : fields){
//if(field.getType().equals(String.class)){
if(field.getType() == String.class){
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b','a');//将字段变量//的字符b换成a。
field.set(obj, newValue);
}
}
}
}
22_张孝祥_Java基础加强_成员方法的反射
l 成员方法放射举例:
String str1 = “abc”;
Method methodCharAt = String.class.getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke(str1,1));//b
System.out.println(methodCharAt.invoke(str1,new Object[]{2}));//c
l jdk1.4和jdk1.5的invoke方法的区别:
Ø Jdk1.5:public Objectinvoke(Object obj,Object... args)
Ø Jdk1.4:public Objectinvoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。
23_张孝祥_Java基础加强_对接收数组参数的成员方法进行反射
l 问题:
启动Java程序的main方法的参数是一个字符串数组,即public static voidmain(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mainMethod.invoke(null,newString[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不把它当作jdk1.5的语法解释,因此会出现参数类型不对的问题。
l 解决办法:
Ø mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
Ø mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了。
代码演示:
//TestArguments.main(newString[]{"111","222","333"});
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);
//mainMethod.invoke(null, newObject[]{new String[]{"111","222","333"}});
mainMethod.invoke(null, (Object)newString[]{"111","222","333"});
24_张孝祥_Java基础加强_数组与Object的关系及其反射类型
int [] a1 = new int[]{1,2,3};
int [] a2 = new int[4];
int[][] a3 = new int[2][3];
String [] a4 = new String[]{"a","b","c"};
System.out.println(a1.getClass()== a2.getClass());
//System.out.println(a1.getClass()== a4.getClass());
//System.out.println(a1.getClass()== a3.getClass());
System.out.println(a1.getClass().getName());
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(a4.getClass().getSuperclass().getName());
Object aObj1 = a1;
Object aObj2 = a4;
//Object[] aObj3 = a1;
Object[] aObj4 = a3;
Object[] aObj5 = a4;
System.out.println(a1);
System.out.println(a4);
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));
}
25_张孝祥_Java基础加强_数组的反射应用
l 数组的反射
Ø 具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。
Ø 代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
Ø 基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
Ø Arrays.asList()方法处理int[]和String[]时的差异。
Ø Array工具类用于完成对数组的反射操作。
代码演示:
printObject(a4);
printObject("xyz");
private static void printObject(Object obj) {
Class clazz = obj.getClass();
if(clazz.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);
}
}
26_张孝祥_Java基础加强_ArrayList_HashSet的比较及Hashcode分析
代码演示:
/*首先,在Reflect类中重写hashCode和equals方法*/
/*下面为测试类中主函数的测试代码*/
Collection collections= newHashSet();
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());//2
28_张孝祥_Java基础加强_用类加载器的方式管理资源和配置文件
/*getRealPath();//金山词霸/内部
一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的。*/
//获取相对路径,开发中不这么做。<配置1>
//InputStream ips =new FileInputStream("config.properties");
/*获取当前工作目录下的文件(类加载器可以加载classpath目录文件,同样一
般文件放到classpath目录中也能加载,注意,Eclipse在src源文件目录中java
文件编译后会以.class文件存到classpath目录中,其他文件会原封不动地存到
classpath目录中),开发中常用到.<配置2>*/
//InputStream ips =ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");
//相对于当前包下面的文件.<配置3>
//InputStream ips =ReflectTest2.class.getResourceAsStream("resources/config.properties");
//路径"/"开头,表示是从根目录开始。<配置4>
InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
Properties props = new Properties();
props.load(ips);
ips.close();
StringclassName = props.getProperty("className");