java反射

一:类的加载

当类被执行的时候,如果该类的没有被执行的话,该类会被系统通过加载、连接、初始化三个步骤加载到内存中。

1、加载  类加载到内存的时候,将Class文件加载到内存中,并为其创建一个class  file对象。----由类加载器完成。class文件不等于 Class对象,Class对象也叫做字节码对象。

    任何类型被使用的时候都会创建一个Class file对象。

2、连接   ----由类加载器完成

       1)验证类的结构正确性。(成员变量、结构等).

       2)为静态成员分配内存和初始化默认值。分配到方法区的共享数据区域。

      3)将类的二进制数据引用转换成直接引用(就是比如:a=1  实际类加载到内存之后,a不存在只存在1的引用变为直接引用。)

3、初始化

     创建对象,在使用new的时候,会调用类的构造方法和以及成员变量。

二:类被加载到内存和初始化时机(如下情景:)

1、创建类的实例

2、类的静态变量、或者静态变量赋值

3、类的静态方法

4、使用反射方式来强制创建某个类的或者接口的对象的java.lang.Class对象

5、初始化某个类的子类,在初始化子类的时候,优先执行父类的,并将父类加载到内存中

6、直接使用java命令执行某个主类。

三:类加载器

1、作用:负责将类的class文件加载到内存中,并为之生成Class对象。

2、分类

    1)根加载器(bootstarp  Classloader):

         也被称为引导加载器,负责java核心类的加载,比如说:String、int等,加载jre中lib的rt.jar.

   2)扩展加载器(extension Classloader)

        负责加载JRE加载lib目录的etx目录。

   3)系统加载器(System Classloader)

       负责加载JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径(也就是自定义的类的class文件。)

四:反射

   java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够使用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能叫做java的

反射机制。

   场景:

         我们在写日常工程的时候,经验会遇到一个问题,原有的class因为功能的不完整问题,需要我们重新写一些方法,在不改动原先的class的代码结构的情况下,使用java的反射技术

来解剖新的类,通过Class对象(字节码对象)来调用新的类的是一个不错的新的方法!

 五:获取class文件对象。

1、通过对象获取

通过Object的getclass获取执行类对象。

Class<?> getClass()

Returns the runtime class of this Object.

2、通过类的属性获取

所有类都有一个属性.class

3、通过Class文件的ForName获取。

通过Class的静态方法forName("类的全路径")

 1 package com.jd.refect;
 2 
 3 public class Get_Class {
 4     public  static void  main(String ... args)throws  ClassNotFoundException{
 5         //通过父类Object.getClass 获取Class对象。
 6         Person person=new Person();
 7         Class  c=person.getClass();
 8         System.out.println(c);
 9         //通过类的.class属性获取当前Class对象。
10         Class c1=Person.class;
11         System.out.println(c1);
12         //通过Class类的静态方法ForNmame获取Class对象。(注意参数是类的全路径)
13         Class c2= Class.forName("com.jd.refect.Person");
14         System.out.println(c2);
15         //c  c1 c2三个对象是一个,类加载到内存只有一次。
16         if(c==c1 && c==c2){
17            System.out.println("equal");//内存地址比较
18         }
19         if(c.equals(c2)&& c.equals(c1)){
20             System.out.println("equal");
21         }
22     }
23 }

 六:获取constructor对象

 1 package com.jd.refect;
 2 
 3 
 4 import java.lang.reflect.Constructor;
 5 
 6 public class Get_Class {
 7     public  static void  main(String ... args)throws  Exception{
 8         //通过父类Object.getClass 获取Class对象。
 9         Person person=new Person();
10         Class  c=person.getClass();
11         System.out.println(c);
12         //通过类的.class属性获取当前Class对象。
13         Class c1=Person.class;
14         System.out.println(c1);
15         //通过Class类的静态方法ForNmame获取Class对象。(注意参数是类的全路径)
16         Class c2= Class.forName("com.jd.refect.Person");
17         System.out.println(c2);
18         //c  c1 c2三个对象是一个,类加载到内存只有一次。
19         if(c==c1 && c==c2){
20            System.out.println("equal");//内存地址比较
21         }
22         if(c.equals(c2)&& c.equals(c1)){
23             System.out.println("equal");
24         }
25         /*
26         获取Person类的构造方法。
27         通过Class方法Constructor<?>[]     getConstructors()
28                         Returns an array containing Constructor objects reflecting all the public constructors of the class represented by this Class object.
29                         返回Constructor[]
30                         只返回有公共权限的constructor。(只有public修饰权限的构造方法)
31          */
32         Class  c3=Class.forName("com.jd.refect.Person");
33         Constructor[] cons=c3.getConstructors();//返回Constructor[]
34         for(Constructor con:cons){
35             System.out.println(con);
36         }
37         /*
38          上面方法获取的constructor的数组。
39          获取指定constructor
40          获取无参constructor
41          */
42         Constructor con1=c3.getConstructor();
43         System.out.println(con1);
44         /*获取有参数的构造方法
45         Constructor<T>     getConstructor(Class<?>... parameterTypes)
46         参数是构造方法需要的参数列表类型。
47         参数需要传入类名.class
48         通过constructor的方法构造对象
49         T     newInstance(Object... initargs)
50         参数是动态的参数。
51         Uses the constructor represented by this Constructor object to create and
52         initialize a new instance of the constructor's declaring class, with the specified
53          */
54         Constructor con2=c3.getConstructor(int.class,String.class);
55         Object  obj=con2.newInstance(2,"小红");
56         System.out.println(con2);
57         System.out.println(obj);
58     }
59 }

 快捷创建实例化对象:

     类需要具备如下特性:

  1、无参构造方法

  2、public 修饰的构造方法。

 1         /*
 2           快捷方式
 3           上述方法是需要创建constructor对象然后调用newstance方法。
 4           使用快捷方法需要该类具备如下条件:
 5           1、必须要有空参构造方法。
 6           2、该构造方法需要public权限。
 7           直接调用Class.newstance() 无参
 8           T     newInstance()
 9                 Creates a new instance of the class represented by this Class object.
10          */
11           Object obj1=c3.newInstance();
12           System.out.println(obj1);

 获取私有构造方法(不推荐使用,这样获取,破坏了类的封装性。)

 1           /*
 2           对于私有构造方法如何获取?
 3           暴力反射(不推荐使用)
 4           getdeclaredconstructors()返回所有的构造方法,无论是public还是private。
 5           返回是constructor[]
 6            */
 7           Constructor[]  con3=c1.getDeclaredConstructors();
 8           for(Constructor con:con3){
 9               System.out.println(con);
10           }
11           /*
12           获取私有的构造方法
13           getDeclaredConstructor()方法获取
14           public void  setAccessible(Boolean flag)解锁该私有方法的权限限制。即会直接越过私有权限。
15            */
16           Constructor con4=c3.getDeclaredConstructor(String.class,int.class);
17           con4.setAccessible(true);
18           Object obj4=con4.newInstance("xxx",2);
19           System.out.println(obj4);

 获取字段和方法并执行方法

 1           /*
 2            获取类的字段。
 3            使用Class类的
 4            Field[] getFields()只能获取公共权限的成员 private字段无法获取。
 5            */
 6         Field[] filed=c3.getFields();
 7         for(Field f:filed){System.out.println(f);};
 8         /*
 9         获取指定成员变量
10         Field     getField(String name)  只能获取公共权限的成员 private字段无法获取。String name 字段名称
11         设置字段值。调用Field的set方法。
12         void     set(Object obj, Object value) 第一个参数需要传入该类的对象 因为person类有空参。
13 
14         第二个参数需要传入设置的值 类型需要和person类的类型一致。
15         Object     get(Object obj) 获取值的方法。
16         参数为Person类的对象。
17          */
18         Field f=c3.getField("age");
19         System.out.println(f);
20         Object per=c3.newInstance();
21         f.set(per,2);
22         System.out.println(f.get(per));
23         /*
24         获取私有变量。
25        使用
26        Field     getDeclaredField(String name)
27        String name 为获取参数的字符串值。
28        需要设置:setAccessible(true);
29        获取数组使用Field[]     getDeclaredFields()
30          */
31         Field f1=c3.getDeclaredField("addr");
32         f1.setAccessible(true);
33         Object obj3=c3.newInstance();//空参构建实例对象。
34         f1.set(obj3,"北京");
35         System.out.println(f1.get(obj3));
36         /*
37         获取成员方法。
38         Method[]     getMethods()
39         获取person类的所有公共成员方法。也包含继承的方法。
40          */
41         Method[] method=c3.getMethods();
42         for(Method me:method) {
43             System.out.println(me);
44         }
45         /*
46         获取指定方法。
47         Method     getMethod(String name, Class<?>... parameterTypes)
48         第一个参数方法名字,第二个是参数列表,因为一个方法可能重载。
49         方法执行:
50         Object     invoke(Object obj, Object... args)
51         第一个参数person类对象  第二参数为动态的参数。
52         获取私有方法同样:
53         Method     getDeclaredMethod(String name, Class<?>... parameterTypes)
54          */
55         Method me1=c3.getMethod("eat",String.class);
56         Object obj5=c3.newInstance();
57         me1.invoke(obj5,"打炮!");

 六:通过配置文件的配置 经过反射的查找对应的类和方法。

 1 package ref_con.config;
 2 
 3 import java.io.InputStream;
 4 import java.lang.reflect.Method;
 5 import java.util.Properties;
 6 
 7 public class config_ref {
 8     /*
 9     通过配置文件灵活的配置。使用反射来进行获取和执行类的对象。
10      */
11     public  static  void  main(String ... args)throws  Exception{
12         InputStream inp=config_ref.class.getClassLoader().getResourceAsStream("config.properites");
13         Properties pro=new Properties();
14         pro.load(inp);
15         inp.close();
16         String classname=pro.getProperty("ClassNmame");
17         String method=pro.getProperty("Method");
18         Class person=Class.forName(classname);
19         Method  method1=person.getMethod(method);
20         Object obj=person.newInstance();
21         method1.invoke(obj);
22 
23     }
24 
25 }

配置文件:

1 ClassNmame=ref_con.config.Person
2 Method=playGames

person类:

 1 package ref_con.config;
 2 
 3 
 4 
 5 public class Person {
 6     public int age;
 7     public  String name;
 8     private  String addr;
 9     public  Person(){}
10     public  Person(int age,String name){
11         this.name=name;
12         this.age=age;
13     }
14     private Person( String name,int age){
15         this.age=age;
16         this.name=name;
17         this.addr=addr;
18     }
19     public String getName() {
20         return this.name;
21     }
22     public int  getAge(){
23         return this.age;
24     }
25 
26     public void setAge(int age) {
27         this.age = age;
28     }
29 
30     public void setName(String name) {
31         this.name = name;
32     }
33 
34     @Override
35     public String toString() {
36         return this.name+" "+this.age+' ';
37     }
38 
39     public String getAddr() {
40         this.addr=addr;
41         return this.addr;
42     }
43 
44     public void setAddr(String addr) {
45         this.addr = addr;
46     }
47     public  void  eat(){
48         System.out.println("吃饭");
49     }
50     public  void  eat(String a){
51         System.out.println("吃饭"+a);
52     }
53     public  void  playGames(){
54         System.out.println(" we are playing baskball!");
55     }
56 }
原文地址:https://www.cnblogs.com/evilliu/p/8507729.html