模板和泛型.为什么我可以用C ++而不是Java进行以下操作?我该如何克服呢? [英] Templates and Generics. Why can I do the following in C++ but not in Java? How do I overcome this?

查看:52
本文介绍了模板和泛型.为什么我可以用C ++而不是Java进行以下操作?我该如何克服呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下C ++程序:

Consider the following C++ program:

#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程序:

And now consider the following Java program:

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.因此,泛型来自使用模板的背景,使我感到困惑.

I have majorly been a C++ developer until now and am learning Java for job purposes. So, coming from a background having worked with templates, generics confuse me.

出现我的问题:

在上面的C ++代码中,如果我将string作为模板参数传递,则代码可以编译并运行良好,因为string确实具有size()方法.如果我将int用作模板参数,那么我会得到一个错误,这是可以理解的.这里要注意的一点是,如果我传递一个具有称为size()方法的模板参数,则C ++允许我编译并运行代码.

In the above C++ code, the code compiles and runs fine if I pass string as template parameter because string does have a size () method. If I used int as a template parameter, I would've gotten an error, understandably. The point to note here is that C++ lets me compile and run the code if I pass a template parameter that has a method called size().

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

However, in the Java code, even when I pass Integer as the generic parameter (? is that a term?) which DOES have toHexString(int) method, the program still does not compile. It returns an error:

cannot find symbol

这是什么问题?是什么使我无法使用Java来实现这一目的?

What's the issue here? What prevents me in Java from achieving this behaviour?

该问题被标记为另一个问题的可能重复项:如何调用通用类型对象的方法?我将复制粘贴我的回答,以说明为什么我认为这个问题与众不同.上面的问题潜在地"告诉我如何摆脱错误.我要问的是什么使我无法使用Java达到上述效果?这个问题给了我这种疾病的药,而不是原因.

The question was marked as a possible duplicate for another question: How do I call a method of a generic type object? I'll copy paste my response to why I think the question's different. The above question 'potentially' tells me how to get rid of the error. What I'm asking is what prevents me in Java from achieving the above effect? The said question gives me the medicine of the disease, not the cause.

我在## java上提出了类似的问题,并听说了一个新词-规范化.我想知道是否与此有关?

I raised a similar question on ##java and heard of a new term - reification. I was wondering if it had anything to do with this?

推荐答案

Java泛型通过类型擦除实现.当您具有这样的类签名时:

Java generics are implemented via type erasure. When you have a class signature like this:

class example<T> { }

..该类被编译为常规Java类.为此,T有效地采用了其上限的类型,在这种情况下为 Object .如果您的示例中有诸如函数之类的方法,且参数类型为 T :

.. The class is compiled as a regular Java class. For this, T effectively takes on the type of its upper bound, in this case Object. If you have a method such as the function in your example, with a parameter of type T:

    public void function (T a)

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

... Then this is, at the point that this function is compiled, almost the same as having the parameter be of type Object. As such, you can't call a method such as toHexString on the parameter, because that method is not defined in Object.

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

In C++ on the other hand, a lot of symbol resolution happens when the template is instantiated rather than when it is first compiled. This is the key difference; in Java, a generic class is compiled to bytecode, and so method calls etc must be resolved when the generic class is compiled (that is, the compiler must be able to decide what class or interface the method comes from). In C++, when the compiler encounters a template, it does not try to resolve references or produce object code unless and until the template is instantiated.

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

Another way to think about it: in Java, example<String> and example<Integer> are both implemented via the same class. In C++, they would be two separate classes (both which result from instantiation of the template).

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

This is, in fact, why Java generic classes are not "templates". In C++, a class template allows to instantiate classes (i.e. it serves as a template from which to create classes). In Java, a generic class allows for parametrized types to be implemented by a single class.

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

A Java generic class can be considered to be quite similar to a non-generic class with the type parameters (eg T) being replaced with the bound type (Object unless otherwise specified) - the main difference being that the compiler will perform additional type checking when you call methods on an instance of the class (which has a full type with type arguments, such that T maps to some other type), and will effectively insert casts (so that you can call a method which returns a T, via a reference where T is mapped to some type, without having to cast the return type).

这篇关于模板和泛型.为什么我可以用C ++而不是Java进行以下操作?我该如何克服呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆