首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java泛型方法是如何在幕后工作的?

Java泛型方法是如何在幕后工作的?
EN

Stack Overflow用户
提问于 2018-01-25 08:01:45
回答 2查看 670关注 0票数 4

首先让我承认,我不是一个Java程序员。我从C++的角度看别人的代码,想知道.那到底是怎么回事?

C++确实有类似于C++的泛型方法的模板成员函数,但是C++模板成员函数不能是虚拟的-也就是说,它们不能被覆盖。这个限制对我来说是有意义的,因为虚拟(可覆盖的)函数最终是函数指针,如果虚拟函数可能被模板化,那么类定义就无法知道要为自己生成多少函数指针。

但是Java泛型方法似乎完全可以被派生类覆盖。Java是如何管理它的?

EN

回答 2

Stack Overflow用户

发布于 2018-01-25 08:16:43

据我所知,C++编译器为给定的模板参数实例化(隐式或显式)模板函数,而在运行时,每个模板参数都有不同的函数。

在Java中,没有像泛型实例化或专门化这样的概念。例如,

代码语言:javascript
复制
public class MyClass{

    public void <T> method(T t){ }

}

我们不能实例化并专门化它,比如在C++中。

代码语言:javascript
复制
public void <Integer> MyClass::method(Integer t){ //not valid in Java
   //...
}

相反,类型擦除出现了,因此在运行时,我们有一个泛型方法的未泛化版本,可以重写它。

看看这个简单的类:

代码语言:javascript
复制
public class Main{

    public static void main(String[] args){

        Main m = new Main();
        m.method(10);
        m.methodNumber(10);
        m.methodNumberAnd(10);
        m.methodNumberAnd2(10);
        m.methodInteger(10);
    }
    public <T> void method(T t){ }
    public <T extends Number> void methodNumber(T t){ }
    public <T extends Number & java.io.Serializable> void methodNumberAnd(T t){ }
    public <T extends java.io.Serializable & java.lang.Comparable<T>> void methodNumberAnd2(T t){ }
    public void methodInteger(Integer t){ }
}

还有跑步

代码语言:javascript
复制
javac Main.java
javap -c Main.class

它的内容如下:

代码语言:javascript
复制
public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class Main
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: bipush        10
      11: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      14: invokevirtual #5                  // Method method:(Ljava/lang/Object;)V
      17: aload_1
      18: bipush        10
      20: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      23: invokevirtual #6                  // Method methodNumber:(Ljava/lang/Number;)V
      26: aload_1
      27: bipush        10
      29: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      32: invokevirtual #7                  // Method methodNumberAnd:(Ljava/lang/Number;)V
      35: aload_1
      36: bipush        10
      38: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      41: invokevirtual #8                  // Method methodNumberAnd2:(Ljava/io/Serializable;)V
      44: aload_1
      45: bipush        10
      47: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      50: invokevirtual #9                  // Method methodInteger:(Ljava/lang/Integer;)V
      53: return

  public <T> void method(T);
    Code:
       0: return

  public <T extends java.lang.Number> void methodNumber(T);
    Code:
       0: return

  public <T extends java.lang.Number & java.io.Serializable> void methodNumberAnd(T);
    Code:
       0: return

  public <T extends java.io.Serializable & java.lang.Comparable<T>> void methodNumberAnd2(T);
    Code:
       0: return

  public void methodInteger(java.lang.Integer);
    Code:
       0: return

}

请注意已编译方法的签名:

代码语言:javascript
复制
Method method:(Ljava/lang/Object;)V
Method methodNumber:(Ljava/lang/Number;)V
Method methodNumberAnd:(Ljava/lang/Number;)V
Method methodNumberAnd2:(Ljava/io/Serializable;)V
Method methodInteger:(Ljava/lang/Integer;)V

正如@Eugene所指出的,泛型类型将在&的情况下擦除到第一个类型绑定。

票数 3
EN

Stack Overflow用户

发布于 2018-01-25 08:36:33

C++模板需要每次使用才能根据实际的参数类型生成实际的类。

Java打算生成一个基于类的单一对象参数。在运行时,只保留对象--这称为类型擦除。

代码语言:javascript
复制
public class A<T> {
    public T f(T x) { return x; }
}

public class B extends A<String> {
    @Override
    public String f(String s) { return s.toLowerCase(); }
}

生成的内容类似于:

代码语言:javascript
复制
public class A {
    public Object f(Object x) { return x; }
}

public class B extends A {
    @Override
    public Object f(Object x) { return B.this.f((String)x); }

    public String f(String s) { return s.toLowerCase(); }
}

C++为它提供了一个虚拟方法表,将方法指针替换为该类的方法指针。

Java有一个.class文件,它更像一个C++ .o或.obj,包含有关方法的“链接”信息:它们的签名:名称和完整的参数类型名称。“链接”发生在类加载中。jvm字节码方法调用操作可以处理继承。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48438160

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档