Java---类反射(3)---类反射加强

简介: Java---类反射(3)---类反射加强

★ 获取与设置属性值

根据属性名称读取与修改属性的值,访问非静态属性需传入对象为参数。

代码示例:

Person还是之前的类;

现在看演示类:

package cn.hncu.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
 * 类反射的演示
 * @author 陈浩翔
 *
 * @version 1.0  2016-5-2
 */
public class ReflectOperateObj {
    private static final String CLASS_FILE_NAME="cn.hncu.reflect.Person";
    public static void main(String[] args) {
        try {
            changeFieldValue(CLASS_FILE_NAME);          
        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }
    }
    /**
     * 五、演示根据属性名称读取和修改属性的值
     * @param classFileName
     * @throws ReflectiveOperationException
     */
    private static void changeFieldValue(String classFileName) throws ReflectiveOperationException{
        Class cls = Class.forName(CLASS_FILE_NAME);
        //需求:给一个对象的某属性设置值,如: p.num=123
                //1.1必须要用一个类对象
        Object obj = cls.newInstance();
        //1.2设置该对象的指定属性
           //1.2.1先拿到对应的Field对象
            Field field  =  cls.getField("num");//获取属性“num”对应的Field对象
            //设置属性值
                field.set(obj, 1234);
            //读取属性值
                System.out.println(field.getInt(obj));//1234----返回的是int类型,如果明确数据类型,用这种更好
                System.out.println(field.get(obj));//1234----返回的是Object类型,是通用的
        Person p = new Person();
        p.num=999;
        System.out.println(field.getInt(p));//999,new 谁调谁
    }
}


暴力访问其他类的私有方法,私有成员变量,私有构造方法:

Person类加了一个私有方法:abc();

    private int abc(){
        System.out.println("abc....");
        return 10;
    }

演示暴力访问:

package cn.hncu.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
 * 类反射暴力访问其他类的演示
 * @author 陈浩翔
 *
 * @version 1.0  2016-5-2
 */
public class ReflectOperateObj {
    private static final String CLASS_FILE_NAME="cn.hncu.reflect.Person";
    public static void main(String[] args) {
        try {
            brokeAccess(CLASS_FILE_NAME);
        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }
    }
    /**
     * 六、演示:暴力访问
     * @param classFileName
     */
    private static void brokeAccess(String classFileName) throws ReflectiveOperationException{
        Class cls = Class.forName(CLASS_FILE_NAME);
        Object obj = cls.newInstance();
        //访问Person中私有的方法abc()
        Method m = cls.getDeclaredMethod("abc",null);
        //只要打开访问权限的开关,就可以暴力访问了
        m.setAccessible(true);
        Object returnObj = m.invoke(obj, null);
        System.out.println("returnObj= "+returnObj);
        //*************
        //有关暴力访问的知识点
        //其实中要在访问之前调用一下AccessibleObject类中的setAccessible()方法且传入boolean型变量就可以
        //而AccessibleObject类是Constructor、Field和Method三个类的父类,因此这三者都能进行暴力访问! 
    }
}

输出结果:


abc....

returnObj= 10


看,访问到了吧。就算你的类设为私有的,一样能访问,是不是很神奇啊,

O(∩_∩)O哈哈~。


练习(模拟Java内省的功能)


★ 准备工作

定义一个Model类,里面所有的属性都是private的,然后为每个属性提供getter和setter方法;

再准备一个Map,map的key值都是类里面的属性字段的字符串表示,值任意。


Model类:

UserModel :

package cn.hncu.reflect.myBeanUtils;
/**
 * @author 陈浩翔
 *
 * @version 1.0  2016-5-2
 */
public class UserModel {
    private String uuid;
    private String name;
    private int age;
    public String getUuid() {
        return uuid;
    }
    public void setUuid(String uuid) {
        this.uuid = uuid;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        UserModel other = (UserModel) obj;
        if (uuid == null) {
            if (other.uuid != null)
                return false;
        } else if (!uuid.equals(other.uuid))
            return false;
        return true;
    }
    @Override
    public String toString() {
        return "UserModel [uuid=" + uuid + ", name=" + name + ", age=" + age
                + "]";
    }
}

bookModel:

package cn.hncu.reflect.myBeanUtils;
public class bookModel {
    private String uuid;
    private String name;
    private double inPrice;
    private double outPrice;
    private int num;
    public String getUuid() {
        return uuid;
    }
    public void setUuid(String uuid) {
        this.uuid = uuid;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getInPrice() {
        return inPrice;
    }
    public void setInPrice(double inPrice) {
        this.inPrice = inPrice;
    }
    public double getOutPrice() {
        return outPrice;
    }
    public void setOutPrice(double outPrice) {
        this.outPrice = outPrice;
    }
    public int getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        bookModel other = (bookModel) obj;
        if (uuid == null) {
            if (other.uuid != null)
                return false;
        } else if (!uuid.equals(other.uuid))
            return false;
        return true;
    }
    @Override
    public String toString() {
        return "bookModel [uuid=" + uuid + ", name=" + name + ", inPrice="
                + inPrice + ", outPrice=" + outPrice + ", num=" + num + "]";
    }
}

★ 真正的工作

设计一个方法Object getModel(Map map,Class cls),传入一个包含所有值的Map,然后再传入Model类的class,那么返回Model类的实例,这个实例里面已经包含好了所有相关的数据。也就是把Map中的数据通过反射,设置回到Model类实例中。


没有用泛型的(一):

MyBeanUtils

package cn.hncu.reflect.myBeanUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
/**
 * 
 * @author 陈浩翔
 *
 * @version 1.0  2016-5-2
 */
public class MyBeanUtils {
    public static Object populate(Class cls,Map map) throws ReflectiveOperationException{
        Object obj =null;
        //1 用类反射new出对象
        obj = (Object) cls.newInstance();
        //2 再用类反射对新new的对象设置属性值(必须遵守Java设置规范)--即通过setter方法设置
            //2.1遍历出所有该类声明的属性
        Field fields[] = cls.getDeclaredFields();
        for(Field fld : fields){
            //获取该fld对象所代表的属性名
            String fldName = fld.getName();
            //根据属性名,到map中去读取数据,只有数据非空才需要给该属性设置值 
            Object mapValue = map.get(fldName);
            if(mapValue==null){
                //如果map中不存在对应的属性数据,我们在这里给出提示信息
                System.out.println(fldName+"的数据为空!");
            }else{
                //如果map中存在对应的属性数据,则由属性名得出它的setter方法的名字
                String setName = "set"+fldName.substring(0, 1).toUpperCase()+fldName.substring(1);
                //根据方法名和参数的数据类型(其实就是属性的类型),获得Method对象
                Class parameterTypes[] =new Class[1];
                parameterTypes[0] = fld.getType();
                Method method = cls.getDeclaredMethod(setName, parameterTypes);//最好不要用getMethod,因为这样可能会用到父类的方法
                //这里不用担心会访问到私有的,因为权限没放开。
                //调用该method对象所代表的方法
                Object args[] = new Object[1];
                args[0] = mapValue;
                method.invoke(obj, args);
            }
        }
        return obj;
    }
}

好了,测试完全通过。

只是那个工具类有强转,好像不太好,怎么办呢。

这个时候,就可以用泛型了。

下面是用泛型的版本,至于测试,我就只测试一次了。

package cn.hncu.reflect.myBeanUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
public class MyBeanUtils2 {
    public static <T>T populate(Class<T> cls,Map<String, Object> map) throws ReflectiveOperationException{
        T t = null;
         //1 用类反射new出对象
        t = cls.newInstance();
         //2 再用类反射对新new的对象设置属性值(必须遵守Java设置规范)--即通过setter方法设置
           //2.1遍历出所有该类声明的属性
        Field flds[] = cls.getDeclaredFields();
        for(Field fld:flds){
            //获取该fld对象所代表的属性名
            String fldName = fld.getName();
            Object mapV = map.get(fldName);
             //根据属性名,到map中去读取数据,只有数据非空才需要给该属性设置值 
            if(mapV==null){
                //如果map中不存在对应的属性数据,我们在这里给出提示信息
                System.out.println(fldName+"数据为空!");
            }else{
                 //如果map中存在对应的属性数据,则由属性名得出它的setter方法的名字
                String setName = "set"+fldName.substring(0,1).toUpperCase()+fldName.substring(1);
                 //根据方法名和参数的数据类型(其实就是属性的类型),获得Method对象
                Class parameterTypes[] = new Class[1];
                parameterTypes[0] = fld.getType();
                Method m = cls.getDeclaredMethod(setName, parameterTypes);
                 //调用该method对象所代表的方法
                Object args[] = new Object[1];
                args[0]=mapV;
                m.invoke(t, args);
            }
        }
        return t;
    }
}

测试类:

package cn.hncu.reflect.myBeanUtils;
import java.util.HashMap;
import java.util.Map;
/**
 * @author 陈浩翔
 *
 * @version 1.0  2016-5-2
 */
public class Client {
    public static void main(String[] args) {
        test4();
    }
    private static void test4() {
        Map map = new HashMap();
        map.put("uuid", "001");
        map.put("name", "红楼梦");
        map.put("inPrice", 20.5);
        //map.put("outPrice", 50.5);
        map.put("num", 123);
        try {
            Object bookModel = MyBeanUtils2.populate(bookModel.class, map);
            System.out.println(bookModel);
        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }
    }
}

输出结果为:


outPrice数据为空!
bookModel [uuid=001, name=红楼梦, inPrice=20.5, outPrice=0.0, num=123]


好了,类反射也就这些内容了。结束啦。

其实类反射也挺容易的,就是通过完整的类名,再调用newInstance方法new一个对象。再通过这个对象来进行操作方法Method,构造方法(调用构造器来new对象

Object initargs[] = new Object[2];

initargs[0] = new String(“Jack”);

initargs[1] = new Integer(20);

Object resultObj = con.newInstance(initargs);),

成员变量Field。

要访问私有的,只要打开访问权限的开关,就可以暴力访问了

也就是.setAccessible(true);方法,设置为true。


目录
相关文章
|
3月前
|
Java 编译器 API
Java 密封类:精细化控制继承关系
Java 密封类:精细化控制继承关系
298 83
|
22天前
|
安全 Java 数据建模
Java记录类:简化数据载体的新选择
Java记录类:简化数据载体的新选择
171 101
|
22天前
|
安全 Java 开发者
Java记录类:简化数据载体的新方式
Java记录类:简化数据载体的新方式
201 100
|
2月前
|
安全 IDE Java
Java记录类型(Record):简化数据载体类
Java记录类型(Record):简化数据载体类
309 120
|
4月前
|
IDE Java 数据挖掘
Java 基础类从入门到精通实操指南
这份指南专注于**Java 17+**的新特性和基础类库的现代化用法,涵盖开发环境配置、数据类型增强(如文本块)、字符串与集合处理进阶、异常改进(如密封类)、IO操作及实战案例。通过具体代码示例,如CSV数据分析工具,帮助开发者掌握高效编程技巧。同时提供性能优化建议和常用第三方库推荐,适合从入门到精通的Java学习者。资源链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
190 35
|
4天前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
37 1
|
4天前
|
Java Go 开发工具
【Java】(8)正则表达式的使用与常用类分享
正则表达式定义了字符串的模式。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
74 1
|
4天前
|
存储 Java 程序员
【Java】(6)全方面带你了解Java里的日期与时间内容,介绍 Calendar、GregorianCalendar、Date类
java.util 包提供了 Date 类来封装当前的日期和时间。Date 类提供两个构造函数来实例化 Date 对象。第一个构造函数使用当前日期和时间来初始化对象。Date( )第二个构造函数接收一个参数,该参数是从1970年1月1日起的毫秒数。
41 1
|
4天前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
36 2
|
10天前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
110 5

热门文章

最新文章