Java 在尝试使用两个泛型方法时,同一调用中的两个泛型方法是否会导致编译错误?
我读过Deital的书:“Java如何编程”,在泛型章节中,这句话是这样写的:“如果编译器没有找到与方法调用完全匹配的方法声明,但是 如果找到两个或多个可以满足方法调用的方法,则会发生编译错误”。 有人能给我举个例子吗,因为当我没有成功得到上面的编译错误时。 我的代码:Java 在尝试使用两个泛型方法时,同一调用中的两个泛型方法是否会导致编译错误?,java,generics,methods,Java,Generics,Methods,我读过Deital的书:“Java如何编程”,在泛型章节中,这句话是这样写的:“如果编译器没有找到与方法调用完全匹配的方法声明,但是 如果找到两个或多个可以满足方法调用的方法,则会发生编译错误”。 有人能给我举个例子吗,因为当我没有成功得到上面的编译错误时。 我的代码: 公共类动物 { 公共动物() { } 公共字符串() { 返回“动物”; } } 公家犬 { 公共字符串() { 返回“如何”; } } 公共类狗 { 公共字符串() { 返回“我是狗儿子”; } } 公开课考试 { 公共静态v
公共类动物
{
公共动物()
{
}
公共字符串()
{
返回“动物”;
}
}
公家犬
{
公共字符串()
{
返回“如何”;
}
}
公共类狗
{
公共字符串()
{
返回“我是狗儿子”;
}
}
公开课考试
{
公共静态void main(字符串[]args)
{
测试t=新测试();
道森d=新道森();
系统输出println(t.helpMethod(d));
}
公共字符串帮助方法(T狗)
{
系统输出打印项次(“aaa”);
返回狗吠声();
}
公共字符串帮助方法(T动物)
{
返回动物。树皮();
}
}
因为并没有一种方法可以精确地得到子对象,所以这里有两种通用的方法。这不是神所说的情况吗?不完全是;在您的示例中,
T狗
变体比T动物
变体更具体,因此,它是所选的变体
我不能保证我知道作者指的是什么。但我可以猜到:
public class Example<T> {
public void m(T arg) {
// At compile time, 'T', as it has a lower bound of Object,
// is treated as Object. Its signature therefore does not clash
// with the next m, and thus this can be compiled.
System.out.println("T-based");
}
public void m(Dog arg) {
System.out.println("Dog-based");
}
}
new Example<Dog>().m(new Dog()); // this line causes a compiler error.
公共类示例{
公共无效m(T参数){
//在编译时,“T”具有对象的下限,
//被视为对象。因此其签名不冲突
//使用下一个m,因此可以编译这个。
System.out.println(“基于T”);
}
公共空间m(狗arg){
System.out.println(“基于狗的”);
}
}
新示例().m(新狗());//此行导致编译器错误。
生成的错误是:
Animal.java:16: error: reference to m is ambiguous
new Example<Dog>().m(d);
^
both method m(T) in Example and method m(Dog) in Example match
where T is a type-variable:
T extends Object declared in class Example
1 error
Animal.java:16:错误:对m的引用不明确
新例子().m(d);
^
示例中的方法m(T)和示例中的方法m(Dog)都匹配
其中T是一个类型变量:
T扩展类示例中声明的对象
1错误
因此,这里发生了什么:在编译时(例如java本身),两个m
方法并不一定是模棱两可的;在大多数情况下,T变量被视为等于其下限(因此,对象),在java中,在同一类中可以有m(Object arg)
和m(Dog arg)
,没有问题
然而,在泛型之后,2
m
方法实际上发生了冲突:它们现在都将Dog
类型的任何对象作为参数。因此,在任何新示例
上都不再可能调用m方法。当涉及泛型且类型参数可能重叠时,正确的解决方案是不要重载(当您有两个具有相同名称的不同方法时,就会这样调用)。想必,您的书的这一部分的作者正试图告诉您,在这种情况下,为什么不应该过载。在您的情况下,没有出现编译错误的原因是因为这两种方法
公共字符串帮助方法(T){
返回树皮();
}
公共字符串帮助方法(T){
返回树皮();
}
告诉编译器分别将T
解析为Dog
和Animal
。这实际上和写作是一样的
公共字符串帮助方法(Dog t){
返回树皮();
}
公共字符串帮助方法(动物t){
返回树皮();
}
狗和动物是两种不同的类型,尽管它们是亲子关系。编译器不会抱怨的
但是,如果要查找编译错误,请尝试以下操作
公共字符串帮助方法(T){
返回树皮();
}
公共字符串帮助方法(T){
返回树皮();
}
你必须理解的东西叫做
这意味着,如果方法的类型参数未绑定或
当它被绑定时,它是第一个绑定类 Bound的意思是,-在您的示例中,-您已经声明了类型参数T与另一个类的关系,就像您所做的那样:
// 1. method
public <T extends Dog> String helpMethod(T dog)
// 2. method
public <T extends Animal> String helpMethod(T animal)
将出现编译错误,如3。类型擦除期间的方法将与您的4完全相同。方法。编译器无法决定要调用哪个,并抛出错误 考虑到上述情况,简短的回答是: 在您的代码中,您使用两种不同的方法,没有歧义,因此不会发生错误
如果您想看到编译错误,您应该声明另一个泛型方法,编译后的签名将与类中现有的泛型/非泛型方法相同。不,擦除是不同的,并且一个方法比另一个方法更具体。在这种情况下,将匹配一个具有更合适返回类型的方法。如果没有更合适(具体)的方法,则会抛出一个错误,为了清楚起见,请阅读。我理解您的解释,但在您的示例中,有一个方法(获取参数的方法)与方法调用完全匹配。在我从书中摘取的一句话中写道:“如果编译器没有找到与方法调用完全匹配的方法声明…”,但正如我所说,这里,方法调用和方法声明完全匹配是的,粘贴的代码编译并工作。你跑了吗?它打印“aaa”。它不会生成编译器错误。是的。但在我的评论中,我指的是你发布的代码。你的解释很清楚。但是作者正在谈论调用该方法。如果问题是李
// 1. method
public <T extends Dog> String helpMethod(T dog)
// 2. method
public <T extends Animal> String helpMethod(T animal)
// 3. method
public <T> String helpMethod(T dog)
// 4. method
public String helpMethod(Object dog)