利用Java反射写所有类通用的toString方法

反射机制最重要的内容--检查类的结构
Java中java.lang.reflect下有三个类Field,MethodConstructor分别用于描述类的域方法和构造器
这三个类中都要一个GetName的方法,用来返回项目的名称
Field中有个GetType方法,用来描述域所属类型的Class对象
Method中还有一个报告返回值的方法,getReturnType()...
 
Class类中的getField(),getMethods(),getConstructors()方法
 将分别返回类提供的public域,方法和构造器 数组,其中包含父类的共有成员
Class类中的getDeclareField(),getDeclareMethods(),getDeclareConstructors()方法
 将分别返回类中声明的全部域,方法和构造器其中包括私有和保护成员,但不包括父类中的成员
 
这三个类中还有一个叫GetModifiers返回的是个整形,
例如可以用Modifier类中的isPublic isFinal...判断属性方法构造器是否是公共 不可变的...
还可以调用Modifier.toString方法将修饰符打印出来
Modifier.isStatic(f.getModifiers())   返回boolean
Modifier.toString(f.getModifiers())   返回String
 


首先我们学习怎么获得一个类的Class对象?

三种方法如下:

class Test
{
    public String name;
    private int age;
    private int[] nums = {1, 2, 3};

    public Test() {}
    public Test(String name, int age)
    {
        this.name = name;
        this.age = age;
    }
}


public class TestReflect
{

    public static void main(String[] args)
    {
        //获取一个类的Class对象的三种方法
        //1.
        Test test1 = new Test();
        Class c1 = test1.getClass();
        String className1 = c1.getName(); 
        //"Test" (类名,如果类在包里面包的名字也作为类名的一部分)

        //2.通过调用静态方法forName获得类名对应的Class对象,这个会抛出受查时异常
        try
        {
            String className2 = "Test";
            Class c2 = Class.forName(className2);
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
        //这个方法还可以快速创建一个类的实例(当不确定创建什么类时可用)
        String s = "java.util.Date";
        try
        {
            Object m = Class.forName(s).newInstance();
            //调用的是默认构造方法,如果想要调用有参构造,
            //必须使用Constructor类中的newInstance方法
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        //3. 简单,int.class也可以返回一个Class对象
        Class c3 = Test.class;
    }

}

下面我们利用反射写一个所有类通用的toString方法(私有域也能访问)

这个公认的一种写法,到后面你会发现会很有用的!!(注释详细)

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;



//通用的toString
class ObjectAnalyzer
{
    private ArrayList<Object> visited = new ArrayList<>();
    //用来记录已经被访问的对象,防止无限递归

    public String toString(Object obj)
    {
        if(obj == null) return "null";
        if(visited.contains(obj)) return "...";
        visited.add(obj);
        Class c1 = obj.getClass();

        //传来的是个字符串
        if(c1 == String.class)
        {
            return (String)obj;
        }

        //传来的是个数组
        if(c1.isArray())
        {
            //cl.getComponentType()返回数组 构成元素的类型
            String r = c1.getComponentType() + "[]{";
            for (int i = 0; i < Array.getLength(obj); i++)
            {
                if(i > 0) r += ",";
                Object val = Array.get(obj, i);
                if(c1.getComponentType().isPrimitive()) //数组里面存的是基本类型
                {
                    r += val;
                }
                else //不是去递归
                {
                    r += toString(val);
                }
            }
            return r + "}";
        }

        //传来的是个自定义类型,里面可能包含多个基本类型或引用类型
        String r = c1.getName();
        do
        {
            r += "[";
            Field[] fields = c1.getDeclaredFields();           
            //拿到obj里面所有的数据域(名字和访问权限)
            AccessibleObject.setAccessible(fields, true); 
            //设置为true,代表忽略Java中的访问控制
            for(Field f : fields)
            {
                if(!Modifier.isStatic(f.getModifiers())) //如果不是静态的
                {
                    if(!r.endsWith("["))
                    {
                        r += ",";
                    }
                    r += f.getName() + "=";

                    try
                    {
                        Class t = f.getType();
                        Object val = f.get(obj);
                        if(t.isPrimitive()) //是基本类型
                        {
                            r += val;
                        }
                        else //不是就去递归
                        {
                            r += toString(val);
                        }
                    }
                    catch (Exception e) { e.printStackTrace(); }
                }
            }
            r += "]";
            c1 = c1.getSuperclass();
        }while(c1 != null);
        return r;
    }
}

测试代码:

class Test
{
    public String name;
    private int age;
    private int[] nums = {1, 2, 3};

    public Test() {}
    public Test(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public static void main(String[] args)
    {
        Test test = new Test("Tom", 18);
        String ret = new ObjectAnalyzer().toString(test);
        System.out.println(ret);
        //运行结果:Test[name=Tom,age=18,nums=int[]{1,2,3}][]
    }
}

下面是Field类中全部方法:

 

 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值