Java反射的小故事

Java反射的小故事:

首先定义一个Java类

 1 package com.xiaoysec.test;
 2 
 3 public class Person {
 4     private String name;
 5     private String sex;
 6     private int id;
 7 
 8     public String getName() {
 9         return name;
10     }
11 
12     public void setName(String name) {
13         this.name = name;
14     }
15 
16     public String getSex() {
17         return sex;
18     }
19 
20     public void setSex(String sex) {
21         this.sex = sex;
22     }
23 
24     public int getId() {
25         return id;
26     }
27 
28     public void setId(int id) {
29         this.id = id;
30     }
31 
32     public Person(String name, String sex, int id) {
33         this.name = name;
34         this.sex = sex;
35         this.id = id;
36     }
37     private void show(){
38         System.out.println("name is:"+this.name);
39         System.out.println("sex is:"+this.sex);
40         System.out.println("id is:"+this.id);
41     }
42     public static void main(String[] args){
43         System.out.println(args[0]);
44     }
45 }
View Code

在类中定义了一些方法,尤其注意的是方法的访问权限,show()方法被定义为了私有方法,以前上课的时候只是说private修饰的方法或属性只能在类的内部进行访问,那么这句话有没有问题呢?

 1 package com.xiaoysec.test;
 2 
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.Field;
 5 import java.lang.reflect.Method;
 6 
 7 import org.junit.Test;
 8 
 9 public class Classtest {
10     private String simplename;
11 
12     @Test
13     public void test() {
14 
15         try {
16             Class c = Class.forName("com.xiaoysec.test.Person");
17             Constructor constructor = c.getConstructor(new Class[] {
18                     String.class, String.class, int.class });
19             Person p = (Person) constructor.newInstance("xiaoysec", "sex", 19);
20             Method m = c.getDeclaredMethod("show", null); // 获取的是private权限的show方法
21             m.setAccessible(true); // 强行打开访问权限 使用发射可以访问private方法
22                                     // 面试的时候如果被问及private是否可以被访问应该 回答
23                                     // 普通的方式只能在类的内部访问 而通过反射可以访问private
24             m.invoke(p, null);
25             System.out.println(c.getName());
26             System.out.println("-------------");
27             Field f = c.getDeclaredField("name");
28             f.setAccessible(true);
29             Class fieldtype = f.getType();
30             System.out.println(fieldtype);
31             Object o = f.get(p);
32             System.out.println(o.getClass()); // 此处返回的是class java.lang.String
33             System.out.println(o);
34             System.out.println("--------------");
35             Method mainmethod = c.getMethod("main", String[].class); // main方法的反射
36             // mainmethod.invoke(p, new String[]{"xiaoysec"});//argument type
37             // mismatch
38             mainmethod.invoke(p, (Object) new String[] { "xiaoysec" });
39             // mainmethod.invoke(p,new Object[]{new String[]{"xiaoysec"}});
40             // //此方法也是对的
41         } catch (Exception e) {
42             // TODO Auto-generated catch block
43             e.printStackTrace();
44         }
45 
46     }
47 
48 }
View Code

请注意setAccessible(true)这点,通过设置,就可以访问private修饰的方法了。

另外在上面的代码中值得一提的是main方法的反射

public static void main(String[] args)

这个大家都不陌生,main方法接收一个String数组,在反射中开始时我写的是mainmethod.invoke(p, new String[]{"xiaoysec"});//argument type mismatch提示参数匹配的错误

解决的方法是这样的

1 mainmethod.invoke(p, (Object) new String[] { "xiaoysec" });
//或者 mainmethod.invoke(p,new Object[]{new String[]{"xiaoysec"}});

为什么呢?

大致可以这样理解 ,当遇到数组类型的参数时 会进行拆分,例如str[0],str[1]...并将拆分后的参数作为方法的实参这样的话就匹配不到合适的参数了当然反射也就失败了

而方法一(Object) 就是故意的转型让方法认为传入的不是数组

方法二 大致的意思就是 经过拆分后获取到第一个String数组作为方法的实参 这样就符合了main方法接收一个String数组作为实参的条件

下面再来看看反射和泛型的基情:

 1 package com.xiaoysec.reflecttest;
 2 
 3 import java.lang.reflect.InvocationTargetException;
 4 import java.lang.reflect.Method;
 5 import java.util.ArrayList;
 6 import java.util.Iterator;
 7 
 8 import org.junit.Test;
 9 
10 
11 
12 public class Reflecttest {
13     @Test
14     public void test() {
15         ArrayList<String> list = new ArrayList<String>();
16         list.add("xiaoysec");
17         list.add("B12040423");
18         Iterator it = list.iterator();
19         while (it.hasNext()) {
20             String str = (String) it.next();
21             if (str.equals("xiaoysec")) {
22                 str = "xiaoy";
23                 // list.add("nanjing"); 在iterator作用范围内不能改变集合中的元素
24             }
25             System.out.println(str);
26         }
27 
28     }
29     /**
30      * 下面的測試方法證明了java中的泛型只是针对编译时有效
31      * 通过反射可以绕过泛型的限制
32     */
33     @Test
34     public void test2() {
35         ArrayList<String> list2 = new ArrayList<String>();
36         list2.add("XIAOYSEC");
37         list2.add("12040423");
38         for(String str:list2){
39             System.out.println(str);
40         }
41         System.out.println("-----------------");
42         try {
43             Class c = list2.getClass();
44             Method m = c.getMethod("add", Object.class);  // public boolean add(E e) 
45             m.invoke(list2, 12);  //传入的参数是12 int类型而非String类型
46             Iterator it = list2.iterator();
47             while (it.hasNext()) {
48                 System.out.println(it.next());
49             }
50         } catch (Exception e) {
51             // TODO Auto-generated catch block
52             e.printStackTrace();
53         }
54         
55 
56     }
57 
58 }
View Code

可以看到通过反射可以绕过泛型的限制,也就是说Java泛型是在编译阶段起作用在运行时不会产生限制。

原文地址:https://www.cnblogs.com/xiaoysec/p/4247830.html