反射(张孝祥Java视频笔记)

17,18节视频

Class 用来描述Java中的各个类

将类的.class文件从硬盘上加载到内存中,并为之生成相应的java.lang.Class对象

得到java.lang.Class的方法有三种:

  • 类名.class 例如:System.class
  • 对象.getClass() 例如:new Date().getClass()
  • Class.forName(“类名”) 例如:Class.forName(“java.util.Date”)

一般推荐使用第一种方式,原因如下:
代码更加安全。程序在编译阶段就可以检查需要访问的class对象是否存在。
代码性能更好。因为这种方法无需调用方法,所以性能更好。

java中的八种基本类型也有对应的Class,void也有Class对象,即可以同过void.class获得void的字节码

字节码.isPrimitive() 通过这个方法判断字节码对应的类是不是基本类型

反射就是把java类中的各种成份映射成相应的类

编译时错误,运行时错误 ;classpath

对字节码的比较用==比较专业(只有一份)
field.getType() == String.class

传智播客web day01视频中讲解的

通过getXxxxx()只能取得该类public的类型
通过getDeclaredXxxxxx()可以取得该类非public的类型
设置非public类型的可访问性,默认为false,不可访问
c.setAccessible(true);

19节视频

构造方法的反射

得到多个构造方法

1
Constructor[] constructor1 = String.class.getConstructors();

得到一个构造方法

1
2
3
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String)constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str2.charAt(2));

注意:
很少通过反射来创建对象,因为通过反射来创建对象时性能要稍微低一些,实际上,只有当程序需要动态的创建某个类的对象的时候才会考虑使用反射,通常在开发通用性比较广的框架,基础平台的时候可能会大量使用反射。

20 , 21节视频

成员变量的反射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 public class ReflectPoint {
    
     private int x;
     public int y;
     public String str1 = "hhhhhhhh";
     public String str1 = "abdcdecc";
     public String str1 = "baseras";

     public ReflectPoint(int x, int y) { 
          super();
          this.x = x;
          this.y = y;
     }
}

  ReflectPoint pt1 = new ReflectPoint(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)); 


ReflectPoint pt1 = new ReflectPoint(3,5); 
//得到所有的字段
Field[] fields = pt1.getClass().getFields();
//遍历所有字段,并将String类型的字段的里面的b替换成a
for(Filed field:fields){
    if(field.getType()==String.class){
            String oldValue  = (String)field.get(pt1);
            String newValue = oldValue.replace('b','a');
            field.set(pt1,newValue);
    }
}

22,23节视频

成员方法的反射

1
2
Method methodCharAt = String.class.getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke("abcdefg",1));//打印结果为b

如果invoke(null,1)第一个参数传入的是null,则表明这个方法是一个静态方法

在一个类中调用另一个类的main方法

1
2
3
4
5
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
//mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
//因为是静态方法,所以第一个参数是null
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});//因为是静态方法,所以第一个参数是null

之所以写成new Object[]{new String[]{"111","222","333"}} 是为了兼容其他版本的jdk

24 , 25节视频

维数相同,存储的元素的类型的相同的数组,在内存中对应的类的字节码是相同的;

1
2
3
4
5
6
7
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()); //true
System.out.println(a1.getClass() == a4.getClass()); //false System.out.println(a1.getClass() == a3.getClass()); //false

数组元素对应的父类都是Object

1
2
3
4
5
6
7
8
System.out.println(a1.getClass().getSuperclass().getName()); //object
System.out.println(a4.getClass().getSuperclass().getName());//object

Object aObj1 = a1;
Object aObj2 = a4;
//Object[] aObj3 = a1; //基本类型的数组不能赋给Object类型的数组
Object[] aObj4 = a3;
Object[] aObj5 = a4;

不能直接打印数组里的值

1
2
System.out.println(a1);
System.out.println(a4);

采用此方法打印数组里的值,注意基本类型的数组采用此方法也无法打印出数组值

1
2
System.out.println(Arrays.asList(a1)); // 仍然无法打印
System.out.println(Arrays.asList(a4));//打印成功

数组反射的应用

数组反射的应用
《1》

1
2
3
4
5
6
7
8
9
10
11
  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);
          }
   }

《2》

1
2
3
4
5
6
7
8
9
10
11
  // 创建一个元素类型为String ,长度为10的数组
   Object arr = Array.newInstance(String.class, 10);
   // 依次为arr数组中index为5、6的元素赋值
   Array.set(arr, 5, "疯狂Java讲义");
   Array.set(arr, 6, "轻量级Java EE企业应用实战");
   // 依次取出arr数组中index为5、6的元素的值
   Object book1 = Array.get(arr , 5);
   Object book2 = Array.get(arr , 6);
   // 输出arr数组中index为5、6的元素
   System.out.println(book1);
   System.out.println(book2);

完整代码链接 http://pan.baidu.com/s/1sjSgAJj

26节视频

HashCode的值得作用

27,28节视频

反射用的最多的地方是框架

框架—–调用你的代码
工具类—-你的代码调用的类

采用框架可以加快开发速度提高效率

反射在框架中的使用:利用反射通过读取配置文件进行类声明

config.properties文件的内容:

1
className=java.util.HashSet

<一>

1
InputStream ips = new FileInputStream("config.properties");//获取绝对路径+配置文件名字

<二>

1
InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");

<三>

1
2
3
InputStream ips = ReflectTest2.class.getResourceAsStream("config.properties");
InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");

<二>,<三>方法不能完全代替<一>方法,因为<二>,<三>方法是只读的,只能读取配置文件的内容

1
2
3
4
5
6
7
Properties props = new Properties();
props.load(ips);
ips.close();
//props.StringPropertyNames();该方法返回所有的name到一个集合中,可以进行遍历
// String[] strArray =props.StringPropertyNames(); 返回所有的name以数组的形式
String className = props.getProperty("className");
Collection collections = (Collection)Class.forName(className).newInstance();

26节视频
路径问题

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器