Java帮帮-IT资源分享网 
  
  
   
    
     
      十二、黑马程序员—反射机制 
     
     
    
     1、反射的概念
     
    
     反射的引入:
     
    
     Object obj = new Student();
     
    
     若程序运行时接收到外部传入的一个对象,该对象的编译类型是 Object,但程序又
     
    
     需要调用该对象运行类型的方法:
     
    
     1.若编译和运行类型都知道,使用 instanceof 判断后,强转。
     
    
     2.编译时根本无法预知该对象属于什么类,程序只能依靠运行时信息来发现对象的
     
    
     真实信息,这时就必须使用反射了。
     
    
     3.要是想得到对象真正的类型,就得使用反射。
     
    
     什么是反射机制?
     
    
     简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在 java 中,只要给
     
    
     定类的名字,那么就可以通过反射机制来获得类的所有信息。
     
    
     反射机制的优点与缺点:
     
    
     为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,
     
    
     静态编译:在编译时确定类型,绑定对象,即通过。
     
    
     动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了 java 的灵活性,体
     
    
     现了多态的应用,有以降低类之间的藕合性。
     
    
     一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特
     
    
     别是在 J2EE 的开发。
     
    
     它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉 JVM,我
     
    
     们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
     
    
     Class 类和 Class 类实例
     
    
     Java 程序中的各个 Java 类属于同一类事物,描述这类事物的 Java 类就是 Class 类。
     
    
     对比提问:众多的人用一个什么类表示?众多的 Java 类用一个什么类表示?
     
    
     人 Person
     
    
     Java 类 Class
     
    
     对比提问: Person 类代表人,它的实例对象就是张三,李四这样一个个具体的人,Class
     
    
     类代表 Java 类,它的各个实例对象又分别对应什么呢?
     
    
     对应各个类在内存中的字节码,例如,Person 类的字节码,ArrayList 类的字节码,等等;
     
    
     一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节
     
    
     码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的;
     
       
     
    
     用类来描述对象,类:描述数据的结构
     
    
     用元数据来描述 Class,MetaData(元数据):描述数据结构的结构;
     
    
     反射就是得到元数据的行为;
     
    
     备注:一个类在虚拟机中只有一份字节码;
     
       
     
    
     
2、获得 Class 对象
     
    
     如何得到各个字节码对应的实例对象?
     
    
     每个类被加载后,系统会为该类生成对应的 Class 对象,通过 Class 对象可以访问到 JVM 中
     
    
     的这个类,
     
    
     3 种方式:
     
    
     1、调用某个类的 class 属性获取 Class 对象,如 Date.class 会返回 Date 类对应的 Class
     
    
     对象(其实就是得到一个类的一份字节码文件);
     
    
     2、使用 Class 类的 forName(String className)静态方法,className 表示全限定名;如
     
    
     String 的全限定名:java.lang.String;
     
    
     3、调用某个对象的 getClass()方法。该方法属于 Object 类;
     
    
     Class<?> clz = new Date().getClass();
     
    
     Eg:
     
    
     package junereflect624;
     
    
     public class ClassDemo1 {
     
    
     public static void main(String[] args) throws Exception {
     
    
     //获得Class对象的方法(三种)
     
    
     //一:调用属性
     
    
     Class<String> c = String.class;
     
    
     System.out.println(c);// 打 印 结 果 : class java.lang.String
     
    
     String.class就表示JVM中一份表示String类的字节码
     
    
     Class<String> c2 = String.class;
     
    
     System.out.println(c == c2);//true都是String类的字节码
     
    
     一个类在虚拟机中只有一份字节码;
     
    
     //二:使用forName()方法
     
    
     //Class cla = Class.forName("String");//ERROR,
     
    
     Class<String> cla =
     
    
     (Class<String>)Class.forName("java.lang.String");// 必 须
     
    
     用上全限定名,否则报错
     
    
     System.out.println(c == cla);//true
     
    
     //三:利用对象调用Object的getClass方法;
     
    
     Class c3 = new String().getClass();
     
    
     System.out.println(c == c3);//ture
     
    
     }
     
    
     }
     
    
     我的总结:获取 Class 对象最常用的是利用属性的方法!
     
       
     
    
     
3、九个预定义 Class 对象
     
    
     基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void
     
    
     通过 class 属性也表示为 Class 对象;
     
    
     Class 类中 boolean isPrimitive() :判定指定的 Class 对象是否表示一个基本类型。
     
    
     包装类和 Void 类的静态 TYPE 字段;
     
    
     Integer.TYPE == int.class ;
     
    
     Integer.class == int.class;
     
    
     数组类型的 Class 实例对象:
     
    
     Class<String[]> clz = String[].class;
     
    
     数组的 Class 对象如何比较是否相等? 数组的维数和数组的类型;
     
    
     Class 类中 boolean isArray() :判定此 Class 对象是否表示一个数组类型。
     
    
     package junereflect624;
     
    
     public class PreClassDemo2 {
     
    
     public static void main(String[] args) {
     
    
     Class<?> in = int.class;
     
    
     System.out.println(in);//int
     
    
     Class<?> in2 = Integer.class;
     
    
     //包装类都有一个常量TYPE,用来表示其基本数据类型的字节码
     
    
     Class<?> in3 = Integer.TYPE;
     
    
     System.out.println(in2);//class java.lang.Integer
     
    
     System.out.println(in3);//int
     
    
     System.out.println(in3 == in);//true 包装类都有一个常量TYPE,用
     
    
     来表示其基本数据类型的字节码,所以这里会相等!
     
    
     System.out.println(in3 == in2);//false
     
    
     Class<String[]> s = String [].class;
     
    
     Class<int[]> i = int [].class;
     
    
     //System.out.println(i ==s);//编译根本就通过不了,一个是int,一个
     
    
     是String
     
    
     }
     
    
     //这两个自定义的方法是可以的,一个int,一个Integer//包装类与基本数据类型
     
    
     的字节码是不一样的
     
    
     public void show(int i){}
     
    
     public void show(Integer i){}
     
    
     }
     
       
     
    
     
4、利用 Class 获取类的属性信息
     
    
     package junereflect624;
     
    
     import java.lang.reflect.Modifier;
     
    
     class A {
     
    
     }
     
    
     interface B{
     
    
     }
     
    
     interface C{
     
    
     }
     
    
     public class BaseDemo3 extends A implements B,C{
     
    
     //内部类
     
    
     public class C{}
     
    
     public interface D{}
     
    
     public static void main(String[] args) {
     
    
     //类可以,接口也可以
     
    
     Class<BaseDemo3> c = BaseDemo3.class;
     
    
     System.out.println(c);//class junereflect624.BaseDemo3
     
    
     //得到包名
     
    
     System.out.println(c.getPackage());//package junereflect624
     
    
     //得到全限定名
     
    
     System.out.println(c.getName());//junereflect624.BaseDemo3
     
    
     //得到类的简称
     
    
     System.out.println(c.getSimpleName());//BaseDemo3
     
    
     //得到父类
     
    
     /**
     
    
     * Class<? super T> getSuperclass() 此处super表示下限
     
    
     返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超
     
    
     类的 Class。
     
    
     */
     
    
     System.out.println(c.getSuperclass().getSimpleName()); //A,
     
    
     先获取父类,再获取父类的简称
     
    
     //得到接口
     
    
     System.out.println(c.getInterfaces());//[Ljava.lang.Class;@1b6
     
    
     0280
     
    
     Class[] arr = c.getInterfaces();
     
    
     for (Class cla : arr) {
     
    
     System.out.println(cla);//interface junereflect624.B
     
    
     interface junereflect624.C
     
    
     }
     
    
     //获得public修饰的类
     
    
     /**
     
    
     * Class<?>[] getClasses()
     
    
     返回一个包含某些 Class 对象的数组,这些对象表示属于此
     
    
     Class 对象所表示的类的成员的所有公共类和接口。 (如果内部类前面没有加上public
     
    
     的话那么得不到!)
     
    
     */
     
    
     Class[] cl = c.getClasses();
     
    
     System.out.println(cl.length);//在内部类没有加上public修饰的时
     
    
     候长度为0,加上就是2(获取的是公共的)
     
    
     for (Class class1 : cl) {
     
    
     System.out.println(class1);
     
    
     }
     
    
     //获得修饰符
     
    
     int i = c.getModifiers();
     
    
     System.out.println(i);//常量值1表示public
     
    
     System.out.println(Modifier.toString(i));//直接打印出public
     
    
     }
     
    
     }
     
       
     
    
     
5、Class 中得到构造方法 Constructor、方法 Method、字段 Field
     
    
     常用方法:
     
    
     Constructor 类用于描述类中的构造方法:
     
    
     Constructor<T> getConstructor(Class<?>... parameterTypes)
     
    
     返回该 Class 对象表示类的指定的 public 构造方法;
     
    
     Constructor<?>[] getConstructors()
     
    
     返回该 Class 对象表示类的所有 public 构造方法;
     
    
     Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
     
    
     返回该 Class 对象表示类的指定的构造方法,和访问权限无关;
     
    
     Constructor<?>[] getDeclaredConstructors()
     
    
     返回该 Class 对象表示类的所有构造方法,和访问权限无关;
     
    
     Method 类用于描述类中的方法:
     
    
     Method getMethod(String name, Class<?> ... parameterTypes)
     
    
     返回该 Class 对象表示类和其父类的指定的 public 方法;
     
    
     Method[] getMethods():
     
    
     返回该 Class 对象表示类和其父类的所有 public 方法;
     
    
     Method getDeclaredMethod(String name, Class<?>... parameterTypes)
     
    
     返回该 Class 对象表示类的指定的方法。和访问权限无关,但不包括继承的方法;
     
    
     Method[] getDeclaredMethods(): 获得类所有的方法,包括公共、保护、默认(包)访问和私
     
    
     有方法,但不包括继承的方法;
     
    
     Eg:
     
    
     package junereflect624;
     
    
     import java.lang.reflect.Constructor;
     
    
     class Emp{
     
    
     private String name;
     
    
     private int age;
     
    
     private Emp() {
     
    
     }
     
    
     Emp(String name){
     
    
     }
     
    
     public Emp(String name,int age){
     
    
     }
     
    
     }
     
    
     public class ConstructorDemo4 {
     
    
     public static void main(String[] args) throws Exception {
     
    
     //得到所有的构造器(先得到类)
     
    
     Class<Emp> c = Emp.class;
     
    
     /**
     
    
     * Constructor<?>[] getConstructors()
     
    
     返回一个包含某些 Constructor 对象的数组,这些对象反映此
     
    
     Class 对象所表示的类的所有公共构造方法。
     
    
     */
     
    
     Constructor[] con = c.getConstructors();//前面的修饰符必须是
     
    
     public才可以在这个方法下获取到
     
    
     for (Constructor cons : con) {
     
    
     System.out.println("c.getConstructors()"+cons);//如果上面
     
    
     的某构造器public去掉,则显示不出
     
    
     /**打印
     
    
     public junereflect624.Emp(java.lang.String,int)
     
    
     */
     
    
     }
     
    
     //得到指定的构造器,也是必须public
     
    
     Constructor c1 = c.getConstructor(String.class,int.class);
     
    
     System.out.println(c1);//public
     
    
     junereflect624.Emp(java.lang.String,int)
     
    
     System.out.println("====================================");
     
    
     //现在想获得不受public影响的,getDeclaredConstructors(),暴力反射
     
    
     con = c.getDeclaredConstructors();
     
    
     for (Constructor cons : con) {
     
    
     System.out.println("c.getDeclaredConstructors()=="+cons);//
     
    
     此时不受修饰符的影响
     
    
     /**打印
     
    
     * public junereflect624.Emp()
     
    
     public junereflect624.Emp(java.lang.String)
     
    
     public junereflect624.Emp(java.lang.String,int)
     
    
     */
     
    
     }
     
    
     }
     
    
     }
     
    
     package junereflect624;
     
    
     import java.lang.annotation.Annotation;
     
    
     import java.lang.reflect.Field;
     
    
     import java.lang.reflect.Method;
     
    
     class AB{
     
    
     protected String name;
     
    
     protected String id;
     
    
     }
     
    
     @Deprecated
     
    
     public class MethodDemo5 extends AB{
     
    
     void show(){}
     
    
     public void say(){}
     
    
     private int age;
     
    
     public char c;
     
    
     private boolean b;
     
    
     public static void main(String[] args) throws Exception {
     
    
     Class<MethodDemo5> c = MethodDemo5.class;
     
    
     //获取所有的(包含父类的方法)public修饰的方法
     
    
     Method[] m = c.getMethods();
     
    
     for (Method method : m) {
     
    
     System.out.println(method);
     
    
     }
     
    
     //总结:4个方法,获取全部,获取特定;不受修饰符影响的全部,不受修饰符影
     
    
     响的特定;(前两个都还是受限制的)
     
    
     //获取指定的方法
     
    
     Method me = c.getMethod("main", String[].class);
     
    
     System.out.println("main "+me);//main public static void
     
    
     junereflect624.MethodDemo5.main(java.lang.String[]) throws
     
    
     java.lang.Exception
     
    
     //访问所有方法,不受访问权限影响
     
    
     m = c.getDeclaredMethods();
     
    
     for (Method method : m) {
     
    
     System.out.println("不受影响的:"+method);
     
    
     }
     
    
     me = c.getDeclaredMethod("show");
     
    
     System.out.println(me);//void
     
    
     junereflect624.MethodDemo.show()
     
    
     me = c.getMethod("toString");
     
    
     System.out.println(me);//public java.lang.String
     
    
     java.lang.Object.toString()
     
    
     /**
     
    
     * Method[] getDeclaredMethods()
     
    
     返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的
     
    
     类或接口声明的所有方法,
     
    
     包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法,
     
    
     只可以对当前类有效
     
    
     */
     
    
     /*me =
     
    
     c.getDeclaredMethod("toString");//ERROR,c.getDeclaredMethod() 不 能
     
    
     得到继承的方法
     
    
     System.out.println(me);//public java.lang.String
     
    
     java.lang.Object.toString()
     
    
     */
     
    
     //得到字段
     
    
     Field[] f = c.getFields();
     
    
     for (Field field : f) {//只得到了public的
     
    
     System.out.println("字段"+field);
     
    
     }
     
    
     //特定字段
     
    
     Field fi = c.getField("c");//""里面是名称
     
    
     System.out.println(fi);//public char
     
    
     junereflect624.MethodDemo.c
     
    
     //得到不受限定名限定的全部字段
     
    
     f = c.getDeclaredFields();
     
    
     for (Field field : f) {//得到不受修饰符限定的字段,但是只对当前类有
     
    
     效
     
    
     System.out.println("全部字段:"+field);
     
    
     /**
     
    
     * 全部字段:private int junereflect624.MethodDemo.age
     
    
     全部字段:public char junereflect624.MethodDemo.c
     
    
     全部字段:private boolean junereflect624.MethodDemo.b
     
    
     */
     
    
     }
     
    
     //注释 Annotation
     
    
     Annotation[] a = c.getAnnotations();
     
    
     System.out.println(a.length);
     
    
     for (Annotation annotation : a) {
     
    
     System.out.println(annotation);
     
    
     }
     
    
     //特定注解
     
    
     Deprecated d = c.getAnnotation(Deprecated.class);
     
    
     System.out.println(d);
     
    
     }
     
    
     }
     
    
     获取当前对象的字段:
     
    
     package july78javaEnhance;
     
    
     import java.lang.reflect.Field;
     
    
     class Stu{
     
    
     public String name;
     
    
     public String sex;
     
    
     public int age;
     
    
     public Stu(String name, String sex, int age) {
     
    
     super();
     
    
     this.name = name;
     
    
     this.sex = sex;
     
    
     this.age = age;
     
    
     }
     
    
     }
     
    
     public class ReflectDemo6 {
     
    
     public static void main(String[] args) throws Exception {
     
    
     Stu s = new Stu("刘昭", "男", 12);
     
    
     Class<Stu> c = Stu.class;
     
    
     Field f = c.getField("name");
     
    
     System.out.println(f.get(s));从哪个对象身上取!此时显示刘昭!
     
    
     // 修改对象的值
     
    
     /**
     
    
     Field f = c.getField("name");
     
    
     f.set(s,"章泽天");
     
    
     System.out.println(f.get(s));//从哪个对象身上取!//此时显示章泽天
     
    
     */
     
    
     }
     
    
     }
     
    
     我的总结:对于方法,字段,构造方法之类用类获取记住四个:获取全部,获
     
    
     取特定,暴力获取全部,暴力获取特定!
     
       
     
    
     
6、利用反射创建对象
     
    
     创建对象:
     
    
     1、使用 Class 对象的 newInstance()方法创建该 Class 对象的实例,此时该 Class 对象必
     
    
     须要有无参数的构造方法。
     
    
     2、使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 的 newInstance()
     
    
     方法创建对象类的实例,此时可以选择使用某个构造方法。如果这个构造方法被私有化起来,
     
    
     那么必须先申请访问,将可以访问设置为 true;
     
    
     Eg:
     
    
     最简单的:
     
    
     package junereflect624;
     
    
     class User{
     
    
     /*private User(){//将默认的构造方法私有化的话就不可以再创建对象,两种方
     
    
     法都是这样
     
    
     }*/
     
    
     public String toString() {
     
    
     return "User对象创建成功!";
     
    
     }
     
    
     }
     
    
     public class NewInstanceDemo6 {
     
    
     public static void main(String[] args) throws Exception {
     
    
     //传统方式创建对象
     
    
     System.out.println(new User());
     
    
     //使用反射的方式
     
    
     Class<User> c = User.class;
     
    
     User u = c.newInstance();(直接newInstance的话必须保证默认的构
     
    
     造方法正常存在,也就是没有被私有化!这是前提条件)
     
    
     System.out.println(u);
     
    
     }
     
    
     }
     
    
     复杂点的:更强大的第二种:
     
    
     使用指定构造方法来创建对象:
     
    
     获取该类的 Class 对象。
     
    
     利用 Class 对象的 getConstructor()方法来获取指定的构造方法。
     
    
     调用 Constructor 的 newInstance()方法创建对象。
     
    
     AccessibleObject 对象的 setAccessible(boolean flag)方法,当 flag 为 true 的时候,就会忽略访问
     
    
     权限(可访问私有的成员)。
     
    
     其子类有 Field, Method, Constructor;
     
    
     若要访问对象 private 的成员?
     
    
     在调用之前使用 setAccessible(true),
     
    
     Xxx x = getDeclaredXxxx();//才能得到私有的类字段.
     
    
     总结步骤:
     
    
     1. 获取该类的 Class 对象。
     
    
     2. 利用 Class 对象的 getConstructor()方法来获取指定的构造方法。
     
    
     3. 申请访问(设置为可访问)
     
    
     4. 调用 Constructor(构造方法)的 newInstance()方法创建对象。
     
    
     例子
     
    
     package junereflect624;
     
    
     import java.lang.reflect.Constructor;
     
    
     class Per{
     
    
     private String name;
     
    
     private int age;
     
    
     private Per(){
     
    
     }
     
    
     private Per(String name){
     
    
     }
     
    
     public String toString() {
     
    
     return "对象!!!";
     
    
     }
     
    
     }
     
    
     public class NewInstanceDemo7 {
     
    
     public static void main(String[] args) throws Exception {
     
    
     Class<Per> c = Per.class;
     
    
     //System.out.println(c.newInstance());;//证明利用无参的可以
     
    
     先获得需要被调用的构造器(private 修饰的构造方法)
     
    
     Constructor<Per> con = c.getDeclaredConstructor();//调用默认
     
    
     的,什么都不要写
     
    
     System.out.println(con);//private junereflect624.Per()
     
    
     /*con = c.getDeclaredConstructor(String.class); 获取指定的构造
     
    
     方法
     
    
     System.out.println(con);//private
     
    
     junereflect624.Per(java.lang.String)*/
     
    
     //现在只需要执行这个构造器,
     
    
     /**
     
    
     * T newInstance(Object... initargs)
     
    
     使用此 Constructor 对象表示的构造方法来创建该构造方法的声明
     
    
     类的新实例,并用指定的初始化参数初始化该实例。
     
    
     */
     
    
     //私有的成员是受保护的,不能直接访问
     
    
     //若要访问私有的成员,得先申请一下
     
    
     con.setAccessible(true);//允许访问
     
    
     Per p = con.newInstance();//成功,通过私有的受保护的构造方法创建了
     
    
     对象
     
    
     System.out.println("无参构造方法"+p);
     
    
     con = c.getDeclaredConstructor(String.class);
     
    
     System.out.println(con);//private
     
    
     junereflect624.Per(java.lang.String)
     
    
     con.setAccessible(true);//允许访问
     
    
     p = con.newInstance("liuzhao");//成功,通过私有的受保护的构造方法
     
    
     创建了对象
     
    
     System.out.println("String构造方法"+p);
     
    
     }
     
    
     }
     
    
     备注:对于此时的话,单例模式就不再安全了!反射可破之!!
     
    
     验证:对于枚举而言,反射依然没有办法重新创建对象
     
    
     对于枚举,安全!
     
    
     package junereflect624;
     
    
     import java.lang.reflect.Constructor;
     
    
     enum Color{
     
    
     RED,BLUE,GREEN;
     
    
     private Color(){
     
    
     }
     
    
     }
     
    
     public class EnumDemo8 {
     
    
     public static void main(String[] args) throws Exception {
     
    
     Class<Color> c = Color.class;
     
    
     Constructor<Color> con = c.getDeclaredConstructor();//(错误
     
    
     在这一行发生,就是说对枚举而言这种方法连构造器都获得不了,)编译可以通过,但是运
     
    
     行就通不过了!
     
    
     Color co = (Color) con.newInstance();
     
    
     System.out.println(co);//失败,证明对枚举而言不行,所以枚举的单例模
     
    
     式更加安全
     
    
     System.out.println(c.isEnum());//true是枚举
     
    
     }
     
    
     }
     
       
     
    
     
7、使用反射调用方法
     
    
     每个 Method 的对象对应一个具体的底层方法。获得 Method 对象后,程序可以使用 Method
     
    
     里面的 invoke 方法来执行该底层方法。
     
    
     Object invoke(Object obj,Object ... args):obj 表示调用底层方法的对象,后面的 args 表示传递
     
    
     的实际参数。
     
    
     如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null,想想为什么?
     
    
     如果底层方法所需的形参个数为 0,则所提供的 args 数组长度可以为 0 或 null。
     
    
     不写,null,或 new Object[]{}
     
    
     若底层方法返回的是数组类型,invoke 方法返回的不是底层方法的值,而是底层方法的返回类
     
    
     型;
     
    
     package junereflect624;
     
    
     import java.lang.reflect.Method;
     
    
     class Dept{
     
    
     public String show(String name){//用反射的方法来调用正常的方法
     
    
     return name+",您好!";
     
    
     }
     
    
     private void privateshow(){//用反射来实现对私有化方法的调用
     
    
     System.out.println("privateshow");
     
    
     }
     
    
     public static void staticshow(){
     
    
     System.out.println("staticshow");
     
    
     }
     
    
     }
     
    
     public class InvokeDemo9 {
     
    
     public static void main(String[] args) throws Exception {
     
    
     /* 传统方式:
     
    
     String name = new Dept().show("刘昭");
     
    
     System.out.println(name);*/
     
    
     /**
     
    
     * Method getMethod(String name, Class<?>... parameterTypes)
     
    
     返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指
     
    
     定公共成员方法。
     
    
     name - 方法名
     
    
     parameterTypes - 参数列表
     
    
     */
     
    
     //想要通过反射来调用Dept中的方法
     
    
     Class<Dept> c = Dept.class;
     
    
     Method m = c.getMethod("show", String.class);
     
    
     Object o = m.invoke(c.newInstance(), "刘昭");
     
    
     System.out.println(o);
     
    
     //私有化的方法
     
    
     m = c.getDeclaredMethod("privateshow");//无参方法
     
    
     m.setAccessible(true);
     
    
     o = m.invoke(c.newInstance());
     
    
     //静态方法的调用
     
    
     m = c.getMethod("staticshow");
     
    
     m.invoke(null);//staticshow为静态方法,不需创建对象,所以这里会是
     
    
     null
     
    
     }
     
    
     }
     
    
     打印
     
    
     刘昭,您好!
     
    
     privateshow
     
    
     staticshow
     
       
     
     
     
8、使用反射调用可变参数方法
       
     
    
     使用反射操作对象-调用可变参数方法
     
    
     要把可变参数都当做是其对应的数组类型参数;
     
    
     如 show(XX... is)作为 show(XX[] is)调用;
     
    
     若可变参数元素类型是引用类型:
     
    
     JDK 内部接收到参数之后,会自动拆包取出参数再分配给该底层方法,为此我们需要把这
     
    
     个数组实参先包装成一个 Object 对象或把实际参数作为一个Object 一维数组的元素再传递。
     
    
     若可变参数元素类型是基本类型:
     
    
     JDK 内部接收到参数之后,不会拆包,所以可以不必再封装.不过封装了也不会错.所以建
     
    
     议,不管基本类型还是引用类型都使用 Object[]封装一层,保证无误.
     
    
     例子
     
    
     package junereflect624;
     
    
     //可变参数的方法调用
     
    
     import java.lang.reflect.Method;
     
    
     class VaryMethod{
     
    
     public static void show(int ...args){
     
    
     System.out.println("基本数据类型传递过来了!");
     
    
     }
     
    
     /*public static void show(int[] args){//这是一样的
     
    
     }*/
     
    
     public static void show(String ...args){
     
    
     System.out.println("引用数据类型传递过来了!");
     
    
     }
     
    
     }
     
    
     public class InvokeVaryDemo10 {
     
    
     public static void main(String[] args) throws Exception{
     
    
     Class<VaryMethod> c = VaryMethod.class;
     
    
     Method m = c.getMethod("show",int[].class);
     
    
     m.invoke(null,new int[]{1,2,3});
     
    
     m = c.getMethod("show",String[].class);
     
    
     //m.invoke(null,new String[]{"A","B","C"});//ERROR
     
    
     m.invoke(null,(Object)new String[]{"A","B","C"});//YES, 强 转
     
    
     为Object类型
     
    
     m.invoke(null,new Object[]{new String[]{"A","B","C"}});//推
     
    
     荐写法
     
    
     }
     
    
     }
     
       
     
    
     
9、使用反射操作字段
     
    
     Field 提供两组方法操作字段:
     
    
     xxx getXxx(Object obj):获取 obj 对象该 Field 的字段值,此处的 xxx 表示 8 个基本数据类型。
     
    
     若该字段的类型是引用数据类型则使用,Object get(Object obj);
     
    
     void setXxx(Object obj,xxx val):将 obj 对象的该 Field 字段设置成 val 值,此处的 xxx 表示 8
     
    
     个基本数据类型。若该字段的类型是引用数据类型则使用,void set(Object obj, Object value);
     
    
     package junereflect624;
     
    
     //获取字符,并且赋值,然后再取出来(对应的去查看api,比如这个是Field,别的比如
     
    
     Constructor,Method)
     
    
     步骤:
     
    
     1.获取类
     
    
     2.获取字段
     
    
     3.赋值(set(c.newInstance(),””));{如果为私有的话设置可接受}
     
    
     import java.lang.reflect.Field;
     
    
     class Cat{
     
    
     private String name;
     
    
     public int age;
     
    
     private String color;
     
    
     }
     
    
     public class FieldDemo12 {
     
    
     public static void main(String[] args) throws Exception {
     
    
     Class<Cat> clz = Cat.class;
     
    
     Field[] f = clz.getDeclaredFields();
     
    
     for (Field field : f) {
     
    
     System.out.println(field);
     
    
     }
     
    
     Field fi = clz.getDeclaredField("name");
     
    
     System.out.println(fi);
     
    
     System.out.println(fi.getName());//name
     
    
     //核心开始
     
    
     /**
     
    
     * void set(Object obj, Object value)
     
    
     将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
     
    
     */
     
    
     Cat c = clz.newInstance();
     
    
     fi.setAccessible(true);
     
    
     fi.set(c, "刘昭");//赋值成功
     
    
     Object o = fi.get(c);
     
    
     System.out.println(o);//取出成功
     
    
     fi = clz.getDeclaredField("age");
     
    
     fi.setAccessible(true);
     
    
     fi.set(c, 21);
     
    
     int i = fi.getInt(c);//左边的接受类型已经写成了int,右边的返回类型
     
    
     就也必须是int
     
    
     System.out.println(i);//获取成功
     
    
     }
     
    
     }
     
    
     打印
     
    
     private java.lang.String junereflect624.Cat.name
     
    
     public int junereflect624.Cat.age
     
    
     private java.lang.String junereflect624.Cat.color
     
    
     private java.lang.String junereflect624.Cat.name
     
    
     name
     
    
     刘昭
     
    
     21
     
       
     
    
     
10、反射和泛型-反射来获取泛型信息
     
    
     通过指定对应的 Class 对象,程序可以获得该类里面所有的 Field,不管该 Field 使用 private
     
    
     方法 public。获得 Field 对象后都可以使用 getType()来获取其类型。
     
    
     Class<?> type = f.getType();//获得字段的类型
     
    
     但此方法只对普通 Field 有效,若该 Field 有泛型修饰,则不能准确得到该 Field 的泛型参数,如
     
    
     Map<String,Integer>;
     
    
     为了获得指定 Field 的泛型类型,我们采用:
     
    
     Type gType = f.getGenericType();得到泛型类型
     
    
     然后将 Type 对象强转为 ParameterizedType,其表示增加泛型后的类型
     
    
     Type getRawType()//返回被泛型限制的类型;
     
    
     Type[] getActualTypeArguments()//返回泛型参数类型;
     
    
     利用反射来获取泛型的类型(泛型信息)
     
    
     步骤:
     
    
     1.获取当前类
     
    
     2.获取目标字段
     
    
     3.获取包含泛型类型的类型 getGenericType()
     
    
     4.强转至子类 ParameterizedType 因为 Type 没有任何对应的方法
     
    
     5.获得泛型真正的类型 getActualTypeArguments()
     
    
     例子
     
    
     package junereflect624;
     
    
     import java.lang.reflect.Field;
     
    
     import java.lang.reflect.ParameterizedType;
     
    
     import java.lang.reflect.Type;
     
    
     import java.util.HashMap;
     
    
     import java.util.Map;
     
    
     public class GetGenericTypeDemo14 {
     
    
     Map<String,Integer> map = new HashMap<String,Integer>();
     
    
     public static void main(String[] args) throws Exception {
     
    
     Class c = GetGenericTypeDemo14.class;
     
    
     Field f = c.getDeclaredField("map");
     
    
     System.out.println(f);
     
    
     System.out.println(f.getName());//map
     
    
     // Class<?> getType() 返回一个 Class 对象,它标识了此 Field 对象
     
    
     所表示字段的声明类型。
     
    
     Class cl = f.getType();
     
    
     System.out.println("获得其类型:"+cl);
     
    
     //获得其类型:interface java.util.Map
     
    
     /**
     
    
     * Type getGenericType() 返回一个 Type 对象,它表示此 Field 对象
     
    
     所表示字段的声明类型。
     
    
     * Type是Class的接口;
     
    
     */
     
    
     Type t = f.getGenericType();//包含泛型的类型
     
    
     System.out.println(t);
     
    
     //java.util.Map<java.lang.String, java.lang.Integer>
     
    
     /**
     
    
     * Type这个类里面没有任何的方法,所以需要调用子类的方法,那么大的类型
     
    
     转到小的类型,需要强转!
     
    
     */
     
    
     ParameterizedType pt = (ParameterizedType)t;//强转到其子类
     
    
     /**
     
    
     * Type[] getActualTypeArguments()
     
    
     返回表示此类型实际类型参数的 Type对象的数组。
     
    
     Type getOwnerType()
     
    
     返回 Type 对象,表示此类型是其成员之一的类型。
     
    
     Type getRawType()
     
    
     返回 Type 对象,表示声明此类型的类或接口。
     
    
     */
     
    
     t = pt.getRawType();//类型的类或接口
     
    
     System.out.println(t);
     
    
     Type[] ts = pt.getActualTypeArguments();
     
    
     for (Type type : ts) {
     
    
     System.out.println(type);
     
    
     /**
     
    
     * class java.lang.String
     
    
     class java.lang.Integer
     
    
     */
     
    
     }
     
    
     }
     
    
     }
     
    
     打印:
     
    
     java.util.Map junereflect624.GetGenericTypeDemo14.map
     
    
     map
     
    
     获得其类型:interface java.util.Map
     
    
     java.util.Map<java.lang.String, java.lang.Integer>
     
    
     interface java.util.Map
     
    
     class java.lang.String
     
    
     class java.lang.Integer
     
    
     我的总结:多查找 api,参考 api 中方法使用的限制,比如是否静态、返回值类型等。
     
    
     
     
     
     
Java帮帮-IT资源分享网
     
     
    
   
  
                
        
 
相关资源:python入门教程(PDF版)