Java泛型,支持“;专业化;?与C+的概念相似性+;模板?
我知道很多如何使用C++模板,请注意,我不是专家。对于Java泛型(以及Scala),我有自己的困难。也许是因为我试图把我的C++知识翻译成java世界。我在别处读到,“它们没有什么相似之处:java泛型只是语法省糖的转换,C++模板只是一个美化的预处理器”:-(<)/P> 我很确定,这两种观点都有点简化。因此,为了理解大的差异和细微的差异,我尝试从专业化开始: 在C++中,我可以设计一个模板(函数类),该模板作用于支持我所需操作的任何类型的Java泛型,支持“;专业化;?与C+的概念相似性+;模板?,java,c++,generics,template-specialization,Java,C++,Generics,Template Specialization,我知道很多如何使用C++模板,请注意,我不是专家。对于Java泛型(以及Scala),我有自己的困难。也许是因为我试图把我的C++知识翻译成java世界。我在别处读到,“它们没有什么相似之处:java泛型只是语法省糖的转换,C++模板只是一个美化的预处理器”:-( 我很确定,这两种观点都有点简化。因此,为了理解大的差异和细微的差异,我尝试从专业化开始: 在C++中,我可以设计一个模板(函数类),该模板作用于支持我所需操作的任何类型的T: template<typename T> T
T
:
template<typename T>
T plus(T a, T b) { return a.add(b); }
即使所有其他类型仍然可以使用“默认”实现,现在我为MyX
添加了一个特殊的实现——没有运行时开销
是否存在具有相同用途的Java泛型机制?当然,在编程中,一切都是可行的,但我的意思是,从概念上讲,没有任何技巧和魔术?嗨
java泛型,它与C++模板不同。 例如:
Java代码: public <T> T sum(T a, T b) {
T newValue = a.sum(b);
return newValue;
}
publictsum(ta,tb){
T newValue=a.和(b);
返回新值;
}
在java中,这段代码不起作用,因为泛型的基类是java.lang.Object,所以只能使用这个类的方法
您可以这样构造此方法:
public <T extends Number> T sum(T a, T b) {
T newValue = a.sum(b);
return newValue;
}
public Object plus(Object that) {
return this.plus((Integer)that);
}
public static <T extends Addable<T>> product (int times, T factor) {
T result = factor;
while(n > 1) {
result = sum(result, factor);
}
return result;
}
publictsum(ta,tb){
T newValue=a.和(b);
返回新值;
}
在本例中,泛型的基础是类java.lang.Number,因此可以使用整数、双精度、长ecc
方法“sum”取决于java.lang.Number的实现
再见否-但您的特定问题更像是一个过载问题 定义2个
加上这样的方法是没有问题的
<T extends Addable>
T plus(T a, T b) { .. }
MyX plus(MyX a, MyX b) { .. }
如果每个Si
都是Ti
对于泛型类,我们可以
class C<T extends Number> { ... }
class C_Integer extends C<Integer>{ ... }
C类{…}
类C_Integer扩展了C{…}
调用者必须使用C_Integer
而不是C
来选择“专用”版本
关于duck类型:Java在静态类型方面更严格——除非它是duck,否则它不是duck 不,Java中的泛型不是这样工作的
有了泛型,你就不能做任何没有泛型就不可能做的事情——你只需要避免编写大量的强制转换,并且编译器确保一切都是类型安全的(只要你没有得到一些警告或抑制这些警告)
因此,对于每个类型变量,您只能调用在其边界中定义的方法(没有duck类型)
此外,没有代码生成(除了一些适配器方法,为了实现泛型类型,可以将它们委托给具有其他参数类型的方法)。假设你有这样的东西
/**
* interface for objects who allow adding some other objects
*/
interface Addable<T> {
/** returns the sum of this object and another object. */
T plus(T summand);
}
静态方法编译为相同的字节码,如下所示(注释中包含其他类型信息):
这称为类型擦除
现在可以为可添加类型的每对两个元素调用此方法,如下所示:
public class Integer implements Addable<Integer> {
public Integer plus(Integer that) {
return new Integer(this.value + that.value);
}
// private implementation details omitted
}
此方法将仅由具有正确类型的泛型代码调用,这保证了编译器,假设您没有在某处执行一些不安全的强制转换-那么这里的(Integer)
强制转换将捕获错误(并抛出ClassCastException)
sum
方法现在总是调用第一个对象的plus
方法,没有办法解决这个问题。没有可能为每种类型的参数生成代码(这个<强> < /强> java泛型与C++模板之间的关键区别),因此不能简单地用专门的方法替换生成的方法之一。
当然,您可以创建第二个sum
方法,如unreputable proposed(带重载),但只有在直接在源代码中使用MyX
类型时,才会选择此方法,而不是在从其他一些碰巧用MyX参数化的通用代码调用sum
方法时,例如:
public <T extends Number> T sum(T a, T b) {
T newValue = a.sum(b);
return newValue;
}
public Object plus(Object that) {
return this.plus((Integer)that);
}
public static <T extends Addable<T>> product (int times, T factor) {
T result = factor;
while(n > 1) {
result = sum(result, factor);
}
return result;
}
公共静态乘积(整数倍,T系数){
T结果=因子;
而(n>1){
结果=总和(结果、系数);
}
返回结果;
}
现在,product(5,新的MyX(…)
将调用我们的sum(T,T)
方法(它反过来调用plus
方法),而不是任何重载的sum(MyX,MyX)
方法
(JDK 7添加了一个新的动态方法分派模式,该模式允许在运行时通过每个参数进行专门化,但Java语言不使用这种模式,只打算由其他基于JVM的语言使用。)类型擦除的方法应为可加和(可加第一,可加第二)
非常好地解释了泛型如何用于sum
。现在我可以将其转化为我的旧Java知识。但这里删除的是什么?“类型擦除”是指什么?当然!通过重载进行专门化。我真是太蠢了:-)那太蠢了。Thx@towi:“类型擦除”是指将每个泛型类型(可能是参数化类型、泛型数组类型或类型变量)转换为非泛型类型的过程,因为VM只能直接处理这些类型。请参阅JLS中的部分。这只是重载,如果使用T
从某些通用方法调用plus
方法,并使用MyX
调用,则此方法无效。
public static <T extends Addable<T>> product (int times, T factor) {
T result = factor;
while(n > 1) {
result = sum(result, factor);
}
return result;
}