解决:Scala反射中Boolean等值类型 type mismatch 问题

描述问题

使用 scala 反射过程中,传入为值类型,比如Boolean时,会出现类型不匹配的情况

type mismatch;
found   : Boolean(true)
required: Object

xxxMethod.invoke(new xxx, true)

解决方案

不多说,先放解决方案

package Reflect

class CopyToAnother {

	private def findBoolean(boolean: Boolean): Unit = {
		println(f"findBoolean ===> $boolean")
	}

	private def findString(string: String): Unit = {
		println(f"findString ===> $string")
	}

}


object CopyToAnother {
	def main(args: Array[String]): Unit = {

		val methods1 = classOf[CopyToAnother].getDeclaredMethods
		for (m <- methods1) {
			println(m)
		}

		/**
		 * private void Reflect.CopyToAnother.findBoolean(boolean)
		 * private void Reflect.CopyToAnother.findString(java.lang.String)
		 * public static void Reflect.CopyToAnother.main(java.lang.String[])
		 */

		// work
		val findStringMethod = classOf[CopyToAnother].getDeclaredMethod("findString", classOf[String])
		findStringMethod.setAccessible(true)
		findStringMethod.invoke(new CopyToAnother, "ssss") // findString ===> ssss

		// fail
		val findBooleanMethod = classOf[CopyToAnother].getDeclaredMethod("findBoolean", classOf[Boolean])
		findBooleanMethod.setAccessible(true)
		findBooleanMethod.invoke(new CopyToAnother, true)

		/**
		 * type mismatch;
		 * found   : Boolean(true)
		 * required: Object
		 * findBooleanMethod.invoke(new CopyToAnother, true)
		 * */

		// fix
		val findBooleanMethodFix = classOf[CopyToAnother].getDeclaredMethod("findBoolean", classOf[Boolean])
		findBooleanMethodFix.setAccessible(true)
		findBooleanMethodFix.invoke(new CopyToAnother, Boolean.box(true)) // findBoolean ===> true
		findBooleanMethodFix.invoke(new CopyToAnother, true.asInstanceOf[AnyRef]) // findBoolean ===> true


	}
}

问题原因

观察一下报错,主要是类型不匹配导致,那么先看下scalainvoke源码;其实可以看到调用的是javainvoke;传入的参数第一个Object是实例对象,第二个Object是反射方法中参数的值,它的类型是 Object,这就是问题的关键;其实是scala的Boolean和java中的Boolean代表含义并不一致造成的,换句话说,scala 中的Boolean更像是java中的boolean,而java的Boolean则是包装类

···

    @CallerSensitive
    public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);
    }

···
java数据结构

在这里插入图片描述

Scala 数据类型

*可以看到,scalaBoolean等并不是AnyRef的子类,而AnyRef恰好表示的是java.lang.Object*;这也就讲通了为什么invoke会报错,因为压根就是类型不匹配;而String呢?scalaString用的就是JavaString啊!

在这里插入图片描述

Any是所有类型的超类型,也称为顶级类 型。它定义了一些通用的方法如equalshashCodetoStringAny有两个直接子类:AnyValAnyRefAnyVal代表值类型。有9个预定义的非空的值类型分别是:DoubleFloatLongIntShortByteCharUnitBooleanUnit是不带任何意义的值类型,它仅有一个实例可以像这样声明:()。所有的函数必须有返回,所以说有时候Unit也是有用的返回类型。AnyRef代表引用类型。所有非值类型都被定义为引用类型。在Scala中,每个用户自定义的类型都是AnyRef的子类型。如果Scala被应用在Java的运行环境中,AnyRef相当于java.lang.Object。 --ref:https://docs.scala-lang.org/zh-cn/tour/unified-types.html

既然知道原因了,那就简单了,无非是吧AnyVal转成AnyRef,以下就是两种思路,第一种很简单,强转:ture.asInstanceOf[AnyRef], 但是这个实在有点违和;还有一种就是装箱!自带方法

More

既然都看到这了,求知欲还挺强啊,哈哈;主要检索还是来自官网:https://www.scala-lang.org/api/2.12.8/scala/Boolean.html 官方就是这么解释的:scala中Boolean更像是Java中的基本数据类型boolean,是AnyVal的子类;

在这里插入图片描述

去源码里面搜一下 object Boolean,好家伙,隔这手动装箱呢?你看java多乖,会自动完成装箱,而scala则需要使用装箱方法,Object BooleanBoolean的伴生类,其中的方法类似java的静态方法,直接Boolean.box(x),最终会返回java.lang.Boolean的对象了

在这里插入图片描述

都到这里,那就肯定ok了吧,以下是java版本的反射,可以结合起来看

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class CTA {

    private void findBoolean(Boolean i) {
        System.out.println(i);
    }

    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Method findBoolean = CTA.class.getDeclaredMethod("findBoolean", Boolean.class);
        findBoolean.invoke(new CTA(), true);  // true

    }
}

Ref

  • https://www.scala-lang.org/api/2.12.8/scala/Boolean$.html
  • https://docs.scala-lang.org/zh-cn/tour/unified-types.html
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值