关闭

初识Java反射

标签: java反射invokenewInstancfield
463人阅读 评论(0) 收藏 举报
分类:

Java反射原理是基于Class类而实现的,Class类代表了所有的类,通过Class类可以获取一个未知类的属性(Filed)、方法(method)、构造器(constructor)、修饰符(modifier)等。
一般情况下,需要创建一个类的实例对象,JVM会确认该类的Class对象是否加载完毕。未加载的话,JVM会根据类名查找.class文件,并载入内存,从而可以创建需要使用的类的对象。

以下代码验证均是在下面代码基础上验证。
接口:SingSong.java

package com.edu;

/**
 * 唱歌
 * 
 * @author xukai
 */
public interface SingSong {

    public static final long iid = -6564235491638363465L;

    public void singSong();

}

父类:PeopleSuperClass

package com.edu;

/**
 * 父类
 * 
 * @author xukai
 */
public class PeopleSuperClass {

    public static final long fid = -6564335491638363465L;

    /**
     * 子类
     */
    private People subPeople;

    /**
     * 父类
     */
    private PeopleSuperClass superPeople;

    public People getSubPeople() {
        return subPeople;
    }

    public void setSubPeople(People subPeople) {
        this.subPeople = subPeople;
    }

    public PeopleSuperClass getSuperPeople() {
        return superPeople;
    }

    public void setSuperPeople(PeopleSuperClass superPeople) {
        this.superPeople = superPeople;
    }

}

子类:People

package com.edu;

/**
 * 人类
 * 
 * @author xukai
 */
public class People extends PeopleSuperClass implements SingSong {

    public static final long sid = -6564335491638363466L;

    private String name;

    private Integer age;

    public String sex;

    public People() {
    }

    public People(String name, Integer age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "People [name=" + name + ", age=" + age + ", sex=" + sex + "]";
    }

    public String helloWorld() {
        return name + " said:Hello World!";
    }

    @Override
    public void singSong() {
        System.out.println("唱一首Until you");
    }

    public static void show() {
        System.out.println("I'm here");
    }

    public static void show(People p) {
        System.out.println(p.getName() + ",I'm here");
    }

}

Class的创建和获取

创建:
1. 使用new关键字创建对象
2. 访问类的静态成员
3. 使用Class.forName()方法
获取:
1. Class.forName方法返回对象即为加载类的Class对象
2. 每个类的class静态属性
3. Object类的成员方法getClass()

package com.edu;

/**
 * 获取Class对象
 * 
 * @author xukai
 */
public class MyReflex {

    public static void main(String[] args) {

        // 访问People的静态成员class,加载类
        System.out.println(People.class.getName());

        // 1.Class.forName静态方法
        Class<?> c1 = null;
        try {
            c1 = Class.forName("com.edu.People");
        } catch (ClassNotFoundException e) {
            System.out.println("加载类路径错误");
        }

        // 2.class静态属性
        Class<?> c2 = People.class;

        // 3.Object的成员方法getClass()
        People people = new People("xukai", 22);
        Class<?> c3 = people.getClass();

        System.out.println("c1=c2 is " + (c1 == c2));

        System.out.println("c1=c3 is " + (c1 == c3));

        System.out.println("c2=c3 is " + (c2 == c3));

    }

}

控制台信息:
Class创建

从上图可以看出,通过几种创建Class的方式返回的对象都是同一个。换句话说一个类对应的Class对象是否只存在一个?有待研究

获取类的成员变量

  1. 通过Class的方法getDeclareField()
  2. 通过Class的方法getDeclareFields()
package com.edu;

import java.lang.reflect.Field;

/**
 * 获取成员变量Field
 * 
 * @author xukai
 */
public class MyField {

    public static void main(String[] args) {
        Class<?> c = People.class;
        /**
         * 获取所有成员变量<br>
         * 1.getDeclaredField(),getDeclaredFields(),作用域对此方法无影响,不会访问父类字段<br>
         * 2.getFields(),getFields(),只能访问公共成员字段,即作用域为public,访问父类字段
         */
        getDeclaredField(c);
        System.out.println("------------------华丽的分割线-----------------");
        getField(c);

        // 通过Filed操作私有成员变量
        People p = new People("xukai", 22);
        try {
            Field fName = c.getDeclaredField("name");
            Field fAge = c.getDeclaredField("age");
            try {
                // 设置可访问性
                fName.setAccessible(true);
                fAge.setAccessible(true);
                fName.set(p, "rj");
                fAge.set(p, 25);
                System.out.println(p.toString());
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    /**
     * 扫描本类的所有成员变量
     * 
     * @param c
     *            Class
     */
    private static void getDeclaredField(Class<?> c) {
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            try {
                System.out.println("Field[] name=" + field.getName());
                Field singleField = c.getDeclaredField(field.getName());
                System.out.println("Field   name=" + singleField.getName());
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                /**
                 * 如果存在安全管理器s<br>
                 * 1.调用 s.checkMemberAccess(this, Member.DECLARED) 拒绝访问已声明字段<br>
                 * 2.调用者的类加载器不同于也不是当前类的类加载器的一个祖先, 并且对 s.checkPackageAccess()
                 * 的调用拒绝访问该类的包<br>
                 */
                e.printStackTrace();
            }
        }
    }

    /**
     * 只能访问公共成员字段,即作用域为public<br>
     * 1.搜索当前类的公共成员变量 2.搜索实现的接口的公共成员变量 3.搜索父类的公共成员变量
     * 
     * @param c
     *            Class
     */
    private static void getField(Class<?> c) {
        Field[] fields = c.getFields();
        for (Field field : fields) {
            try {
                System.out.println("Field[] name=" + field.getName());
                Field singleField = c.getField(field.getName());
                System.out.println("Field   name=" + singleField.getName());
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            }
        }
    }
}

控制台信息:
获取成员变量和修改成员变量的值

需要注意getDeclaredFiled和getFiled的区别

方法 作用域限制 访问实现接口成员变量 访问继承父类成员变量
getDeclaredFiled 不能 不能
getDeclaredFileds 不能 不能
getFiled 限制为公共public
getFileds 限制为公共public

获取类的方法(method)

  1. 通过Class的方法getMethod()
  2. 通过Class的方法getMethods()
package com.edu;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 获取类的方法
 * 
 * @author xukai
 */
public class MyMethod {

    public static void main(String[] args) {
        Class<?> c = People.class;
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            System.out.println(method + "\t\t" + method.getName());
        }
        System.out.println("------割-----");
        try {
            // getMethod(String name, Class<?>... parameterTypes),第二个参数为方法参数
            Method method = c.getMethod("show", new People("zj", 23).getClass());
            System.out.println(method);
            try {
                // 使用invoke调用方法
                System.out.println("------割-----");
                // 调用show方法
                method.invoke(new People("xukai", 22), new People("zj", 23));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }
}

控制台信息:
获取method和invoke使用

需要注意getMethod(String name, Class<\?>… parameterTypes)的第二个参数为Class类型。
Method.invoke(Object obj, Object… args)第一个参数为调用对象,第二个参数为方法参数

反射的简单应用

创建一个类的实例对象

package com.edu;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 使用反射实例化一个对象<br>
 * 建议使用newInstance方法创建对象,在使用setters方法赋值
 * 
 * @author xukai
 */
public class ReflexApplication {

    public static void main(String[] args) {
        Class<? extends People> c = People.class;
        People p = null;
        // 1.使用Class.newInstance创建对象
        try {
            /**
             * 使用此方法可以有效地绕过编译时的异常检查,而在其他情况下编译器都会执行该检查<br>
             * 调用空参构造方法
             */
            p = c.newInstance();
            System.out.println(p);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        // 2.使用带参数构造方法
        try {
            Constructor<? extends People> con = c.getConstructor(new String("zhouyang").getClass(),
                    new Integer(23).getClass());
            try {
                p = con.newInstance("ft", 24);
                System.out.println("constructor create: " + p);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }

        // 使用反射重写toString()
        People people = new People("zt", 23);
        System.out.println(people);
        overrideToString(people);
    }

    /**
     * 使用反射重写toString
     * 
     * @param obj
     *            重写对象
     */
    public static void overrideToString(Object obj) {
        StringBuffer sb = new StringBuffer();
        Field[] fields = obj.getClass().getDeclaredFields();
        sb.append(obj.getClass().getSimpleName() + "[");
        for (Field f : fields) {
            try {
                if (!f.isAccessible()) {
                    f.setAccessible(true);
                    sb.append(f.getName());
                    sb.append("=");
                    sb.append(f.get(obj));
                    sb.append(", ");
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        sb.append("]");
        System.out.println(sb);
    }

}

控制台信息:
创建实例对象和重写toString方法
一般使用Constructor创建实例太过于麻烦,常用newInstance创建实例,然后通过setter方法给成员变量赋值。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:84903次
    • 积分:1636
    • 等级:
    • 排名:千里之外
    • 原创:92篇
    • 转载:1篇
    • 译文:0篇
    • 评论:27条
    最新评论
    博客专栏
    文章分类