资讯 小学 初中 高中 语言 会计职称 学历提升 法考 计算机考试 医护考试 建工考试 教育百科
栏目分类:
子分类:
返回
空麓网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
空麓网 > 计算机考试 > 软件开发 > 后端开发 > Java

关于jvm范型和scala implicit隐式参数以及classTag[T] typeTag[T]的一点思考

Java 更新时间: 发布时间: 计算机考试归档 最新发布

关于jvm范型和scala implicit隐式参数以及classTag[T] typeTag[T]的一点思考

java范型

一般都是java中的范型在编译的时候,都会进行类型擦除,那么在真正运行的时候,我们是获取不到范型信息的,因为编译器在编译的时候,会把对应的范型用对应的限定类型给替换掉(如果没有限定,则是object),如下:

public class Generics {  
    private T value;  
    public T getValue() {  
        return value;  
    }  

}  
  ||
  /
public class Generics {  
    private Object value;  
    public Object getValue() {  
        return value;  
    }  

}  
 

这是正确的,但是我们运行如下代码(会发现不一样的地方):

public class AATest {

  public  T get(T a){

    return a;
  }

  public static void main(String[] args) {
    AATest a = new AATest();
    String b = a.get("aaa");
  }
}

String b = a.get("aaa"); 看到我们居然把可以范型为T(也就是object)的类型的值,赋值给String类型的变量,这难道是编译器没有进行类型擦除么?
我们可以用命令javap -c AATest.class反编译下字节码,如下:

public class AATest {
  public AATest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public  T get(T);
    Code:
       0: aload_1
       1: areturn

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class AATest
       3: dup
       4: invokespecial #3                  // Method "":()V
       7: astore_1
       8: aload_1
       9: ldc           #4                  // String aaa
      11: invokevirtual #5                  // Method get:(Ljava/lang/Object;)Ljava/lang/Object;
      14: checkcast     #6                  // class java/lang/String
      17: astore_2
      18: return

可以看到有这么两行字节码:

11: invokevirtual #5                  // Method get:(Ljava/lang/Object;)Ljava/lang/Object;
14: checkcast     #6                  // class java/lang/String

invokevirtual这一行表明编译器确实进行了类型擦数,因为能偶看到调用的是object类型的方法
checkcast这一行表明,jvm字节码进行了String的类型转换
原来是因为我们调用的是a.get("aaa"),其中aaa是String类型的变量,这样编译器在编译的时候,就会做一层强制转换。所以这和范型擦数不冲突。
可以参考Java泛型类型擦除以及类型擦除带来的问题

scala classTag[T] typeTag[T]

在scala代码中我们会经常看到类似与这样的代码:

def max[T : Comparator] (a:T, b:T) = { … }

其实这种与以下代码是等同的:

def max[T](a:T, b:T) (implicit cp : Comparator[T]) = {
        }

[T: Comparator],它主要做了两件事:第一,引入了一个参数类型 T;第二,增加了一个隐式参数 Comparator[T]。
如果在调用该方法的时候没有显式得传入 Comparator[T]类型的参数,则编译器会自动会从上下问中去查找。所以以下两种方式调用都是可以的:

// 这种方式说明上下文中有隐式参数
max(a,b)
// 这种是显式的传入对应类型的参数
max(a,b)(cp)

在上面说到对于java语言来说,会在编译器期间擦除掉类型,但是对于scala来说,我们在编译器阶段是可以保存类型T的,这就是接下来说的classTag[T] typeTag[T]:

def max[T : classTag] (a:T, b:T) = { … }
def max[T : typeTag] (a:T, b:T) = { … }

与上面代码不同的是,该隐式参数classTag[T],typeTag[T]是由编译器给传递进去的,所以我们不需要显式传入。
关于这两者的区别,可以参考:谈谈 Scala 的运行时反射,
对于怎么在运行期间或得对应的T的具体类型,可以参考SPARK中的ExpressionEncoder:

 val mirror = ScalaReflection.mirror
 val tpe = typeTag[T].in(mirror).tpe

 val cls = mirror.runtimeClass(tpe)

而对于classTag获取运行时的T类型,如下代码:

val cl = classTag[T].runtimeClass
转载请注明:文章转载自 http://www.konglu.com/
免责声明:

我们致力于保护作者版权,注重分享,被刊用文章【关于jvm范型和scala implicit隐式参数以及classTag[T] typeTag[T]的一点思考】因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理,本文部分文字与图片资源来自于网络,转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即通知我们,情况属实,我们会第一时间予以删除,并同时向您表示歉意,谢谢!

我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2023 成都空麓科技有限公司

ICP备案号:蜀ICP备2023000828号-2