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

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

java范型


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

public class Generics<T> {  
    private T value;  
    public T getValue() {  
        return value;  
    }  
}  
  ||
  \/
public class Generics<Object> {  
    private Object value;  
    public Object getValue() {  
        return value;  
    }  
}  

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

public class AATest {
  public <T> 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."<init>":()V
       4: return
  public <T> 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 "<init>":()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
相关文章
|
2月前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80
|
6月前
|
缓存 安全 算法
Java面试题:如何通过JVM参数调整GC行为以优化应用性能?如何使用synchronized和volatile关键字解决并发问题?如何使用ConcurrentHashMap实现线程安全的缓存?
Java面试题:如何通过JVM参数调整GC行为以优化应用性能?如何使用synchronized和volatile关键字解决并发问题?如何使用ConcurrentHashMap实现线程安全的缓存?
66 0
|
3月前
|
监控 架构师 Java
JVM进阶调优系列(6)一文详解JVM参数与大厂实战调优模板推荐
本文详述了JVM参数的分类及使用方法,包括标准参数、非标准参数和不稳定参数的定义及其应用场景。特别介绍了JVM调优中的关键参数,如堆内存、垃圾回收器和GC日志等配置,并提供了大厂生产环境中常用的调优模板,帮助开发者优化Java应用程序的性能。
|
3月前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
85 3
|
3月前
|
Java Android开发 开发者
【编程进阶知识】精细调控:掌握Eclipse JVM参数配置的艺术
本文详细介绍了如何在Eclipse中配置JVM参数,包括内存的初始和最大值设置。通过具体步骤和截图演示,帮助开发者掌握JVM参数的精细调控,以适应不同的开发和测试需求。
54 1
|
5月前
|
Java
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
|
6月前
|
运维 Java Linux
(九)JVM成神路之性能调优、GC调试、各内存区、Linux参数大全及实用小技巧
本章节主要用于补齐之前GC篇章以及JVM运行时数据区的一些JVM参数,更多的作用也可以看作是JVM的参数列表大全。对于开发者而言,能够控制JVM的部分也就只有启动参数了,同时,对于JVM的性能调优而言,JVM的参数也是基础。
127 8
|
5月前
|
C# 开发者 Windows
震撼发布:全面解析WPF中的打印功能——从基础设置到高级定制,带你一步步实现直接打印文档的完整流程,让你的WPF应用程序瞬间升级,掌握这一技能,轻松应对各种打印需求,彻底告别打印难题!
【8月更文挑战第31天】打印功能在许多WPF应用中不可或缺,尤其在需要生成纸质文档时。WPF提供了强大的打印支持,通过`PrintDialog`等类简化了打印集成。本文将详细介绍如何在WPF应用中实现直接打印文档的功能,并通过具体示例代码展示其实现过程。
440 0
|
6月前
|
存储 Java
java 服务 JVM 参数设置配置
java 服务 JVM 参数设置配置
171 3
|
6月前
|
安全 Java fastjson
JVM 配置参数 -D,-X,-XX 的区别
JVM 配置参数 -D,-X,-XX 的区别
117 2