java反射简单介绍以及使用反射时出现的一些常见问题

一、反射的概念

Java反射指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法。这种动态获取类的内容以及动态调用对象的方法称为反射机制。

上面的介绍较为官方,不太理解也没有关系,我们先从为什么存在反射,反射有什么作用开始一点点的了解反射。

正如我们所知,当编译时知道类或对象的具体信息,此时直接对类和对象进行操作即可。即——直接使用类来new出一个对象,然后通过new出来的对象可以调用它的方法以及拿到它的属性。
但是,如果编译不知道类或对象的具体信息,此时应该如何做呢?
此时便可使用反射来实现。比如类的名称放在XML文件中,属性和属性值放在XML文件中,需要在运行时读取XML文件,动态获取类的信息

1.1 反射的入口——Class类

既然要使用反射,那就得谈谈Class类了。Class类是Java 反射机制的起源和入口。用于获取与类相关的各种信息。Class类提供了获取类信息的相关方法
在这里插入图片描述
Class类是所有类的共同的图纸
每个类有自己的对象,好比图纸和实物的关系
每个类也可看做是一个对象,有共同的图纸Class,存放类的结构信息,比如类的名字、属性、方法、构造方法、父类和接口,能够通过相应方法取出相应信息

如果要想使用Class类进行操作,就必须首先产生Class类这个对象,一共有三种方法:

1.1.2使用Class.forName()来获取类对象
   Class<?> aClass = Class.forName("com.bjsxt.pojo.Student");
1.1.3使用类名.class()来获取类对象
Class c = String.class;
1.1.4使用对象名.getClass()来获取类对象
String str=“sxt";
Class clazz = str.getClass();

其中类名.class、对象名.getClass()方式在编码时已经知道了要操作的类,而Class.forName()方式在操作的时候,可以知道,也可以不知道要操作的类。所以当编码时还不知道要操作的具体类,就只能使用Class.forName()方式了。

1.2class类实例化对象

Class类如果使用forName()方法之后,就可以调用Class类中newInstance()无参构造函数方法进行操作。

 Object student = aClass.newInstance();

newInstrance()方法虽然过时了,但是没有什么影响。
也可以通过类对象调用getConstructor()方法,再通过Constructor的newInstance()方法实例化对象。

 public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //使用反射获取类对象
        //1.读取配置文件,或者类的完整路径字符串
        Class<?> aClass = Class.forName("com.bjsxt.pojo.Student");
        //3.从Class信息中获取有参数构造方法
        Constructor<?> constructor = aClass.getConstructor(Integer.class, String.class, Integer.class);
        //突破封装性的限制,即使是private、默认的也可以访问
        constructor.setAccessible(true);
        //4.使用反射创建对象
        Object instance = constructor.newInstance(1, "小明", 17);//传递实参
        System.out.println(instance);
    }
}

当创建完对象之后,便可使用反射操作属性以及方法。

1.3使用反射操作属性

通过Class对象的getFields()或者getField()方法可以获得该类所包括的全部Field属性或指定Field属性。

 //创建student对象
 Object student = constructor.newInstance(1, "小明", 17);//传递实参
 Field name = aClass.getDeclaredField("name");//获取属性
 Field sid = aClass.getDeclaredField("sid");
1.4使用反射执行方法

通过Class对象的getMethods() 方法可以获得该类所包括的全部public方法, 返回值是Method[]
通过Class对象的getMethod()方法可以获得该类所包括的指定public方法, 返回值是Method
每个Method对象对应一个方法,获得Method对象后,可以调用其invoke() 来调用对应方法
Object invoke(Object obj,Object [] args):obj代表当前方法所属的对象的名字,args代表当前方法的参数列表,返回值Object是当前方法返回值,即执行当前方法的结果。

//stuMethod是方法的名字,后两个是参数的类型
 Method stuMethod = aClass.getDeclaredMethod("stuMethod", Integer.class, String.class);
 stuMethod.invoke(student, 15, "小丽");
1.5反射的优缺点

反射优点
功能强大
1.编码时不知道具体的类型,可以使用反射动态操作
2.突破封装的限制,即使private的成员也可以进行操作
反射缺点:
1.代码繁琐,可读性差
2.突破封装的限制,即使private的成员也可以进行操作(既是优点也是缺点)

二、反射时出现的常见问题

在此过程中可能会遇到的一些问题:
问题1:Exception in thread “main” java.lang.NoSuchMethodException: com.bjsxt. why.Dog.(java.lang.String, java.lang.String)。
原因:getConstructor只能获取public方法,无法获取其他修饰符修饰的方法。
解决:调用getDeclaredConstructor()解决,可获取非public修饰的构造方法
问题2:Exception in thread “main” java.lang.IllegalAccessException: Class com. bjsxt. TestConstructor3 can not access a member of class com.bjsxt.Dog with modifiers "
原因:可以获取非public修饰的构造方法,不等于可以运行非public修饰的构造方法,受到了封装性的限制
解决:调用con.setAccessible(true);方法,可以突破封装性的限制。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值