详解Java反射机制

反射是程序在运行状态下,动态的获取某个类的内部信息的一种操作。例如:类名,包名,所有属性的集合,所有方法的集合,构造方法的集合等。该操作发生在程序的运行时状态,所以编译器管不着有关反射的一些代码,通常只有在运行时才能暴露出程序的内部错误。反射的核心在于‘Class’这个类,本篇将从Class这个类开始介绍有关反射的一些基本的概念,主要内容如下:

  • 获取Class对象
  • 从Class对象中读取字段信息
  • 从Class对象中读取方法信息
  • 获取Class对象中的所有构造方法并使用它们动态创建类对象
  • 反射的一些其他细节

一、获取Class对象

此处的Class是一个具体的类(java.lang.Class),并不是我们自定义一个类时所使用的关键字class。这是一个泛型类,通常有两种方法可以获取该对象。第一种方式,使用类名.class来获取Class对象。

        Class<Integer> integerClass = int.class;
        Class<Double> doubleClass = double.class;
        Class<Character> characterClass = char.class;
        .......
        
        Class<Map> mapClass = Map.class;
        
        Class<String> stringClass = String.class;
        Class<Date> dateClass = Date.class;
        ........

无论是基本数据类型,还是一般的class类型,或是接口类型,都是可以通过.class的方式来获取与之对应的Class对象。第二中获取Class对象的方法是,通过getClass方法,当然不是所有类都提供了这个方法的,例如:Object类就提供这么一个方法:

public final native Class<?> getClass;

还有我们的数组类型:

int array = new int[23];
Class<?> arrayClass = array.getClass;

鉴于不是所有类都提供了这个方法,一般建议使用第一种方式获取Class对象。

下面看看有关我们获取到的这个Class对象的一些基本信息。首先我们可以获取有关该Class对象的名称,包,父类,父接口等信息。

//获取该Class对象代表的类名
public String getName

//获取该Class对象代表的类名,不包含包名
public String getSimpleName

//获取该Class对象所代表的类的包名
public Package getPackage

//获取该类继承的父类对象
public native Class<? super T> getSuperclass;

//获取该类实现的所有接口的集合
public Class<?> getInterfaces

//获取修饰在该类上的访问修饰符
public native int getModifiers;

//获取该类中所有内部类的集合
public Class<?> getClasses
............

还有一些有关注解的信息,由于之前在介绍注解的时候已经说明过,此处不再赘述。上面的这些方法的使用还是比较简单,此处不再演示。

二、获取Class对象中字段信息

类中的字段包括实例域和静态域。在Java反射机制中,使用Field类管理字段信息。

//获取该类中所有字段的集合(public修饰符修饰的)
public Field getFields

//返回指定名称的字段(public修饰符修饰的)
public Field getField(String name)

//获取所有字段的集合,不包括从父类继承的(包括非public)
public Field getDeclaredFields

//获取指定的字段,不包含从父类继承的(可以是非public)
public Field getDeclaredField(String name)

对以上四种获取字段Field的方法做一点说明,getFields或者getField方法可以看见该类所有的被public修饰的字段,包括从父类继承的,但是不可见非public修饰的字段。getDeclaredFields或者getDeclaredField方法可以看见该类所有的字段,包括非public修饰的,但是不可见父类中的字段。接下来,我们看看对获取到的field字段可以做哪些操作:

//获取该字段的名称
public String getName

//获取该字段的访问修饰符
public int getModifiers

//获取指定对象中的该字段的值
public Object get(Object obj)

//设置指定对象中该字段的值
public void set(Object obj, Object value)

//获取该字段的类型
public Class<?> getType 

//判断当前程序是否具有访问该字段的权限
public boolean isAccessible

//flag设为true表示忽略Java的访问检查机制,以允许读写非public的字段
public void setAccessible(boolean flag)
.......

对于以上的几个基本的方法,可以说见名知意,这里需要说明的是get和set方法,先看个例子:

   Class<Student> studentClass = Student.class;
   //这里的school是Student类中的一个属性
   Field f = studentClass .getDeclaredField("school");
   Student s = new Student;
   f.set(s,"yanSchool");
   System.out.println(f.get(s));
输出结果:yanSchool

这里的 f 代表了 school这个实例属性,如果别的类中有相同的属性,我们是可以通过 f为该属性赋值的,当然也可以从某个具有该属性的类中获取该属性的值,前提是具备目标类中的该属性的访问权限。上述的getModifiers返回的是int值,该值代表了一个修饰符,想要转换成我们能看懂的字符串的形式需要使用 Modifier.toString(int a)方法,将刚刚返回的int值作为参数传入即可。

三、获取Class对象的方法信息

无论是静态方法还是实例方法,在Java反射机制中都是使用Method这个类来管理的,一个方法对应于一个Method对象。先看怎么通过Class对象获取其中的方法。

//返回所有被public修饰的方法的集合,包括父类的
public Method getMethods

//返回指定的被public修饰的方法,包括父类中的
public Method getMethod(String name, Class<?>... parameterTypes)

//返回所有的方法的集合(可以有非public),不包括父类的
public Method getDeclaredMethods

//返回本类中声明的指定名称和参数类型的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

对于以上四个方法需要说明一点的是,getMethod或者getDeclaredMethod在获取指定方法的时候,需要传入该方法的形参类型,如果没有传入或者传入错误就会抛出NoSuchMethodException异常。因为方法名和方法参数类型(个数)是唯一确定一个方法的凭据。对于获取到的Method方法有以下一些操作:

//获取该方法的方法名
public String getName

public int getModifiers

//获取该方法的返回类型
public Class<?> getReturnType

//获取所有参数的类型
public Class<?> getParameterTypes

//获取方法声明抛出的异常类型
public Class<?> getExceptionTypes

//将该方法在指定的对象上执行,有形参的需要传入形参值
public Object invoke(Object obj, Object... args)

....//还有一些有关注解的操作,此处不再赘述

上述方法中的invoke方法和之前介绍的字段的get/set方法一样,需要指定目的对象才能使用,因为他们只是代表了具体的一个字段或者一个方法。

public class Student extends People {

    public String school;

    private int sno;

    public void sayHello(String str){
        System.out.println("hello "+str);
    }

    public void sayHello(int s){
        System.out.println("my age is "+s);
    }
}
public static void main(String[] args){

    Class<Student> studentClass = Student.class;
   
    Method method  = studentClass.getMethod("sayHello",String.class);
    
    method.invoke(new Student,"walker");
    }
输出结果:hello walker

四、获取构造方法和创建实例对象

一旦我们获取到了Class对象,我们就可以通过以下的方法进一步获取其中的构造方法,并使用它们创建一个实例对象。

//获取所有被public修饰的构造方法,不包含父类中的
public Constructor<?> getConstructors 

//获取指定的被pubic修饰的构造方法,不包含父类中的
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 

//返回所有的构造方法,可以包含非public修饰的
public Constructor<?> getDeclaredConstructors 

//返回指定的构造方法,可以是非public修饰的
public Constructor<T> getConstructor(Class<?>... parameterTypes)

以上的方法和之前介绍的字段Field,方法Method很是相似。下面我们看看如何使用Constructor做一些事情。

public String getName

public int getModifiers

public Class<?> getParameterTypes

//创建该类的实例对象
public T newInstance(Object ... initargs)

........一些注解有关的信息,可以查看之前的文章

我们主要看看如何通过 newInstance 创建一个实例对象:

public class Student extends People {

    public String school;
    publicint sno;

    public Student(String school,int sno){
        this.school=school;
        this.sno = sno;
    }

    public void sayHello(String str){
        System.out.println("hello "+str);
    }

    public void sayHello(int s){
        System.out.println("my age is "+s);
    }
}
public static void main(String[] args){

        Class<Student> studentClass = Student.class;
        
        Constructor constructor = studentClass.getConstructor(String.class,int.class);

        Student s = (Student) constructor.newInstance("walker", 21);
        System.out.println(s.school+" "+s.sno);
    }
输出结果:walker 21

五、反射机制的一些细节

前面我们一直讨论的都是具体的类,我们可以从这些类中获取到字段,方法,构造器,注解等。java.lang.reflect包中对数组类型增添了专门的类Array来实现反射,这里的Array和数组中的Arrays是不同的。

//创建指定元素类型、指定长度的数组,
public static Object newInstance(Class<?> componentType, int length)

//创建多维数组
public static Object newInstance(Class<?> componentType, int... dimensions)

//获取数组array指定的索引位置index处的值
public static native Object get(Object array, int index)

//修改数组array指定的索引位置index处的值为value
public static native void set(Object array, int index, Object value)

//返回数组的长度
public static native int getLength(Object array)

我们可以通过Array类在运行时动态创建数组和操作数组中的元素,而不必想之前一样必须在编译之前完成数组的创建。需要注意的是此处返回的数组类型是Object而非Object,那时因为前者可以转化成具体类型的数组,后者则不能。

至此,反射的基本内容介绍完了,我们应该知道,虽然反射很是灵活,可以动态的读取类的信息,动态的创建实例对象和数组等,但是没有了编译器的一层检查,很容易导致运行是异常。如果能够用接口来完成的,尽量使用接口来完成。

理解不到之处,还望大家不吝赐教!

http://blog.csdn.net/liujiahan629629/article/details/18013523

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值