Java 在尝试使用两个泛型方法时,同一调用中的两个泛型方法是否会导致编译错误?

Java 在尝试使用两个泛型方法时,同一调用中的两个泛型方法是否会导致编译错误?,java,generics,methods,Java,Generics,Methods,我读过Deital的书:“Java如何编程”,在泛型章节中,这句话是这样写的:“如果编译器没有找到与方法调用完全匹配的方法声明,但是 如果找到两个或多个可以满足方法调用的方法,则会发生编译错误”。 有人能给我举个例子吗,因为当我没有成功得到上面的编译错误时。 我的代码: 公共类动物 { 公共动物() { } 公共字符串() { 返回“动物”; } } 公家犬 { 公共字符串() { 返回“如何”; } } 公共类狗 { 公共字符串() { 返回“我是狗儿子”; } } 公开课考试 { 公共静态v

我读过Deital的书:“Java如何编程”,在泛型章节中,这句话是这样写的:“如果编译器没有找到与方法调用完全匹配的方法声明,但是 如果找到两个或多个可以满足方法调用的方法,则会发生编译错误”。 有人能给我举个例子吗,因为当我没有成功得到上面的编译错误时。 我的代码:

公共类动物
{
公共动物()
{
}
公共字符串()
{
返回“动物”;
}
}
公家犬
{
公共字符串()
{
返回“如何”;
}
}
公共类狗
{
公共字符串()
{
返回“我是狗儿子”;
}
}
公开课考试
{
公共静态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)