反射(未完待续)

反射

反射机制(比较简单,由于只要会查帮助文档,就能够了。)

反射的概述

  • 反射机制有什么用?java

    • 经过java语言中的反射机制能够操做字节码文件。优势相似于黑客。(能够读和修改字节码文件。)经过反射机制能够操做代码片断。(class文件。)
  • 反射机制的相关类在java.lang.reflect.*;包下。数组

  • 反射机制相关的重要的类有哪些?安全

    • java.lang.Class:表明整个字节码,表明一个类型,表明整个类。工具

    • java.lang.reflect.Method:表明字节码中的方法字节码。表明类中的方法。测试

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

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

    • 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;
      	}
      }

```

获取Class的三种方式

  • 要操做一个类的字节码,须要首先获取到这个类的字节码,获取java.lang.Class实例的三种方式。
    • 第一种方式:Class c = Class.forName("完整类名带包名")
    • 第二种方式:Class c = 对象.getClass();
    • 第三种方式:Class c = 任何类型.class;
public class ReflectTest01 {
    public static void main(String[] args) {
        /*
        Class.forName()
            1.静态方法
            2.方法的参数是一个字符串
            3.字符串须要的是一个完整的类名
            4.完整类名必须带有包名。java.lang包也不能省。
         */
        Class c1 = null;
        Class c2 = null;
        try {
            c1 = Class.forName("java.lang.String");//c1表明String.class文件,或者说C1表明String类型
            c2 = Class.forName("java.util.Date");//c2表明Date类型
            Class c3 = Class.forName("java.lang.Integer");//c3表明Integer类型
            Class c4 = Class.forName("java.lang.System");//c4表明System类型
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
//        Java中任何一个对象都有一个方法:getClass()
        String s = "abc";
        Class x = s.getClass();//x表明String.class字节码文件,x表明String类型
        System.out.println(c1 == x);//true (==判断的是对象的内存地址)

        Date time = new Date();
        Class y = time.getClass();
        System.out.println(c2 == y);//true(c2和y两个变量中保存的内存地址都是同样的,都指向方法区中的字节码文件)

//        第三种方式,Java语言中任何一种类型,包括基本数据类型,它都有.class属性。
        Class z = String.class;//z表明String类型
        Class k = Date.class;//k表明Date类型
        Class f = int.class;//f表明int类型
        Class e = double.class;//e表明double类型
        System.out.println(x == z);//true
    }
}

经过反射实例化对象

  • 经过ClassnewInstance()方法来实例化对象
  • 注意:newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造存在才能够。
  • 反射机制的灵活性,Java代码写一遍,在不改变Java源代码的基础上,能够作到不一样对象的实例化,很是灵活。(符合OCP开闭原则:对扩展开放,对修改关闭)
public class ReflectTest02 {
    public static void main(String[] args) {
//        这是不使用反射机制建立对象
        User user = new User();
        System.out.println(user);

//        下面这段代码是以反射机制的方式建立对象。
        try {
//            经过反射机制,获取Class,经过Class来实例化对象。
            Class c = Class.forName("com.yang.javaSE进阶.反射.bean.User");//c表明User类型
//            newInstance()这个方法会调用User这个类的无参数构造方法,完成对象的建立
//            重点是:newInstance()调用的是无参构造,必须保证无参构造器是存在的
            Object obj = c.newInstance();
            System.out.println(obj);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}
public class User {
    public User() {
        System.out.println("无参构造方法!");
    }
}

只让静态代码块执行

  • 记住(重点):若是只是但愿一个类的静态代码块执行,其它代码一概不执行。可使用:Class.forName("完整类名");这个方法的执行会致使类加载,类加载时,静态代码块执行。
  • 提示:后面JDBC技术的时候咱们还须要.
public class ReflectTest03 {
    public static void main(String[] args) {
        try {
//            Class.forName()这个方法的执行会致使类加载
            Class.forName("com.yang.javaSE进阶.反射.bean.MyClass");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
public class MyClass{
    //    静态代码块在类加载时执行,而且只执行一次。
    static{
        System.out.println("MyClass类的静态代码块执行了!");
    }
}

JDK中自带的类加载器(不须要掌握,知道固然最好!)

  • 什么是类加载器?专门负责加载类的命令/工具。ClassLoader
  • JDK中自带了3个类加载器
    • 启动类加载器:rt.jar
    • 扩展类加载器:ext/*.jar
    • 应用类加载器:classpath
  • 假设有这样一段代码:String s = "abc";
    • 代码在开始执行以前,会将所须要类所有加载到JVM当中。经过类加载器加载,看到以上代码类加载器会找String.class文件,找到就加载,那么是怎么进行加载的呢?
      • 首先经过“启动类加载器”加载。注意:启动类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jarrt.jar中都是JDK最核心的类库。
      • 若是经过“启动类加载器”加载不到的时候,会经过"扩展类加载器"加载。注意:扩展类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\*.jar
      • 若是“扩展类加载器”没有加载到,那么会经过“应用类加载器”加载。注意:应用类加载器专门加载:classpath中的类。
  • java中为了保证类加载的安全,使用了双亲委派机制。优先从启动类加载器中加载,这个称为“父”,“父”没法加载到,再从扩展类加载器中加载,这个称为“母”。双亲委派。若是都加载不到,才会考虑从应用类加载器中加载。直到加载到为止。

获取反射属性Field

  • 反射Field类中全部的Field
public class ReflectTest04 {
    public static void main(String[] args) throws Exception {
//        获取整个类
        Class studentClass = Class.forName("com.yang.javaSE进阶.反射.bean.Student");
//        获取类中全部的Field
        Field[] fields = studentClass.getFields();
        System.out.println(fields.length);//测试数组中只有一个元素
//        取出这个Field
        Field f = fields[0];
//        取出这个Field的名字
        String fieldName = f.getName();
        System.out.println(fieldName);
//        获取全部的Field
        Field[] fs = studentClass.getDeclaredFields();
        System.out.println(fs.length);
//        遍历
        for (Field field : fs) {
//            获取属性的修饰符
            int i = field.getModifiers();//返回的修饰符是一个数字,每一个数字是修饰符的代号!
            System.out.println(i);
//            能够将这个“代号”数字转换成“字符串”
            String modifierString = Modifier.toString(i);
            System.out.println(modifierString);
            //            获取属性的类型
            Class fieldType = field.getType();
//            String fName = fieldType.getName();
            String fName = fieldType.getSimpleName();
            System.out.println(fName);
//            获取属性的名字
            System.out.println(field.getName());
        }
    }
}
public class Student {
    //    Field翻译为字段,其实就是属性/成员
//    4个Field,分别使用了不一样的访问控制权限修饰符
    public int no;
    private String name;
    protected int age;
    boolean sex;
    public static final double MATH_PI = 3.1415926;
}

反编译Field

相关文章
相关标签/搜索