Class类----反射的基石
Class类代表一类事物
java类用于描述一类事物的共性,该事物有什么属性,没有什么属性,至于这个属性的值是什么,则由这个类的实例对象来确定。Java中的各个java类,他们是否属于同一类事物,是不是可以用一个类来描述这类事物呢,这个类名就是Class
Class类描述了哪些信息呢——类的名字,类的访问属性,类所属的包名,字段名称的列表,方法名称的列表
九个预定义的Class实例对象
基本的 Java 类型(boolean
、byte
、char
、short
、int
、long
、float
和double
)和关键字void
也表示为 Class
对象。
例子 Class cl = void.class;
isPrimitive()
方法
判定指定的 Class
对象是否表示一个基本类型。
Int.class == Integer.TYPE TYPE代表一个常量,就是基本类似所代表的字节码
数组类型的Class实例对象
Int[].class.isArray() 也是基本类型
结果true
总之,只要在源程序中出现的类型都有自己的Classs实例对象
反射
反射就是把java类中的各种成分映射成相应的java类
Constructor类
代表某个类中的一个构造方法
得到某个类所有的构造方法
Constructor constructor[] =
Class.forName(“java.lang.String”).getConstructor()
得到某个类所有的一个方法
Constructor constructor[] =
Class.forName(“java.lang.String”).getConstructor(StringBuffer.class)
//获得方法时要用到类型
创建实例对象
一般方式
String str1 = new String (new StringBuffer("abc"));
反射方式 classàconstrutorànew object
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 =
(String) constructor1.newInstance(newStringBuffer("abc"));
//调用获得的方法时要用到上面相同类型的实例对象
Class.newInstance()方法 不带参数的构造方法
例子:String str = (String)Class.forName(“java.lang.String”) .newInstance
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象
成员变量的反射
Filed类 代表某个类中的一个成员变量
ReflectPoint pt1 = new ReflectPoint(3,5);
//获取一个字段,fieldY代表字节码身上的变量,没有对应到对象身上所以fieldY的值不是5
Field filedY = pt1.getClass().getField("y");
//取出变量在某个对象上的值
System.out.println(filedY.get(pt1));
获取私有的
//x是私有的 会返回java.lang.NoSuchFieldException: x错误
//Field filedX =pt1.getClass().getField("x");//getField只能的到可见的
Field filedX = pt1.getClass().getDeclaredField("x");//getDeclaredFields可以获取不可见的
//getDeclaredFields虽然可以看见了但是不可以使用,
filedX.setAccessible(true);
//取出变量在某个对象上的值
System.out.println(filedX.get(pt1));
将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的”b”改成”a”
//定义String类型
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "itcast";
public String toString(){
return str1+"::"+str2 +"::" + str3;
}
//将字符串中的b改变成a
changeStringValue(pt1);
System.out.println(pt1);
}
private static void changeStringValue(Object obj) throwsIllegalArgumentException, IllegalAccessException {
Field[] fields = obj.getClass().getFields();
for(Field field : fields){
//获取类型
/* field.getType().equals(String.class) 字节码应该用等号比*/
if(field.getType() == (String.class)){
//获取变量的值
String oldValue = (String) field.get(obj);
//b改变成a 获取新值
String newValue = oldValue.replace("b", "a");
//对象的字段还没有改
field.set(obj, newValue);
}
}
}
成员方法的反射
Method类代表某个类中的成员方法
String str1 = "abcs";
Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
//JDK1.5多个可变参数
System.out.println(charAt.invoke(str1, 1));//如果invoke(str1,1));里的对象为null则代表为静态的
//JDK1.4 //静态方法调用不需要对象
System.out.println(charAt.invoke(str1,new Object[]{1}));
用反射方式执行某个类中的main方法
目标:写一个程序,这个程序能够根据用户名提供的类名,去执行该类中的main方法
public class GetMainDemo {
public static void main(String[] args) throws Exception {
// TODO Auto-generatedmethod stub
//一般调用方法
//MainDemo.main(newString[]{"114","12r5"});
//反射方法
//假设这里面的第一个参数就是那个类的名字
String className = args[0];
Method methodCharAt = Class.forName(className).getMethod("main", String[].class);
methodCharAt.invoke(null,(Object)(new String[]{"114","12r5"}));
}
}
class MainDemo{
public static void main(String[]args){//传了一些参数,执行我的方法的时候,这个方法里面就带有去
for(String arg : args){ //启动哪个类。假设这里面的第一个参数就是那个类的名字
System.out.println(arg);
}
}
}
数组的反射
public static void main(String[] args) {
// TODO Auto-generatedmethod stub
Object obj = null;
printObject("saab");
String [] a = {"Ag","agw"};
printObject(a);
}
private static void printObject(Object obj) {
// TODO Auto-generatedmethod stub
//获取obj的字节码
Class cl = obj.getClass();
if(cl.isArray()){
//获取obj的长度
int leg = Array.getLength(obj);
for(int x=0; x<leg; x++){//获取obj
System.out.println(Array.get(obj, x));
}
}else{
System.out.println(obj);
}
}
结果
saab
Ag
agw
HashCoad的作用
提高从集合中查找元素的效率,这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应若干个区域存储,根据一个对象的哈希码就可以确定该对象对应存储在哪个区域
当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与运算的哈希值字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了。在这种情况下,即使在contains方法使用该对象的当前引用作为的参数与HashSet集合中检索对象,也将返回找不到对象的结果,这样会导致无法从HashSet集合中单独删除当前对象,从而造成内存溢出
反射的作用--à实现框架功能
框架:
我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。
框架与工具类的区别:
工具类被用户的类调用,而框架则是调用用户提供的类
框架要解决的核心问题
因为写程序时无法知道要被调用的类名,所以,在程序中无法直接new出来某个类的实例对象,而要用反射方式来做
用反射的方式来做HashSet 和ArrayList
//加载config.properties文件
FileInputStream fis = new FileInputStream("config.properties");
//Properties可以把自己内存中的键值对存到硬盘里,也可以把硬盘中的键值对直接读取
Properties props = new Properties();
props.load(fis);
fis.close();
String className = props.getProperty("className");
//new一个Collection对象
Collection collections = (Collection)Class.forName(className).newInstance();
ReflectPoint rp1 = new ReflectPoint(3,4);
ReflectPoint rp2 = new ReflectPoint(4,4);
ReflectPoint rp3 = new ReflectPoint(5,4);
ReflectPoint rp4 = new ReflectPoint(3,4);
collections.add(rp1);
collections.add(rp2);
collections.add(rp3);
collections.add(rp4);
System.out.println(collections.size());
用类加载器的方式管理资源和配置文件
类加载器把.class文件加载到内存中去
方法一:
一定要用完整的路径,但完整的路径不是硬编码,而是运算出来的
方法二:
ArrayDemo2.class.getClassLoader().getResourceAsStream("目录文件名");
//类加载器 //加载普通文件,在classPath目录查找文件
ArrayDemo2.class.getResourceAsStream("文件名");
没有\只取相对路径,相对于包而言。有\则是代表据对路径,需要写上完整的地址
ArrayDemo2.class.getResourceAsStream("\路径文件名");
内省-àIntorSpector
用于对JavaBean操作,JavaBean是特殊的java类。主要用于传递数据信息。方法的名字符合某种既定规则。
规则就是方法都是以get,set开头的。
javaBean的属性就是方法名去掉get,set后面的单词。如果第二个子母小写就把第一个子母变小写 ,如果第二个子母是大的就保持原样
如:setgAge() 在javaBean中的属性就是age
对javaBean简单内省操作 获取和修改点的X和Y
//把对象当作javaBean来操作
ReflectPoint rp = new ReflectPoint(3,5);
//一般方法获取X的值
String propertyName = "x";
//属性描述符 PropertyDescriptor 获取javaBean的属性
PropertyDescriptor pd =
new PropertyDescriptor(propertyName,rp.getClass());//属性名,和java类
//获取读写方法 pd.getReadMethod(); pd.getWriteMethod();
//获取X属性的读方法
Method getMethodX = pd.getReadMethod();
Object retVal = getMethodX.invoke(rp);
System.out.println(retVal);
//修改x的属性
Method setMethodX =pd.getWriteMethod();
setMethodX.invoke(rp,4);
System.out.println(rp.getX());
获取
方法一
//把对象当作javaBean来操作
ReflectPoint rp = new ReflectPoint(3,5);
//方法一
/*//一般方法获取X的值
String propertyName = "x";
//属性描述法 PropertyDescriptor 获取javaBean的属性
PropertyDescriptor pd = newPropertyDescriptor(propertyName,rp.getClass());//属性名,和java类
//获取读写方法 pd.getReadMethod(); pd.getWriteMethod();
//获取X属性的读方法
Method getMethodX = pd.getReadMethod();
Object retVal = getMethodX.invoke(rp);
System.out.println(retVal);
*/
方法二 //重构 Refactor---> Extract Mathod
//方法二
String propertyNameX = "x";
//对哪个对象身上的哪个属性进行获取
Object retVal = getProperty(rp, propertyNameX);
System.out.println(retVal);
//重构 Refactor---> Extract Mathod
private static Object getProperty(Object rp, String propertyName)throws Exception {
PropertyDescriptor pd = newPropertyDescriptor(propertyName,rp.getClass());
Method getMethodX = pd.getReadMethod();
Object retVal = getMethodX.invoke(rp);
return retVal;
}
设置
方法一
//修改Y的属性 方法一
String propertyNameY = "y";
Object value = 4;
PropertyDescriptor pd = newPropertyDescriptor(propertyNameY,rp.getClass());
Method setMethodY = pd.getWriteMethod();
setMethodY.invoke(rp,value);
System.out.println(rp.getY());
方法二 重构
//方法二
String propertyNameY = "y";
Object value = 4;
setProperty(rp, propertyNameY, value);
System.out.println(rp.getY());
private static void setProperty(Object rp, String propertyNameY,
Object value) throws Exception{
PropertyDescriptor pd = newPropertyDescriptor(propertyNameY,rp.getClass());
Method setMethodY = pd.getWriteMethod();
setMethodY.invoke(rp,value);
}
BeanUtils工具包
System.out.println(BeanUtils.getProperty(rp, "x"));
BeanUtils.setProperty(rp,"y", "9");