Java反射机制(三):调用对象的私有属性和方法

简介:

一、 通过反射调用类中的方法

在正常情况下,得到类的对象后,我们就可以直接调用类中的方法了,如果要想调用的话,则肯定必须清楚地知道要调用的方法是什么,之后通过Class类中的getMethod方法,可得到Method对象。

public Method getMethod(String name,
                        Class<?>... parameterTypes)
                 throws NoSuchMethodException,
                        SecurityException
当获取到Method对象后,可以通过该对象来执行方法,但是在方法调用的时候,因为会牵扯到方法中参数的问题,所以通过getMethod()取得的时候,必须设置好参数类型。

package org.chen.yuan.reflect;
interface China{	// 定义China接口
	public static final String NATIONAL = "China" ;	// 定义全局常量
	public static final String AUTHOR = "李兴华" ;	// 定义全局常量
	public void sayChina() ;		// 无参的,没有返回值的方法
	public String sayHello(String name,int age) ;	// 定义有两个参数的方法,并返回内容
}
public class Person implements China{
	private String name ;
	private int age ;
	public Person(){	// 无参构造
	}
	public Person(String name){
		this.name = name ;	// 设置name属性
	}
	public Person(String name,int age){
		this(name) ;
		this.age = age ;
	}
	public void sayChina(){	// 覆写方法
		System.out.println("作者:" + AUTHOR + ",国籍:" + NATIONAL) ;
	}
	public String sayHello(String name,int age){
		return name + ",你好!我今年:" + age + "岁了!" ;
	}
	public void setName(String name){
		this.name = name ;
	}
	public void setAge(int age){
		this.age = age ;
	}
	public String getName(){
		return this.name ;
	}
	public int getAge(){
		return this.age ;
	}
};
我们调用sayChina()方法,此方法中没有任何参数。

执行调用的方法,需通过Method的invoke方法来实现:

public Object invoke(Object obj,
                     Object... args)
              throws IllegalAccessException,
                     IllegalArgumentException,
                     InvocationTargetException

示例1:(调用无参的方法)

package org.chen.yuan.reflect;
interface China{	// 定义China接口
	public static final String NATIONAL = "China" ;	// 定义全局常量
	public static final String AUTHOR = "沉缘" ;	// 定义全局常量
	public void sayChina() ;		// 无参的,没有返回值的方法
	public String sayHello(String name,int age) ;	// 定义有两个参数的方法,并返回内容
}
public class Person implements China{
	private String name ;
	private int age ;
	public Person(){	// 无参构造
	}
	public Person(String name){
		this.name = name ;	// 设置name属性
	}
	public Person(String name,int age){
		this(name) ;
		this.age = age ;
	}
	public void sayChina(){	// 覆写方法
		System.out.println("作者:" + AUTHOR + ",国籍:" + NATIONAL) ;
	}
	public String sayHello(String name,int age){
		return name + ",你好!我今年:" + age + "岁了!" ;
	}
	public void setName(String name){
		this.name = name ;
	}
	public void setAge(int age){
		this.age = age ;
	}
	public String getName(){
		return this.name ;
	}
	public int getAge(){
		return this.age ;
	}
};

我们在Person.java 类中定义了一个无参方法sayChina和一个有参数的方法sayHello,接下来,我们调用无参数的方法:

package org.chen.yuan.reflect;

import java.lang.reflect.Method;

public class InvokeSyaChinaDemo
{
    public static void main(String[] args)
    {
        Class<?> c1 = null;
        try
        {
            c1 = Class.forName("org.chen.yuan.reflect.Person");
            Method met = c1.getMethod("sayChina");
            met.invoke(c1.newInstance());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

输出: 作者:沉缘,国籍:China

可以看出,通过上述反射的方式,我们能够顺利的调用Person类中的方法。 那思考下,如果我们要调用含有参数的方法sayHello,该如何做呢?

可以想象,如果方法里存在了参数,则必须设置参数的类型及内容。

public class InvokeSayHelloDemo
{

    public static void main(String[] args) throws Exception
    {
        Class<?> c1 = null;
        c1 = Class.forName("org.chen.yuan.reflect.Person");
        Method met = c1.getMethod("sayHello", String.class, int.class);
        String result = (String) met.invoke(c1.newInstance(), "沉缘", 25);
        System.out.println(result);
    }

}

输出: 沉缘,你好!我今年:25岁了!


二、 通过反射调用类中的setter及getter方法

setter和getter方法是访问类属性的标准方法,如果一个类中的属性被封装,则必须通过setter及getter方法设设置和取得,实际上此方法的操作之所以要这样规定,主要是由于反射机制可以给予支持。

通过反射可以调用setter及getter方法。

package org.chen.yuan.reflect;

import java.lang.reflect.Method;

public class InvokeSetGetDemo
{

    public static void main(String[] args) throws Exception
    {
        Class<?> c1 = null;
        Object obj = null;

        c1 = Class.forName("org.chen.yuan.reflect.Person");
        obj = c1.newInstance();

        setter(obj, "name", "沉缘", String.class);
        getter(obj, "name");

        setter(obj, "age", 25, int.class);
        getter(obj, "age");
    }

    /**
     * @param obj 要操作的对象
     * @param att 要操作的属性
     * @param value 要设置的属性数据
     * @param type 要设置的属性的类型
     */
    public static void setter(Object obj, String att, Object value, Class<?> type)
    {
        try
        {
            Method met = obj.getClass().getMethod("set" + initStr(att), type);
            met.invoke(obj, value);

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * @param obj 要操作的对象
     * @param att 要操作的属性
     */
    public static void getter(Object obj, String att) throws Exception
    {
        Method met = obj.getClass().getMethod("get" + initStr(att));
        System.out.println(met.invoke(obj));
    }

    /**
     * 将单词首字母大写
     * 
     * @param old
     * @return
     */
    public static String initStr(String old)
    {
        String newStr = old.substring(0, 1).toUpperCase() + old.substring(1);
        return newStr;
    }
}


三、 通过反射调用属性

如果假设要操作一个类中的属性,则也可以通过Field完成,而不必麻烦的通过setter和getter。Class类中,获取类中Field的方法:

1) 得到类中公共属性

public Field getField(String name)
               throws NoSuchFieldException,
                      SecurityException
2)得到本类属性

public Field getDeclaredField(String name)
                       throws NoSuchFieldException,
                              SecurityException

而在Field类中,提供了获取属性内容及设置属性内容的方法:

1) 获取属性内容

public Object get(Object obj)
           throws IllegalArgumentException,
                  IllegalAccessException
2) 设置属性内容

public void set(Object obj,
                Object value)
         throws IllegalArgumentException,
                IllegalAccessException

还有一点需要注意,访问类中的私有属性时,必须要让该属性对外可见:

public void setAccessible(boolean flag)
                   throws SecurityException
该方法继承自Field的父类:
java.lang.reflect

Class AccessibleObject

只要把该方法的参数内容设置为true即可。

public class InvokeFieldDemo
{
    public static void main(String args[]) throws Exception
    {
        Class<?> c1 = null;
        Object obj = null;
        c1 = Class.forName("org.chen.yuan.reflect.Person"); // 实例化Class对象
        obj = c1.newInstance();
        Field nameField = null;
        Field ageField = null;
        nameField = c1.getDeclaredField("name"); // 取得name属性
        ageField = c1.getDeclaredField("age"); // 取得name属性
        nameField.setAccessible(true); // 此属性对外部可见
        ageField.setAccessible(true); // 此属性对外部可见
        nameField.set(obj, "沉缘"); // 设置name属性内容
        ageField.set(obj, 25); // 设置age属性内容
        System.out.println("姓名:" + nameField.get(obj));
        System.out.println("年龄:" + ageField.get(obj));
    }
};


输出: 

姓名:沉缘
年龄:25

可见,操作属性,未必需要setter和getter方法的支持,但是,为了保证程序的安全性,最好还是通过setter和getter方法对属性进行操作。


四、 通过反射操作数组

反射机制不光能用在类中,也可以应用在任意的引用数据类型上,当然,这就包含了数组,数组使用Array类完成。

Class类中存在以下一个方法:

public Class<?> getComponentType()

Array类中得到数组指定下标的内容:

public static Object get(Object array,
                         int index)
                  throws IllegalArgumentException,
                         ArrayIndexOutOfBoundsException

Array类中修改内容:

public static void set(Object array,
                       int index,
                       Object value)
                throws IllegalArgumentException,
                       ArrayIndexOutOfBoundsException

Array类中开辟新的数组:

public static Object newInstance(Class<?> componentType,
                                 int... dimensions)
                          throws IllegalArgumentException,
                                 NegativeArraySizeException

取得数组信息并修改内容:

package org.chen.yuan.reflect;
import java.lang.reflect.Array ;
public class ClassArrayDemo{
	public static void main(String args[]) throws Exception{
		int temp[] = {1,2,3} ;// 声明一整型数组
		Class<?> c = temp.getClass().getComponentType() ;	// 取得数组的Class对象
		System.out.println("类型:" + c.getName()) ;	// 取得数组类型名称
		System.out.println("长度:" + Array.getLength(temp)) ;
		System.out.println("第一个内容:" + Array.get(temp,0)) ;
		Array.set(temp,0,6) ;
		System.out.println("第一个内容:" + Array.get(temp,0)) ;
	}
};
输出:

类型:int
长度:3
第一个内容:1
第一个内容:6


数组修改的过程,实际上就是创建一个新的数组的过程,所以要把旧的数组内容拷贝到新的数组中去。

package org.chen.yuan.reflect;

import java.lang.reflect.Array;

public class ChangeArrayDemo
{
    public static void main(String args[]) throws Exception
    {
        int temp[] = {1, 2, 3};// 声明一整型数组
        int newTemp[] = (int[]) arrayInc(temp, 5); // 重新开辟空间5
        print(newTemp);
        System.out.println("\n-------------------------");
        String t[] = {"chenyuan", "wuqing", "lengxue"};
        String nt[] = (String[]) arrayInc(t, 8);
        print(nt);
    }

    public static Object arrayInc(Object obj, int len)
    {
        Class<?> c = obj.getClass();
        Class<?> arr = c.getComponentType(); // 得到数组的
        Object newO = Array.newInstance(arr, len); // 开辟新的大小
        int co = Array.getLength(obj);
        System.arraycopy(obj, 0, newO, 0, co); // 拷贝内容
        return newO;
    }

    public static void print(Object obj)
    { // 数组输出
        Class<?> c = obj.getClass();
        if (!c.isArray())
        { // 判断是否是数组
            return;
        }
        Class<?> arr = c.getComponentType();
        System.out.println(arr.getName() + "数组的长度是:" + Array.getLength(obj)); // 输出数组信息
        for (int i = 0; i < Array.getLength(obj); i++)
        {
            System.out.print(Array.get(obj, i) + "、"); // 通过Array输出
        }
    }
};

输出:

nt数组的长度是:5
1、2、3、0、0、
-------------------------
java.lang.String数组的长度是:8
chenyuan、wuqing、lengxue、null、null、null、null、null、


相关文章
|
11天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
39 2
|
15天前
|
Java 编译器
探索Java中的异常处理机制
【10月更文挑战第35天】在Java的世界中,异常是程序运行过程中不可避免的一部分。本文将通过通俗易懂的语言和生动的比喻,带你了解Java中的异常处理机制,包括异常的类型、如何捕获和处理异常,以及如何在代码中有效地利用异常处理来提升程序的健壮性。让我们一起走进Java的异常世界,学习如何优雅地面对和解决问题吧!
|
25天前
|
安全 Java 编译器
Java对象一定分配在堆上吗?
本文探讨了Java对象的内存分配问题,重点介绍了JVM的逃逸分析技术及其优化策略。逃逸分析能判断对象是否会在作用域外被访问,从而决定对象是否需要分配到堆上。文章详细讲解了栈上分配、标量替换和同步消除三种优化策略,并通过示例代码说明了这些技术的应用场景。
Java对象一定分配在堆上吗?
|
26天前
|
XML 安全 Java
Java反射机制:解锁代码的无限可能
Java 反射(Reflection)是Java 的特征之一,它允许程序在运行时动态地访问和操作类的信息,包括类的属性、方法和构造函数。 反射机制能够使程序具备更大的灵活性和扩展性
36 5
Java反射机制:解锁代码的无限可能
|
14天前
|
Java 数据库连接 开发者
Java中的异常处理机制及其最佳实践####
在本文中,我们将探讨Java编程语言中的异常处理机制。通过深入分析try-catch语句、throws关键字以及自定义异常的创建与使用,我们旨在揭示如何有效地管理和响应程序运行中的错误和异常情况。此外,本文还将讨论一些最佳实践,以帮助开发者编写更加健壮和易于维护的代码。 ####
|
18天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
67 4
|
20天前
|
安全 IDE Java
Java反射Reflect机制详解
Java反射(Reflection)机制是Java语言的重要特性之一,允许程序在运行时动态地获取类的信息,并对类进行操作,如创建实例、调用方法、访问字段等。反射机制极大地提高了Java程序的灵活性和动态性,但也带来了性能和安全方面的挑战。本文将详细介绍Java反射机制的基本概念、常用操作、应用场景以及其优缺点。 ## 基本概念 ### 什么是反射 反射是一种在程序运行时动态获取类的信息,并对类进行操作的机制。通过反射,程序可以在运行时获得类的字段、方法、构造函数等信息,并可以动态调用方法、创建实例和访问字段。 ### 反射的核心类 Java反射机制主要由以下几个类和接口组成,这些类
42 2
|
22天前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
63 2
|
25天前
|
存储 缓存 安全
🌟Java零基础:深入解析Java序列化机制
【10月更文挑战第20天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
24 3
|
25天前
|
安全 Java UED
深入理解Java中的异常处理机制
【10月更文挑战第25天】在编程世界中,错误和意外是不可避免的。Java作为一种广泛使用的编程语言,其异常处理机制是确保程序健壮性和可靠性的关键。本文通过浅显易懂的语言和实际示例,引导读者了解Java异常处理的基本概念、分类以及如何有效地使用try-catch-finally语句来处理异常情况。我们将从一个简单的例子开始,逐步深入到异常处理的最佳实践,旨在帮助初学者和有经验的开发者更好地掌握这一重要技能。
23 2
下一篇
无影云桌面