括号内的Javagenerics方法参数类型与外部括号
之间有什么区别:
static void findMax(LinkedList list){...}
和:
static void findMax(LinkedList list){...}
既然两者都有效,我想知道两者之间是否有任何重大差异,建议采用哪种方法。
主要区别在于,在第二个版本中,您可以访问类型T
而在第一个版本中,您不能访问。
例如,您可能希望返回链接到T的内容(例如,返回T而不是void):
static T findMax(LinkedList list){...}
或者您可能需要创建一个新的Ts列表:
static void findMax(LinkedList list){ List copyAsArrayList = new ArrayList<> (list); //do something with the copy }
如果您不需要访问T
,则两个版本在function上都是等效的。
如果您只关心findMax
接受符合特定条件的列表(在您的情况下是扩展Number
的类型的List),则应使用第一个 。
static Number findMax(LinkedList extends Number> list) { Number max = list.get(0); for (Number number : list) { if (number > max) { max = number; } } return max; }
此方法返回Number
。 例如,如果您拥有一个扩展Number
的类,并且您希望稍后在此方法的结果上使用某些特殊方法,则可能会出现问题。
当您计划在方法体中使用精确类型T
,方法参数或方法的返回类型时,应使用第二个 。
static T findMax(LinkedList list, T currentMax) { T max = currentMax; for (T number : list) { if (number > max) { max = number; } } return max; }
结论:
在function上,它们几乎相同, 只是具有未知类型( ?
)的列表无法修改。
这是区别
static void findMax(LinkedList extends Number> list){ list.add(list.get(0)); <-- compile error }
你不能在列表中添加任何空格。
同时编译时没有错误或警告
static void findMax2(LinkedList list){ list.add(list.get(0)); <-- no error }
就签名的权力而言,两者完全相同。 我的意思是,如果您有任何使用第二个签名的API,您可以将其替换为使用第一个签名的API,并且使用该API的任何代码将完全像以前一样工作,并且任何以前无效的代码也行不通。 所以对于外部代码,两者之间没有区别。
你如何将第二个的实现改为第一个? 其他人用list.add(list.get(0));
指出了例子list.add(list.get(0));
。 具有第一个签名的API是否可以执行该操作? 是。 这很简单。 只需让第一个调用第二个(将第二个调用为内部私有方法)。 这称为捕获助手 。 你可以这样做的事实certificate,两者都可以从外部代码的角度“做”相同的事情(通过任何内部手段“做”,包括调用其他方法)。
static void findMax(LinkedList extends Number> list){ findMaxPrivate(list); } static static void findMaxPrivate(LinkedList list){ list.add(list.get(0)); }
我认为关于参数T在第二种方法体中的访问已经有了很好的答案。
我想补充一点,如果您有许多需要按类型链接的参数,则需要第二种表示法。 例:
static int getPosition(LinkedList list, T element){...}
如果不使用generics类型参数
无法强制执行上述约束。