Java 接口(interface)和模板的混淆

标签 java templates interface

我正在阅读一些关于某些不同编程语言中模板之间差异的问题。我明白这主要归功于以下问题:What are the differences between Generics in C# and Java... and Templates in C++? 。然而,当他开始谈论接口(interface)并添加一些东西时,我确实对接受的答案的结尾感到有点困惑。我主要从这个问题了解接口(interface)的概况:Explaining Interfaces to Students 。我仍然对问题中所说的内容感到困惑。那么有人可以更好地解释最后一部分吗:

Because of this, the C++ compiler places no restrictions on what you can do with templates - basically any code you could write manually, you can get templates to write for you. The most obvious example is adding things:

In C# and Java, the generics system needs to know what methods are available for a class, and it needs to pass this down to the virtual machine. The only way to tell it this is by either hard-coding the actual class in, or using interfaces. For example:

string addNames( T first, T second ) { return first.Name() + second.Name(); }

That code won't compile in C# or Java, because it doesn't know that the type T actually provides a method called Name(). You have to tell it - in C# like this:

interface IHasName{ string Name(); }; string addNames( T first, T second ) where T : IHasName { .... }

And then you have to make sure the things you pass to addNames implement the IHasName interface and so on. The java syntax is different (), but it suffers from the same problems.

The 'classic' case for this problem is trying to write a function which does this

string addNames( T first, T second ) { return first + second; }

You can't actually write this code because there are no ways to declare an interface with the + method in it. You fail.

C++ suffers from none of these problems. The compiler doesn't care about passing types down to any VM's - if both your objects have a .Name() function, it will compile. If they don't, it won't. Simple.

我真的很想理解这个答案中的代码,因为我很困惑 .Name() 方法如何在 IHasName 接口(interface)中工作。有人有一个更好的例子,可以进一步解释如何使用接口(interface)向 Person 类添加名称之类的东西或其他东西......

编辑:我对 Java 代码更感兴趣。

最佳答案

“+”在 C++ 中编译的原因是 C++ 模板(C++ 专家请原谅我的笨拙)就像巨大的宏。它将等到模板实例化后检查每个操作是否可行(仍在编译时,正如 foo 在他们的评论中警告我的那样)。

例如这段代码:

#include "stdafx.h"

#include <stdio.h>

#include <vector>
#include <iostream>

template <class T> class adder {
public:
    adder();
    T add(T t1, T t2);
};


template <class T> adder<T>::adder() {}

template <class T> T adder<T>::add (T t1, T t2) {
        return t1 + t2;
}

using namespace std;

typedef vector<int> int_vector;


int _tmain(int argc, _TCHAR* argv[])
{

    adder<int_vector> vector_adder;
    int_vector v1;
    int_vector v2;

    v1.push_back(1);
    v1.push_back(2);

    v2.push_back(3);
    v2.push_back(4);
    v2.push_back(5);

    // will fail here, in compile time!
    int_vector v3 = vector_adder.add(v1, v2);

    for (int_vector::iterator it = v3.begin(); it != v3.end(); it++) {
        cout << *it;
    }

    return 0;
}

在我尝试添加两个 vector 之前,它会完美地工作;在那一刻,C++ 编译器将意识到我在模板中使用的实际类型没有重载。但是,我可以在模板中定义一些其他操作,如果我没有尝试添加实际类型,编译器将不会意识到(然后它将尝试解决宏)。然而类似 adder<int>会完美地工作。

Java 不允许您达到这一点,因为它不允许对泛型类型进行任何实际操作(定义泛型包含很好,例如 java.util.* 下的类,但除此之外就很少了)。最好的办法是选择有界类型泛型,就像 java 文档中一样:

public class NaturalNumber<T extends Integer> {

    private T n;

    public NaturalNumber(T n)  { this.n = n; }

    public boolean isEven() {
        return n.intValue() % 2 == 0;
    }

    // ...
}

在这里您可以将泛型的类型限制为某个父类(super class),并对其进行一些操作。

关于Java 接口(interface)和模板的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21171688/

相关文章:

java - 为什么java中的abs()不起作用?

java - 用于拆分数字表达式的正则表达式

用于非类型模板参数的 c++ enable_if

Python - 创建类似命令行的界面来加载模块/函数

.net - 如何在c#中定义接口(interface)的默认实现?

java - 我想将多个 JSON 对象合并到一个数组中

java - 使用基于事件的计时器与轮询的性能注意事项

c++ - std::hash 特化仍未被 std::unordered_map 使用

html - golang html 模板不显示任何内容

java - Java中的类中可以嵌套注解吗?