JAVA的反射机制

刚学习反射机制不久,参考了几篇博客,然后再自己吸收一下,记录自己的足迹。
1.反射机制是什么


反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。


2.反射机制能做什么


反射机制主要提供了以下功能: 
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理。




正如上面提到的,反射机制可以在运行状态中,获取任意类的所有属性和方法,甚至还能获取字段的具体指以及调用任意方法。
下面给出两个得到Class类的实例对象的方法(假设才e是E类的实例化对象):
1.Class c1=e.getClass();
2.Class c1=Class.forName("...");
3.Class c1=E.class;
其中第二个方法forName的字符串应该传入那个类所在的包名加类名,例如可以传入"java.util.Random"。




除此之外还可以用反射机制直接实例化某类的对象,下面给出实例化Random类的例子:
Random random=(Random)Class.forName("java.util.Random").newInstance();
注意,如果希望用这种方法向构造器提供参数,则应该用Constructor类中的newInstance()方法。






下面就写个小例子,用来获取某个类的全部属性,包括字段,构造器以及全部方法。
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Scanner;


public class reflection {
public static void main(String[] args){
String name="";
Scanner cin=new Scanner(System.in);
while(cin.hasNext())
{
name=cin.nextLine();//输入包名加类名
try {
Class c1= Class.forName(name);//通过第二种方法户获得Class类的实例
Class superc1=c1.getSuperclass();//获取该类的超类的Class类
String modifiers=Modifier.toString(c1.getModifiers());//modifiers存储的是该类的修饰符
if(modifiers.length()>0)System.out.print(modifiers+" ");
System.out.print("class "+name);
if(superc1!=null&&superc1!=Object.class)System.out.print(" extends "+superc1.getName());//判断超类是否存在并且超类不是Object类
System.out.print("\n{\n");
printConstructors(c1);//用于打印构造器的方法
System.out.println();
printMethods(c1);//用于打印方法的方法
System.out.println();
printFields(c1);//用于打印字段的方法
System.out.println("}");
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}


private static void printFields(Class c1) {
Field[] fields=c1.getDeclaredFields();//获取表示该类所有字段的Field类
for(Field f:fields)
{
Class types=f.getType();//获取该字段的类型
String name=f.getName();//获取该字段的名字
System.out.print("  ");
String modifiers=Modifier.toString(f.getModifiers());//获取该字段的修饰符
if(modifiers.length()>0)System.out.print(modifiers+" ");
System.out.println(types.getName()+" "+name+";");
}
}


private static void printMethods(Class c1) {
Method[] methods=c1.getDeclaredMethods();//获取表示该类所有方法的Method类
for(Method m:methods)
{
Class returnType=m.getReturnType();//获得该方法的返回值类型
String name=m.getName();//获取该方法的名字
System.out.print("  ");
String modifiers=Modifier.toString(m.getModifiers());//获取该方法的修饰符
if(modifiers.length()>0)System.out.print(modifiers+" ");
System.out.print(returnType.getName()+" "+name+"(");
Class[] types=m.getParameterTypes();//获取该方法每个参数的类型,返回一个Class数组
for(int j=0;j<types.length;j++)
{
if(j>0)System.out.print(",");
System.out.print(types[j].getName());//打印每一个参数的类型
}
System.out.println(");");
}
}


private static void printConstructors(Class c1) {
Constructor[] constructors=c1.getConstructors();//获取表示该类所有构造器的Constructor类
for(Constructor c:constructors)
{
String name=c.getName();//获取该构造器名字
System.out.print("  ");
String modifiers=Modifier.toString(c.getModifiers());//获取该构造器的修饰符
if(modifiers.length()>0)System.out.print(modifiers+" ");
System.out.print(name+"(");
Class[] types=c.getParameterTypes();//获取该构造器每个参数的类型,返回一个Class数组
for(int j=0;j<types.length;j++)
{
if(j>0)System.out.print(",");
System.out.print(types[j].getName());//打印每一个参数的类型
}
System.out.println(");");
}

}
}




可以看出方法基本一样,只不过用到的类不同,分别是Constructor,Method,Field类。
如果我们输入java.lang.Double,就会输出以下结果:
public final class java.lang.Double extends java.lang.Number
{
  public java.lang.Double(double);
  public java.lang.Double(java.lang.String);


  public boolean equals(java.lang.Object);
  public static java.lang.String toString(double);
  public java.lang.String toString();
  public int hashCode();
  public static int hashCode(double);
  public static double min(double,double);
  public static double max(double,double);
  public static native long doubleToRawLongBits(double);
  public static long doubleToLongBits(double);
  public static native double longBitsToDouble(long);
  public volatile int compareTo(java.lang.Object);
  public int compareTo(java.lang.Double);
  public byte byteValue();
  public short shortValue();
  public int intValue();
  public long longValue();
  public float floatValue();
  public double doubleValue();
  public static java.lang.Double valueOf(java.lang.String);
  public static java.lang.Double valueOf(double);
  public static java.lang.String toHexString(double);
  public static int compare(double,double);
  public static boolean isNaN(double);
  public boolean isNaN();
  public static boolean isInfinite(double);
  public boolean isInfinite();
  public static boolean isFinite(double);
  public static double sum(double,double);
  public static double parseDouble(java.lang.String);


  public static final double POSITIVE_INFINITY;
  public static final double NEGATIVE_INFINITY;
  public static final double NaN;
  public static final double MAX_VALUE;
  public static final double MIN_NORMAL;
  public static final double MIN_VALUE;
  public static final int MAX_EXPONENT;
  public static final int MIN_EXPONENT;
  public static final int SIZE;
  public static final int BYTES;
  public static final java.lang.Class TYPE;
}
可以看出在运行时候我们获得了这个类的所有方法,字段和构造器,还包括它的超类。


下面我们还可以获得某个字段的具体的值而不是仅仅知道它的类型和修饰符以及名字了。
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;


public class ObjectAnalyzer {
private ArrayList<Object> visited=new ArrayList<>();
public String toString(Object obj)
{
if(obj==null)return "null";//如果该类为Object类,直接返回null
if(visited.contains(obj))return "...";//如果该类已经调用过了,返回null
visited.add(obj);//将该类加入到visited标记数组中
Class c1=obj.getClass();//获取该类的Class对象
if(c1==String.class)return (String)obj;//如果是该类是String类,直接返回
if(c1.isArray())//判断类是不是数组类
{
String r=c1.getComponentType().getName()+"[]{";//获得数组类的名称
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;//如果是基本类型如int double 直接加上
else r+=toString(val);//如果不是,递归调用toString
}
return r+"}";
}
String r=c1.getName();
do
{
r+="[";
Field[] fields=c1.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);//利用AccessibleObject类提供的setAccessible把所有字段设置为可访问的,不然会出现有些字段不可访问的问题
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);//如果不是递归调用toString方法
}catch(Exception e)
{
e.printStackTrace();
}
}
}
r+="]";
c1=c1.getSuperclass();//获取该类的超类,继续执行
}
while(c1!=null);
return r;
}
}
这里利用递归调用实现了一个通用的toString方法,递归调用需要解决一个问题,就是循环调用可能引起无限递归,所以设置了标志数组visited以及一些判断来防止这个的发生,这样通用的toString就实现了,在自己写的类中也可以直接使用它而不用自己重新写了。如下:
public String toString()
{
return new ObjectAnalyzer().toString(this);
}
我们创建一个int数组
int[] num=new int[]{1,2,3,4,5};
调用System.out.println(new ObjectAnalyzer().toString(num));
就会输出int[]{1,2,3,4,5}
我们再创建一个ArrayList数组:ArrayList<Integer>array=new ArrayList<>();
调用System.out.println(new ObjectAnalyzer().toString(array));
就会输出java.util.ArrayList[elementData=java.lang.Object[]{java.lang.Integer[value=2][][],java.lang.Integer[value=4][][],java.lang.Integer[value=6][][],java.lang.Integer[value=8][][],java.lang.Integer[value=10][][],null,null,null,null,null},size=5][modCount=5][][]
对于非数组的类,它也能很好的显示Employee[name=Jack,salary=2000.0,hireday=java.time.LocalDate[year=2016,month=2,day=14][]][]
这样就利用反射完成了一个通用toString的方法


另外还有一个是用反射调用任意类的方法,以后会补上,同时官方也建议仅在必要的时候使用反射来调用方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值