反射的基本使用

本文深入探讨Java反射机制,包括如何获取类的各种属性如字段、方法等,并通过示例代码展示了反射的具体应用。此外,还讨论了反射过程中的注意事项及如何正确使用反射。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 


       反射就是把java类中的各种属性映射到另一个java类中,本以为我对反射还学得挺不错的,后来做着做着实验,发现杯具了。这个实验就是把一个类的所有东西打印出来,是的,所有,包括方法是如何具体实现的,然后我就拿前一篇写的枚举那个Animals2的类进行反射,里面阿猫阿狗里面的内容反射不出来,本想用递归的,结果你懂的,一个类本身拥有五个自己的实例对象,但是当我用暴力反射的时候,每个类有五个自己的实例对象,五个实例对象自己各自也含有五个实例对象…….一直不断循环,结果虚拟机不干了,抛出个异常,但是如果只打印一般的信息,比如把field,method,package,classname之类的按顺序打印出来就相对简单很多,唯一麻烦的就是排版问题,先把我写的代码弄上来,再进一步解释:

public class ReflectAnimal2 {

    

    public static void main(String[] args) throws ClassNotFoundException {

       Class clazz = Class.forName("it.cast.heima.Animals2");

       printAll(clazz);         

    }

    //打印出所有字段的值,不包括父类的

    private static void printFileds(Class clazz) throws ClassNotFoundException {

       Field[] fields = clazz.getDeclaredFields();

       String modName;

       String fieldName;

       Class typeName;

       for(Field field: fields) {

           field.setAccessible(true);

           modName = Modifier.toString(field.getModifiers());

           fieldName = field.getName();

           typeName = field.getType();

           System.out.print("  " + modName);

           System.out.print("  " + typeName.getName());

           System.out.println(" " + field.getName()+"");

       }

    }

    //打印出所有东西(包名,类名,字段,方法,但写的时候忘了把构造函数弄上去了)

    public static void printAll(Class clazz) throws ClassNotFoundException {

       printPackage(clazz);

       printClassName(clazz);

       printFileds(clazz);

       printMethod(clazz);

    }

//打印出所有方法

    private static void printMethod(Class clazz) {

       Method[] methods= clazz.getDeclaredMethods();

       String modName;

       String fieldName;

       Class retName;

           for(Method method: methods) {

           method.setAccessible(true);

           modName = Modifier.toString(method.getModifiers());

           fieldName = method.getName();

           retName = method.getReturnType();

           Type[] types = method.getParameterTypes();

           System.out.print("  " + modName);

           System.out.print(" " + retName.getName());

           System.out.print(" " + method.getName()+"(");

           StringBuffer sb = new StringBuffer();

           for(Type type: types) {

              sb = sb.append( type + ",");

           }

           if(sb.length() != 0) {

               System.out.println(sb.substring(0, sb.length()-1) + ")");

               continue;

           }

           System.out.println(sb +")");

       }

       

    }

    //打印出类名

    private static void printClassName(Class clazz) {

       System.out.print(Modifier.toString(clazz.getModifiers()));

       System.out.println(" " + clazz.getName()+ "{");      

    }

    public static void printPackage(Class clazz) {

       System.out.println(clazz.getPackage().toString());

    }

}


 

打印结果如下:

package it.cast.heima

public it.cast.heima.Animals2{

  private  int age

  public  java.lang.String name

  protected  [I a

  public static final  it.cast.heima.Animals2 Dog

  public static final  it.cast.heima.Animals2 CAT

  public static final  it.cast.heima.Animals2 MONKEY

  public static final  it.cast.heima.Animals2 PERSON

  public  void scream()

 private java.lang.String say(class java.lang.String,int)

那个枚举类我自己增加了一些字段,还增加了带参数的有返回值的一个方法(增加难度)。另外我发现上面这段代码漏掉了构造方法= =不过差不多,对于反射,基本上只要了解如何得到一个类的field字段,基本上想要反射其他内容,仿造一下做法就得了。所以就只解释下如何获得一个类的所有字段吧。首先你要加载要反射的类进虚拟机,要不然白搭。加载方法有三种,Class.forName(), ClassName.class或者在一个实例对象上调用它的getClass()方法。好了,类的字节码得到了,于是你可以发现在Class类文档上有多个get方法,这些都是返回以下该类的包名啊,修饰符啊,字段啊,方法啊等等等等,为了得到这个类的字段,你可以用getFields()得到所有字段,并且返回一个Field数组,然后你遍历的输出来看一下,就发现你得到只是公有的字段,而且还包括父类的(上面这个例子父类是object,没字段)。所以你可以只用getDeclaredFields()方法获得所有的字段,包括public,private,protect和默认的(什么也没写那种)修饰符,但不包括父类的,这个文档也有说明。获得所有字段还不行,你还得有访问权限,调用setAccessible方法,默认情况下是不给你访问的,你非要访问的话。强暴它一下就能得到了,这个是方老师视频上说的,我一边看还一边笑= =真的太风趣了,这个就是所谓暴力反射。。。好了,反射其他内容就不再多做讲解了,操作大同小异。

    反射出来当然还要调用,要不反射出来就没意义了,你要想调用它的方法,或者该方法的实例对象,然后invoke,传个对象,传参数进去就得了。静态方法可以写null表示没有对象,无参数的话也是填null;你也可以先new一个对象出来,怎么new?获得构造方法,调用newInstance方法就行了,如果那个对象有无参构造函数,可以直接clazz.newInstance,这是sun为了方便咱们这些有经验的开发人员才弄这么个方法出来的^ ^

    隔天补充:反射内部类问题,其实内部类反射大同小异,只是内部类的名字有点怪异,格式一般为:外部类名$内部类名.class,所以加载进来的时候要把类名写好。另外非静态内部类构造函数,编译器默认会带有一个参数,参数类型为外部类的实例对象的引用。其实可以这么理解,要是没有外部类的实例对象,也就new不出内部类的实例对象出来,所以内部类的构造方法才需要传递一个实例对象的引用进去。至于静态类,参数类型为null。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值