黑马程序员-张老师基础加强2-反射
2014-06-06 18:33 黑马程序员* 阅读(223) 评论(0) 收藏 举报反射
出现的原因:当要修改已有的应用程序时,早起是提供接口,让新的程序实现该接口,并在原程序中使用多态。现在可以使用反射,只要将程序的类名,传到配置文件中即可。
好处:1.大大提高了程序的扩展性2.不用再面对源代码,而只看配置文件。
反射的定义:可以动态获取一个类中的各种信息。
反射的基础:Class类
获取Class类的方法:
类名.class,如:Math.Class
对象.getClass(),如果对象已经加载到了内存中
Class.forName(String).如果字节码文件已经加载了,则直接返回。如果没加载,则用类加载器加载到内存中,并返回该字节码文件。
如:Class.forName(“java.lang.String”),类名要使用完整的类名,包括包名。
九个预定义Class实例对象:八个基本数据类型和void.
常用方法。getConstructor(),getMethod(),getField(),newInstance().
Construtor<T>类
4.1获取Constructor:
getConstructors():返回Constructor数组,获取所有的public构造方法,包括父类的。
GetDeclaredConstructor():获取本类的构造方法,包括私有。不包括父类。
getConstructor(Class<?>…Para):获取单个Constructor.
如果有多个构造方法,根据参数类型和个数进行区分。
4.2创建实例对象
Constructor 类的方法:T newInstance((Object... initargs):传递进参数。
Class clazz = Class.forName("java.lang.String");
Constructor cons= clazz.getConstructor(StringBuilder.class);
String str2 = (String)cons.newInstance(new StringBuilder());
Class类的newInstance(),当参数为空时,可以使用。
5.Method类
5.1获取Method
getMethod(String name,Class<?>parameter):获取public的方法,包括抽象。
getDeclaredMethod();获取本类,包括私有
getMethods();
public static void main(String[] args) throws {
Method m1 = Class.forName("cn.itcast.person").getMethod("show2");
Method m3 = Class.forName("cn.itcast.person").getDeclaredMethod("show");
Method m2 = Class.forName("cn.itcast.person").getMethod("show1",int.class);
}}
abstract class person{
private int age;
public String name;
private void show(){
}
public void show1(int a){
}
public abstract void show2();
}
5.2使用Method对象调用对象的方法
Invoke(Object obj,Object …args):对带有指定参数的指定对象调用表示该Method对象的底层方法。
解释:调用方法一定是调用某个对象的方法。(Method对象调用对象的方法,如只有火车才可以调用火车刹车的具体方法,司机只是给了一个指令。)
Method me =
Class.forName("java.lang.String").getMethod("charAt", int.class);
char ch = (Character)me.invoke(new String("cn.ithema"), 5);
System.out.println(ch);
如果Objcet是null,表示该方法是静态方法。
如:Method me = Class.forName("java.lang.Integer").getMethod("toString", int.class);
String num= (String)me.invoke(null, 5);
练习:练习:写一个程序,根据用户提供的类名,访问该类的main方法。
Method me = Class.forName("cn.itcast.Demo6").getMethod("main",String[].class);
Demo6 d = new Demo6();
String[] arr ={"ithema"};
//注意invoke方法为兼顾1.4(接收的是一个Object[]数组对象,或者数组里面是Object对象。因为1.4会将数组拆包)
//Jdk1.5:public Object invoke(Object obj,Object...args)
//Jdk1.4:public Object invoke(Object obj,Object[] args)
//me.invoke(d,arr);不可以
me.invoke(d,(Object)arr);
//或者
Object[] arr1 = {new String[]{"ithema"}};
me.invoke(d,arr1);
获取字段Field
getField();getFields()
get(Object obj);传入要获取的字段的对象。
Field f1 = Class.forName("cn.itcast.person1").getDeclaredField("age");
int age= (Integer) f1.get(new person1());//私有方法无法获取该字段
//暴力反射。父类(AccessibleObject)的方法 setAccessible(boolean)
//getDeclaredField可以访问私有字段,但是无法获取字段的值.使用暴力//反射时用它.如果使用getField()不可以.
f1.setAccessible(true);
System.out.println(age);
}}
class person1{
//private int age=8;
public int age=8;
}
5.3字段的练习:将一个对象的所以String类型的成员变量,对应的字符串的“a”变成“b”
public static void main(String[] args) Exception {
// TODO Auto-generated method stub
Field[] fields = Class.forName("cn.itcast.person11").getFields();
person11 p =new person11();
for(Field f:fields){
if(f.get(p).getClass()==String.class){
String oldString = (String)f.get(p);
String newString =oldString.replace('a', 'b');
f.set(p, newString);
} }
System.out.println(p);
}}
class person11{
public String name="liasiq";
public String age="20a";
public String toString(){
return age+name;
}
}
6 数组的反射
Array类提供了动态创建和访问 Java 数组的方法,Array 允许在执行 get或 set 操作期间进行扩展转换。数组一旦建立:长度就固定了
6.1具有相同维度和类型的数组,Class是相同的。
public static void main(String[] args) {
int[] arr = new int[]{};
int [] arr1= new int[]{1,4,5,6,41};
arr1[0]=10;
System.out.println(arr.getClass()==arr1.getClass());
//打印Object的方法(如果不是数组则直接打印)
printObj(arr1);
}
public static void printObj(Object obj){
Class object = obj.getClass();
if(object.isArray()){
int len=Array.getLength(obj);//只能使用的是Array的这个方法。
for(int x=0;x<len;x++){//直接打印数组中内容 asList
System.out.println(Array.get(obj, x));//使用Array类的方法
}}
else{
System.out.println(obj);
}}}
Hashcode和HashSet类。
通常查找集合中的对象时,是取每个对与该对对象进行比较,很麻烦。因此在HashSet中,就使用每个对象哈希值进行存储。查找对象时,根据hash值,找到对应的区域,其余的区域就不用查找了。
注意:
- 只有类的实例对象需要被采用哈希值算法进行存储和检索时,才能覆盖hashcode方法。通常也要覆盖equals方法,即使用不到。在比较时,先用哈希值比较,如果相等,再用equals比较。("ab","df"的哈希值相同,但是equasl结果不同)
- 当对象存储进HashSet集合后,就不可以再改变参与哈希值计算的字段了。否则即使是当前的引用,因为哈希值的变化会导致找不到对象,容易导致内存泄露。
Hahscode的作用:
1.提高存储和检索对象时的效率。
2.只能应用与hashSet中。
3.容易导致内存泄露(该删掉没删掉,找不到对应哈希值的对象)
反射的作用—>实现框架的功能。
框架与框架要解决的核心问题:
我做房子给用户,房子就是框架。用户字节安装门窗和空调,用户需要把门窗插入到我们的框架中。
框架与工具类的区别:框架调用用户的类。工具类被用户调调用,如锁。
框架要解决的核心问题:
我在写框架(房子)时,要考虑到框架程序怎样调用以后写的类(门窗)
因为在写程序时无法知道要被调用的类名。所以在程序中无法new某个类的实例对象了,要用反射方式来做。
练习:使用反射读取配置文件中的类名。
FileInputStream fis= new FileInputStream("properties.config");
Properties pro =new Properties();
pro.load(fis);
String classname = pro.getProperty("classname");
Class clazz = Class.forName(classname);
clazz.newInstance();
注意:配置文件的存放问题。运行时的路径是相对于运行环境的,所以不能再前面加个“d:”,因为用户可能没有d盘
怎么解决?:
通过获取getReadname获取用户的安装路径。配置文件就可以设置该路径。
既然类加载器可以加载.class文件,那么它也能加载classpath下的其他普遍文件。所以配置文件就放在classpath路径下。
浙公网安备 33010602011771号