Class类
JAVA程序中的各个Java类属于同一类事物,描述这类事物的java类名就是Class。
Class类提供的方法很多,例如:getName,getMethod,getPackage.....
Class引用 没有构造方法或构造方法私用。所以不能用new的方式获取实例。
如何得到各个字节码对应的实例对象(Class类型)
1. 类名.class,例如:System.class
2. 对象.getClass(),例如:new Date().getClass()
3. Class forName(“类名”),例如:Class forName(“java.util.Date”);
以上三种获取的Class都是在内存中的同一个
九个预定义Class实例对象
八个基本数据类型加一个void.class();
.isPrimitive():判断是否是基本类型的字节码
包装类.TYPE:代表包装的基本类型的字节码,例如:int.class == Integer.TYPE
.isArray():判断class是不是数组
反射:
反射就是把Java类中的各种成分映射成相应的java类。
Constructor类
代表某个类中的一个构造方法
得到某个类所有的构造方法:
例子:Constructor[]constructor = Class.forName(“java.lang.String”).getConstructors()
得到某个类中的一个构造方法:
例子:Construtor constructor = String.class.getConstructor( 第一个参数(StringBuffer.class),第二个参数(int.class) );
获得方法时要用到类型
创建实例对象:
通常方式:String str =new String(new StringBuffer(“abc”));
反射方式:Constructor constructor =String.class.getConstructor(StringBuffer.class);
String str = (String) constructor.newInstance(new StringBuffer(“abc”));
反射会导致程序性能下降
Class.newInstance()方法:
例子:String obj =(String) Class.forName(“java.lang.String”).newInstance();
该方法先得到默认的构造方法,然后用构造方法创建实例。
用到了缓存机制来保存默认构造方法的实例对象。
Field类
代表某个类中的成员变量
获取所有成员变量
getFields()
获取一个成员变量
classAaa{
private int x;
public int y;
Aaa(){
this.x = 3;
this.y = 5;
}
}
Aaa a = new Aaa();
Field fieldY = a.getClass().getField(“y”);
这里的fieldY指的是一个变量,而不是里面的值
fieldY.get(a);取出对象a的fieldY变量的值。
Field fieldX = a.getClass().getDeclaredField(“x”);//获取私有的变量
fieldX.setAccessibie(true);//暴力反射。这样就可以获取私有变量的值了
例:用反射将一个类中所有为String类型的变量的值中的a改为b
Axx a = Axx.class.getInstanct(); //实例化对象
Field[] fields = a.getClass().getFields(); //获取所有成员变量,但不包括私有成员变量
//Field[]fieldArr = sc.getClass().getDeclaredFields(); 获取所有成员变量,包含私有的。
//Field.setAccessible(fields,true);将一个Field的数组中的私有成员变量设为可以访问的。
for(Field fieldVal : fields){
if(fieldVal.getType() == String.class){ //这里比较不要用equase(),因为字节码对象只会产生一个
String oldVal = fieldVal.get(a); //获取值
String newVal = oldVal.replace(‘a’,’b’);
fieldVal.set(‘a’,newVal); //将值写入对应的成员变量中
}
}
Method类
代表某个类中的一个成员方法
获取类中的某一个方法:
Method method = String.class.getMethod(“方法名称”,参数类型1.class, 参数类型2.class);
调用方法:
返回值类型 变量 =method.invoke(“对象”,参数1,参数2);
如果这个方法是静态方法:
返回值类型 变量 =method.invoke( null,参数1,参数2);
jdk1.4和jdk1.5的invoke方法的区别
因为jdk1.4没有可变参数:invoke(“对象”, Object[] obj);
例:当一个类启动另一个类的main函数,而这个类的类名是由参数传递进来。这里就需要用到反射。
正常写法: A.main(new String(){“aa”,”bb”}); 如果A类的名称未来,我们又如何来调用main函数。
反射写法:
StringstartClass = args[0];
Method startMain =Class.forName(startClass).getMethod("main", String[].class);
startMain.invoke(null,(Object)new String[]{"123","abc","xyz"}); 在String数组对象前为什么要再(Object)?因为当String[]{"123","abc","xyz"}传入main(String[] args)时,会将String数组解包,之后就有三个参数。会报参数不匹配异常。这种情况就可以写成。 new Object[]{new String[]{"123","abc","xyz"}}或(Object)newString[]{"123","abc","xyz"}。
数组的反射
相同的元素数据类型,和相同的维度。具有相同的Class实例对象
int[ ] a1 = new int[3];
int[ ] a2 = new int[4];
a1.getClass()== a2.getClass() //true
getSuperclass():返回父类为Object类对应的Class。
基本类型的一维数组可以被当做Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可当做Object[]类型使用。
数组就是一个对象,所以:
int[] a1 = new int[]{1,3,5};
int[] a2 =new int[5];
int[][] a3 = newint[][]{{3,4,5,2},{1,2,3,5},{1,2,3,5}};
String[] a4 =new String[]{"ab","de","fg"};
Object obj1 = a1;因为数组就是一个Object,所以这里是正确的
//Object[] obj2 = a2; 因为a2数组是int型的,但这里数组里装的是Object类型。所以不正确。
Object[] obj3 = a3; 因为a3数组是int型的,这里的数组里装的是Object类型,而a3里的int[]也是Object型的。
Object[] obj4 = a4; 因为a4数组是String型的,String就是Object的子类,所以正确。
Arrays.asList()方法处理int[] 和 String[] 的差异。
jdk1.4的List asList(Object[] obj)
jdk1.5的List asList(T... a)
当一维基本类型数组传入之后,会去匹配jdk1.5的asList方法。这里会把整个数组当做一个元素传入,然后再返回成List类型,所以这个List里存入的是这个int数组的hashcode值。
当其它类型或者二维基本类型数组传入之后,因为其它类型和二维基本类型数组中的一维数组是Object的子类,所以会去匹配JDK1.4的asList()方法,asList接收的是一个Object类型的数组。可以将整个数组传入。并正确返回List的值。
那为什么二维基本类型数组打印出来的是hashCode值呢? 这个跟toString方法有关系。
数组反射的应用:
Array.get();
Array.set();
例:
int[] obj = new obj[]{1,3,5,6};
Class objClass = obj.getClass();
if(objClass.isArray()){
intlen = Array.getLength(obj);
for(intx=0;x<len;x++){
//Array.set(obj,x, 7); 设置数组某个元素角标的值
System.out.println(Array.get(obj,x)); //取某个元素角标的值
}
}else{
System.out.println(obj);
}
可以获取数组中元素的类型,但是不可以获取数组的类型。
str[1].getClass().getName();
反射的作用->实现框架功能
框架和工具类:框架调用我写的类,而我调用工具类。
从外部调用配置文件,将类的名称以键值对形式放入。用properties载入。
第一种:此种方式可以读取配置文件,也可以写入配置文件
InputStream ips = new FileInputStream("config.properties");
Propertiespros = newProperties();
pros.load(ips);
ips.close();
StringclassName = pros.getProperty("classname");
配置文件的路径不能用相对路径
javaweb中得到项目路径:getRealPath( ); 再用这个目录加上内部的地址。
一定要用完整的路径,但是这个完整的路径不是硬编码,而是通过运算得来的。
第二种:通过类加载器加载普通的文件
InputStreamips =ReflectLoadClass.class.getClassLoader().getResourceAsStream("cn//code//resource//config.properties");
是在classpath的根目录下找config.properties文件。如果不是在根目录下则找不到!
InputStreamips =ReflectLoadClass.class.getResourceAsStream("config.properties");
以 ReflectLoadClass此类为参考,config.properties的相对路径。
InputStreamips =ReflectLoadClass.class.getResourceAsStream("//cn//code//resource//config.properties");
从根目录开始指定完整的路径