关于JAVA反射机制的学习

 

关于JAVA反射机制的学习

1、基本概念:反射机制(比较简单,因为只要会查帮助文档,就可以了。)

2.1、反射机制有什么用?
通过java语言中的反射机制可以操作字节码文件。
优点类似于黑客。(可以读和修改字节码文件。)
通过反射机制可以操作代码片段。(class文件。)

2.2、反射机制的相关类在哪个包下?
  java.lang.reflect.*;

2.3、反射机制相关的重要的类有哪些?

java.lang.Class:代表整个字节码,代表一个类型,代表整个类。

java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。

java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法

java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。

java.lang.Class:
    public class User{
  // Field
       int no;

 // Constructor
       public User(){

         }
      public User(int no){
          this.no = no;
 }

 // Method
      public void setNo(int no){
              this.no = no;
    }
      public int getNo(){
        return no;
  }
}

3、关于JDK中自带的类加载器:(聊一聊,不需要掌握,知道当然最好!)
3.1、什么是类加载器?
专门负责加载类的命令/工具。
ClassLoader

3.2、JDK中自带了3个类加载器
启动类加载器:rt.jar
扩展类加载器:ext/*.jar
应用类加载器:classpath

3.3、假设有这样一段代码:


String s = "abc";

代码在开始执行之前,会将所需要类全部加载到JVM当中。
通过类加载器加载,看到以上代码类加载器会找String.class
文件,找到就加载,那么是怎么进行加载的呢?

首先通过“启动类加载器”加载。
注意:启动类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar
rt.jar中都是JDK最核心的类库。

如果通过“启动类加载器”加载不到的时候,
会通过"扩展类加载器"加载。
注意:扩展类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\*.jar


如果“扩展类加载器”没有加载到,那么
会通过“应用类加载器”加载。
注意:应用类加载器专门加载:classpath中的类。


3.4、java中为了保证类加载的安全,使用了双亲委派机制

优先从启动类加载器中加载,这个称为“父”
“父”无法加载到,再从扩展类加载器中加载,
这个称为“母”。双亲委派。如果都加载不到,
才会考虑从应用类加载器中加载。直到加载
到为止。

1、回顾反射机制

1.1、什么是反射机制?反射机制有什么用?
反射机制:可以操作字节码文件
作用:可以让程序更加灵活。

1.2、反射机制相关的类在哪个包下?
java.lang.reflect.*;

1.3、反射机制相关的主要的类?
java.lang.Class
java.lang.reflect.Method;
java.lang.reflect.Constructor;
java.lang.reflect.Field;

1.4、在java中获取Class的三种方式?
第一种:
Class c = Class.forName("完整类名");
第二种:
Class c = 对象.getClass();
第三种:
Class c = int.class;
Class c = String.class;

 1 /**
 2  * 反射
 3  * 要操作一个类的字节码,首先要获取这个类的字节码,怎么获取java.lang.Class实例
 4  * 三种方式
 5  * @author yumu
 6  *
 7  */
 8 public class ReflectTest01 {
 9 
10     public static void main(String[] args) throws ClassNotFoundException {
11         /*
12          * 1.第一种 Class.forName()
13          * Class.forName(0
14          *   1.静态方法
15          *   2.方法的参数是一个字符串
16          *   3.字符串需要一个完整类名
17          *   4.完整类名必须带有包名
18          */
19             Class c1=Class.forName("java.lang.String");
20             Class c2=Class.forName("java.util.Date");
21             Class c3=Class.forName("java.lang.Integer");
22             Class c4=Class.forName("java.lang.System");
23             
24         //第二种 java中任何一个对象都有一个方法:getClass()
25             String s="abc";
26             Class x=s.getClass();//x代表String.class字节码文件,x代表String类型
27             System.out.println(c1==x);  //true
28             
29             Date time=new Date();
30             Class d=time.getClass();
31             System.out.println(c2==d);  //true
32             
33         //第三种 java语言任何一种类型,包括基本数据类型,它都有.class属性
34             Class z=String.class;  //z代表String类型
35             Class k=Date.class;    //k代表Date类型
36             Class f=int.class;     //f代表int类型
37             Class e=double.class;   //e代表double类型
38             
39             System.out.println(x==z);  //true
40             System.out.println(k==d);        
41     }
42 
43 }

 

1.5、获取了Class之后,可以调用无参数构造方法来实例化对象

//c代表的就是日期Date类型
Class c = Class.forName("java.util.Date");

//实例化一个Date日期类型的对象
Object obj = c.newInstance();

一定要注意:
newInstance()底层调用的是该类型的无参数构造方法。
如果没有这个无参数构造方法会出现"实例化"异常。

 

 

  验证反射机制的灵活性

 1 /**
 2  * 验证反射机制的灵活性
 3  *   java代码写一遍,再不改变java源代码的基础上,可以做到不同对象的实例化
 4  * @author yumu
 5  *
 6  */
 7 public class ReflectTest03 {
 8 
 9     public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
10         //通过IO流读取classinfo.properties文件
11         FileReader reader=new FileReader("classinfo.properties");
12         //创建属性类对象Map
13         Properties pro=new  Properties();
14         //加载
15         pro.load(reader);
16         //关闭流
17         reader.close();
18          
19         //通过key获取value
20         //配置文件的改变会实例不同的对象
21         String className = pro.getProperty("className");
22         //通过反射机制实例化对象
23         Class c=Class.forName(className);
24         Object obj=c.newInstance();
25         System.out.println(obj);
26         
27     }
28 
29 }

 

1.6、如果你只想让一个类的“静态代码块”执行的话,你可以怎么做?
     Class.forName("该类的类名");
    这样类就加载,类加载的时候,静态代码块执行!!!!
    在这里,对该方法的返回值不感兴趣,主要是为了使用“类加载”这个动作。


1.7、关于路径问题?

String path = Thread.currentThread().getContextClassLoader()
.getResource("写相对路径,但是这个相对路径从src出发开始找").getPath();

String path = Thread.currentThread().getContextClassLoader()
.getResource("com/bjpowernode/test.properties").getPath();
//必须保证src下有com目录,com目录下有bjpowernode目录。
//bjpowernode目录下有test.properties文件。

这种方式是为了获取一个文件的绝对路径。(通用方式,不会受到环境移植的影响。)
但是该文件要求放在类路径下,换句话说:也就是放到src下面。
src下是类的根路径。

直接以流的形式返回:
InputStream in = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/bjpowernode/test.properties");

 1 public class ReflectTest05 {
 2 
 3     public static void main(String[] args) throws IOException {
 4         //上面学的路径移植性太差 ,
 5         //接下来说一种通用的方式
 6         //注意:以下方法的前提,这个文件必须在类路径下
 7         //src是类的根路径
 8         /*
 9          * 解释:
10          * Thread.currentThread() 当前线程对象
11          * getContextClassLoader() 是线程对象方法,可以获取当前线程的类加载器对象
12          * getResource [获取资源] 这是类加载器对象的方法,当前线程的类加载器默认从当前类的根路径下加载资源
13          */
14         //这是一个获取文件的绝对路径
15         //String path = Thread.currentThread().getContextClassLoader().getResource("classinfo.properties").getPath();
16         //FileReader reader =new FileReader(path);
17         //System.out.println(path);
18         //这是一种直接以流的形式获取
19         InputStream reader =Thread.currentThread().getContextClassLoader().getResourceAsStream("classinfo.properties");
20         
21         Properties pro = new Properties();
22         pro.load(reader);
23         reader.close();
24         String className = pro.getProperty("className");
25         System.out.println(className);
26     
27     
28     }
29 
30 }

 

1.8、IO + Properties,怎么快速绑定属性资源文件?

//要求:第一这个文件必须在类路径下
//第二这个文件必须是以.properties结尾。
ResourceBundle bundle = ResourceBundle.getBundle("com/bjpowernode/test");
String value = bundle.getString(key);

 1 /**
 2  * java.util包下提供了一个资源绑定器,便于获取属性文件中的内容
 3  * 使用以下方法,属性配置文件xxx.properties必须放到类路径下
 4  * 并且,写路径的时候,路径下面的扩展名不写
 5  * @author yumu
 6  *
 7  */
 8 public class ResourceBundleTest01 {
 9 
10     public static void main(String[] args) {
11         ResourceBundle bundle=ResourceBundle.getBundle("classinfo");
12         String str = bundle.getString("className");
13         System.out.println(str);
14     }
15 
16 }

 

2、今日反射机制的重点内容
2.1、通过反射机制访问对象的某个属性。

 1 /**
 2  * 必须掌握:
 3  *    怎么通过反射机制访问一个java对象的属性?
 4  *     给属性赋值,
 5  *     获取属性的值get
 6  * @author yumu
 7  *
 8  */
 9 public class ReflectTest08 {
10 
11     public static void main(String[] args) throws Exception {
12         //不使用反射机制,怎么去访问一个对象的属性
13         Student s=new Student();
14         s.no=100;
15         System.out.println(s.no);
16         
17         //使用反射机制
18         Class studentClass=Class.forName("javase.bean.Student");
19         Object obj = studentClass.newInstance();
20         //获取属性  靠名字气氛
21         Field field = studentClass.getDeclaredField("no");
22         /*
23          * 虽然是反射机制,但三要素还是一样  
24          *  要素1:obj对象
25          *  要素2:no属性
26          *  要素3:222值
27          * 注意:反射机制让代码复杂了,但更灵活,这也是值了
28          * 
29          */
30         //设置属性值
31         field.set(obj, 22222);
32         //获取属性值
33         System.out.println(field.get(obj));
34         
35         //可以访问私有的属性吗
36         Field nameField = studentClass.getDeclaredField("name");
37         //打破封装(反射机制的缺点)
38         //这样留下安全隐患.外部可以访问private
39         nameField.setAccessible(true);
40         nameField.set(obj, "zhangsan");
41         System.out.println(nameField.get(obj));
42         
43     }
44 
45 }

 

2.2、通过反射机制调用对象的某个方法。

 1 /**
 2  * 重点:通过反射机制调方法
 3  * @author yumu
 4  *
 5  */
 6 public class ReflectTest10 {
 7 
 8     /**
 9      * @param args
10      * @throws Exception
11      */
12     /**
13      * @param args
14      * @throws Exception
15      */
16     public static void main(String[] args) throws Exception {
17         //不使用反射机制,怎么调用方法
18         UserService UserService=new UserService();
19         boolean login = UserService.login("admin", "1213");
20         //System.out.println(login ? "登录成功":"登录失败");
21         
22         //使用反射机制来调用一个对象的方法
23         Class UserServiceClass=Class.forName("javase.service.UserService");
24         
25         //创建对象
26         Object obj=UserServiceClass.newInstance();
27         //获取Method
28         @SuppressWarnings("unchecked")
29         Method loginMethod=UserServiceClass.getDeclaredMethod("login",String.class,String.class);
30         //调用方法有4要素
31         //反射机制中最最最重要的内容,必须记住
32         /*
33          * 四要素:
34          * loginMethod方法
35          * opbj对象
36          * "admin","123"实参
37          * returnValue 返回值
38          */
39         Object returnValue = loginMethod.invoke(obj, "admin","123");
40         System.out.println(returnValue);
41     }
42 
43 }

2.3、通过反射机制调用某个构造方法实例化对象。

 1 public class ReflectTest12 {
 2 
 3     public static void main(String[] args) throws Exception{
 4         //不使用反射机制怎么创建对象
 5         Vip v1=new Vip();
 6         Vip v2=new Vip(110,"张三","20200-10-10",true);
 7         System.out.println(v2);
 8         
 9         //使用反射机制怎么创建对象
10         Class c=Class.forName("javase.bean.Vip");
11         //调用无参数构造方法
12         Object obj=c.newInstance();
13         //调用有参数构造方法
14         //第一步,先获取有参数构造方法
15         Constructor con = c.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
16         Object obj1 = con.newInstance(110,"masan","1999-7-2",false);
17         System.out.println(obj1);
18         
19         
20     }
21 
22 }

2.4、通过反射机制获取父类以及父类型接口。

 

 1 /**
 2  * 重点:获取父类,以及父类实现的接口
 3  * @author yumu
 4  *
 5  */
 6 public class ReflectTest13{
 7 
 8     public static void main(String[] args) throws Exception {
 9         //String 类举例
10         Class stringClass=Class.forName("java.lang.String");
11         //获取String父类
12         Class superClass=stringClass.getSuperclass();
13         System.out.println(superClass);
14         
15         //获取String类实现的所有接口
16         Class [] interfaces =stringClass.getInterfaces();
17         for(Class in : interfaces){
18             System.out.println(in.getName());
19             
20         }
21         System.out.println("-------------");
22         System.out.println(interfaces);
23     }
24 
25 }

 

了解:

1.反编译一个类的属性field

 1 **
 2  * 反射机制
 3  *  反编译一个类的属性field
 4  * @author yumu
 5  *
 6  */
 7 public class ReflectTest07 {
 8 
 9     public static void main(String[] args) throws ClassNotFoundException {
10         StringBuilder sb=new StringBuilder();
11         //获取整个类
12         Class studentClass=Class.forName("javase.bean.Student");
13         //                                       修饰符                                                                                                 //类名                       
14         sb.append(Modifier.toString(studentClass.getModifiers())+" "+"class"+" "+studentClass.getSimpleName()+"{"+"\n");
15         //获取所有元素
16         Field[] fields=studentClass.getDeclaredFields();
17         for(Field field:fields){
18             sb.append("\t");
19             //权限修饰符
20             sb.append(Modifier.toString(field.getModifiers()));
21             sb.append(" ");
22             //数据类型
23             sb.append(field.getType().getSimpleName());
24             sb.append(" ");
25             //数据名
26             sb.append(field.getName());
27             sb.append(";\n");
28         }
29         sb.append("}");
30         System.out.println(sb);
31         
32     }
33 
34 }
反编译一个类的属性field

2.反编译 Method

 1 /**
 2  * 反编译 Method
 3  * @author yumu
 4  *
 5  */
 6 public class ReflectTest09{
 7 public static void main(String[] args) throws Exception {
 8     StringBuilder s=new StringBuilder();
 9     //获取类
10     Class UserServiceClass =Class.forName("java.lang.String");
11     //                                        修饰符                                                                  //类名
12     s.append(Modifier.toString(UserServiceClass.getModifiers())+"class"+UserServiceClass.getSimpleName()+"\n");
13     //获取所有的Method 包括私有的
14     Method[] methods=UserServiceClass.getDeclaredMethods();
15     //遍历Method
16     for(Method method:methods){
17         s.append("\t");
18         //获取修饰符列表
19         s.append(Modifier.toString(method.getModifiers()));
20         s.append(" ");
21         //获取返回值类型
22         s.append(method.getReturnType().getSimpleName());
23         s.append(" ");
24         //获取方法名
25         s.append(method.getName());
26         s.append("(");
27         //参数列表
28         Class[] parameterTypes=method.getParameterTypes();
29         for(Class parameterType:parameterTypes){
30             s.append(parameterType.getSimpleName());
31             s.append(",");
32             
33         }
34         //删除字符串最后一个
35         s.deleteCharAt(s.length()-1);
36         s.append("){}\n");
37             
38     }
39     s.append("}");
40     System.out.println(s);
41 }
42 }
反编译 Method

3.反编译一个类的构造方法,costructor

/**
 * 反编译一个类的构造方法,costructor
 * @author yumu
 *
 */
public class ReflectTest11{

    public static void main(String[] args) throws Exception{
        StringBuilder s=new StringBuilder();
        Class vipClass=Class.forName("javase.bean.Vip");
        s.append(Modifier.toString(vipClass.getModifiers())+" ");
        s.append("class ");
        s.append(vipClass.getSimpleName());
        s.append("{\n");
        //拼接构造方法
        //public Vip(int no, String name, String birth, boolean sex) {
        Constructor[] constructors = vipClass.getDeclaredConstructors();
        for(Constructor constructor:constructors){
            s.append("\t");
            s.append(Modifier.toString(constructor.getModifiers()));
            s.append(" ");
            s.append(vipClass.getSimpleName());
            s.append("(");
            //拼接参数
            Class[] paramenterTypes=constructor.getParameterTypes();
            for(Class paramenterType:paramenterTypes){
                s.append(paramenterType.getSimpleName());
                s.append(",");
                
            }
            if(paramenterTypes.length>0){
                s.deleteCharAt(s.length()-1);
            }
            
            s.append("){}\n");
            
        }
        
        s.append("}");
        
        System.out.println(s);
    }

}
反编译一个类的构造方法,costructor

 

posted @ 2020-10-24 14:10    阅读(137)  评论(0编辑  收藏  举报