java - 模板和泛型。为什么我可以在 C++ 中执行以下操作,但不能在 Java 中执行?我该如何克服这个问题?

标签 java c++ templates generics

<分区>

考虑以下 C++ 程序:

#include <iostream>
using namespace std;

template<typename T>
class example
{
    public:
    void function (T a)
    {
        std::cout<<a.size ();
    }
};

int main() {
    example<string> a; // this doesn't
    string b = "a";
    //example<int> a; This gives an error
    a.function (b);
    // your code goes here
    return 0;
}

现在考虑以下 Java 程序:

import java.util.ArrayList;

class example<T> {

    public void function (T a)
    {
        System.out.println (a.toHexString(5)); /* this does not compile even when T is Integer */
    }


}

public class  Main
{
    public static void main (String[] args)
    {
        example<Integer> a = new example<Integer> (); 
        Integer b = 2;
        a.function(b);

        return;
    }
}

到目前为止,我主要是一名 C++ 开发人员,并且出于工作目的正在学习 Java。因此,从使用模板的背景来看,泛型让我感到困惑。

回到我的问题:

在上面的 C++ 代码中,如果我将字符串作为模板参数传递,代码可以正常编译和运行,因为字符串确实有一个 size () 方法。如果我使用 int 作为模板参数,我会得到一个错误,这是可以理解的。这里要注意的一点是,如果我传递一个具有名为 size() 的方法的模板参数,C++ 允许我编译和运行代码。

但是,在 Java 代码中,即使我将 Integer 作为通用参数传递(?这是一个术语吗?),它确实具有 toHexString(int) 方法,程序仍然无法编译。它返回一个错误:

cannot find symbol

这里有什么问题?是什么阻止我在 Java 中实现这种行为?

编辑:该问题被标记为可能与另一个问题重复: How do I call a method of a generic type object? 我将复制粘贴我对为什么我认为这个问题不同的回答。 上面的问题“可能”告诉我如何摆脱错误。我想问的是,是什么阻止了我在 Java 中实现上述效果?上述问题给了我疾病的药物,而不是原因。

我在##java 上提过类似的问题,听说了一个新名词——物化。我想知道这是否与此有关?

最佳答案

Java 泛型是通过类型删除 实现的。当你有这样的类签名时:

class example<T> { }

.. 该类被编译为常规 Java 类。为此,T 有效地采用了其上限的类型,在本例中为 Object。 .如果您有一个方法,例如示例中的函数,其参数类型为 T :

    public void function (T a)

... 然后,在编译此函数时,几乎与参数类型为 Object 相同.因此,您不能调用 toHexString 之类的方法。在参数上,因为该方法未在 Object 中定义.

另一方面,在 C++ 中,很多符号解析发生在模板实例化时而不是首次编译时。这是关键的区别;在 Java 中,泛型类被编译为字节码,因此在编译泛型类时必须解析方法调用等(也就是说,编译器必须能够决定该方法来自哪个类或接口(interface))。在 C++ 中,当编译器遇到模板时,它不会尝试解析引用或生成目标代码,除非并且直到模板被实例化。

另一种思考方式:在 Java 中,example<String>example<Integer>都是通过同一个类实现的。在 C++ 中,它们将是两个独立的类(均由模板的实例化产生)。

事实上,这就是为什么 Java 泛型类不是"template"的原因。在 C++ 中,类模板 允许实例化类(即它用作创建类的模板)。在 Java 中,泛型类允许参数化类型由单个类实现。

Java 泛型类可以被认为与类型参数(例如 T )被替换为绑定(bind)类型( Object 除非另有说明)的非泛型类非常相似 - 主要区别在于当您在类的实例上调用方法时,编译器将执行额外的类型检查(它具有带类型参数的完整类型,这样 T 映射到其他类型),并且会有效地插入强制转换(以便您可以调用一种返回 T 的方法,通过引用将 T 映射到某种类型,而无需转换返回类型)。

关于java - 模板和泛型。为什么我可以在 C++ 中执行以下操作,但不能在 Java 中执行?我该如何克服这个问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31513892/

相关文章:

java - 是否有 JSON_CONTAINS 谓词的 QueryDSL 表示?

c++ - IDA pro 'this' 关键字

c++ - 当我移动轨迹栏时,如何防止控件(选项卡)在 Windows 通用控件 6.0 中闪烁和消失?

asp.net - 如何在不访问 .ASP 文件的情况下自定义 Volusion 模板

c++ - 带有 size_t 模板参数的函数

非专用模板类型对象的 C++ 列表?

Java 用户界面

java - 插入哨兵双向链表实现的优先级队列

c++初学者使用while循环生成随机数

java - 如何在 Java 中搜索键/值对的字符串