我有一个接口,其声明如下:
/**
* @param T - the type of entity.
* @param C - the type of entity container will be returned.
*/
public interface FindByNamedQuery<T extends Serializable, C extends Collection<T>> extends Command {
C executeNamedQuery(String namedQuery);
}
我想知道我是否可以(应该)打破Java命名约定来执行此操作:
public interface FindByNamedQuery<ENTITY_TYPE extends Serializable, RETURNED_CONTAINER extends Collection<ENTITY_TYPE>> extends Command {
RETURNED_CONTAINER executeNamedQuery(String namedQuery);
}
答案 0 :(得分:23)
我想知道我是否可以(应该)打破java命名约定来执行此操作:
不,这应该避免,因为更容易将类型参数与常量和其他标识符混淆。
以下是the official trail on generics的引用:
类型参数命名约定
按照惯例,类型参数名称是单个大写字母。这与你已经知道的变量命名约定形成了鲜明的对比,并且有充分的理由:没有这个约定,就很难区分一个类型变量和一个普通的类或接口名称 的
最常用的类型参数名称是:
E
- 元素(Java集合框架广泛使用)K
- 密钥N
- 号码T
- 输入V
- 价值S
,U
,V
等 - 第2,第3,第4类型您将在整个Java SE API和本教程的其余部分中看到这些名称。
答案 1 :(得分:21)
自20世纪90年代中期以来,我开始不同意单字符约定。
我发现可读名称更具可读性。这有助于理解泛型类型的实现和接口。
模糊性问题似乎被夸大了。几个类名都是大写的。常量不在类名称的相同上下文中使用。
@param JavaDoc元素确实可以提供更长的描述。但是,JavaDocs也不一定是可见的。 (例如,Eclipse中有一个显示类型参数名称的内容辅助。)
例如,比较:
public final class EventProducer<L extends IEventListener<E>,E>
implements IEventProducer<L,E> {
为:
public final class EventProducer<LISTENER extends IEventListener<EVENT>,EVENT>
implements IEventProducer<LISTENER, EVENT> {
虽然Sun / Oracle建议将单字符名称作为约定,但可以更改约定。挑战这一公约的后果是微不足道的。如果您和您的团队更喜欢类型参数的有意义的名称,我个人会选择它。
Google style for Java允许单字母名称和以T结尾的多字符类名称。
每个类型变量都以两种样式之一命名:
单个大写字母,可选后跟一个数字(如E,T,X,T2)
用于类的表单中的名称(参见第5.2.2节,类名),后跟大写字母T(示例:RequestT, FooBarT)。
答案 2 :(得分:10)
在C#中使用TDescription很常见。它维护T名称,但同时也是描述性的,如下所示:
public interface FindByNamedQuery<
TEntityType extends Serialiazble,
TReturnedContainer extends Collections<TEntityType>> extends Command
{
TReturnedContainer executeNamedQuery(String namedQuery);
}
正如其他人所说ALL_CAPS
几乎总是表示一个常数。
IMO,“很难区分类型变量和普通类或接口名称。”不适用于此,因为T前缀很容易将其识别为类型变量
同样,这是C#,但请参阅MSDN: Naming Conventions For Generics
在所有其他情况下,官方 微软通用指南 命名约定是:
使用描述性名称命名泛型类型参数,除非单个参数 字母名称完全是自我 解释性和描述性名称 不会增加价值。
public interface ISessionChannel<TSession> {...} public delegate TOutput Converter<TInput,TOutput>(TInput from);
- 考虑在参数名称中指明对类型参数的约束。例如,约束到ISession的参数可以称为TSession。
答案 3 :(得分:4)
编译器可能不会抱怨,但是你的队友可能不会喜欢你在他们期望类型参数的地方使用看似常量的东西。
答案 4 :(得分:3)
我认为这是很多人使用仿制药的抱怨。我不太同意Sun的声明,如果你使用一个完整的名称,那么它将与现有的类名或其他东西混淆。在这种情况下,我们可以用这样的美元开始占位符名称:
public class HashMap<$Key,$Value> implements Map<$Key,$Value>{}
没有人在他们理智的头脑中命名一个以美元符号开头的班级。并且一个美元符号也用于表示占位符许多模板语言的速度,支柱,弹簧等。我认为这是要走的路。
如果有人有兴趣的话,我有更多关于此的详细信息以及在我的博客文章中不必使用单字母符号的原因。
http://readsethu.wordpress.com/2012/05/23/a-generic-class-and-why-is-it-confusing/
答案 5 :(得分:1)
与Allen before一样,我的建议来自C#(我在5个月后广泛使用)而不是Java(我玩过它,但它从未走得太远......),但我发现Java和C#代码在精神上非常相似(也就是说,比较C ++时)
无论如何,当在简单类型上使用C#/ Java泛型(或C ++模板)时,我通常使用T:
// C++
template<typename T>
class MyClass { /* ... */ } ;
// C#
public MyClass<T> { /* etc. */ }
// Java
public MyClass<T> { /* etc. */ }
通常,类型T与类一起使用,因此无需再对其进行描述。
但是当真正描述类型增加代码清晰度时,我会这样做。
或者当我在同一个通用/模板声明中有两个或更多类型时,它有助于区分两种类型。例如(C#中的现实例子):
// C++
template<typename T_Data, typename T_Underlying>
class MyClass { /* ... */ } ;
// C#
public MyClass<T_Data, T_Underlying> { /* etc. */ }
// Java
public MyClass<T_Data, T_Underlying> { /* etc. */ }
通过这种方式,很容易区分代码中的两个类型名称,其中T
和U
是,有点......有点匿名:对于那些使用Visual C ++的人来说,进入在Dinkumware的STL代码中调试,充满T
,_U
和其他单字母类型名称可能非常令人沮丧...我猜C#或Java代码也是如此。
你会注意到在每种情况下(C ++,Java或C#),我都不遵循我的类型命名中的约定:原因是有时候,你只需要尝试别的东西而不是跟随牛群,即使最后,你也会发现自己错了。
在目前的情况下,违反命名惯例并不重要(Java中存在最严重的问题而不是这种轻微的犯罪),最后,您将亲自了解并确切地说为什么是错误的,而不是引用旧文件。
如果你最终发现你是对的,那么......
答案 6 :(得分:0)
我会将类型变量命名为类似于camel大小写的类型变量,但前缀为“_”。
public interface FindByNamedQuery
<_EntityType extends Serialiazble,
_ReturnedContainer extends Collections<_EntityType>>
extends Command
{
_ReturnedContainer executeNamedQuery(String namedQuery);
}