根据这一https://docs.oracle.com/javase/specs/jls/se18/html/jls-15.html#jls-15.12.2.5,Java编译器将尝试选择最具体的方法来调用时,有多个适用的和可访问的,直觉是更具体的方法可以取代较不具体的,但不是相反。
所以我有点惊讶,当我们在通用包装器中包装模糊调用时,这不会起作用,如下所示:
public class Test{
static <T> void direct(T t) { System.out.println("generic");}
static void direct(int t) { System.out.println("specific-int");}
static <T> void indirect(T t) { direct(t);}
public static void main ( String [] args ) {
direct(1); // print specific-int
indirect(1); // print generic
}
}
所以我们可以看到,只要调用direct
就可以让它按预期工作。但是当调用间接
时,会调用不太具体的方法。
如果我改变直接方法的类型,行为就会改变
static void direct(short t) { System.out.println("specific-short");}
在这种情况下,两行都打印generic
(两种情况下都不调用short
方法),这告诉我,literal1
在第一个实例中被隐式转换为int
。如果是这样,为什么不使用更具体的方法调用它,将int
作为参数?
为什么不使用更具体的方法调用它,将int作为参数?
Java编译器决定在编译时调用哪个方法。也就是说,对于indirect
方法,它选择一个重载direct
,该重载可以安全地用于indirect
的所有调用。
唯一的重载是Direct(T)
方法:它接受任何Object
参数,就像间接(T)
一样。它不能调用Direct(int)
,因为并非所有Object
都是intger
s。
间接
在使用int
参数调用时没有任何不同。
2个不相关的原因,这两个原因都导致了通用版本:
类型参数必须是对象的子类型(目前,Project Valhalla是一个正在进行的java更新,可能会有所改变)。
因此,您的间接方法中的直接(t)调用不可能将直接(int)作为最特定的版本,因为间接方法中的参数不可能是int。
具体来说,当您调用indirect(1)
时,1是一个int
,它不是indirect
的有效值(asindirect
的参数类型为t
;t是一个具有下限java.lang.Object
的类型参数,1
不是Object
的有效值)。
然而,java也有“装箱”的概念,即原语将自动转换为装箱类型,但前提是代码不会以其他方式编译。您可以在javap
中看到这一点——您会注意到编译器将1
替换为整数。valueOf(1)
使其工作。
选择的方法在编译时被锁定。请注意,重写(子类型实现完全相同的方法,即,如果该方法用@Override
注释,编译器将接受它)完全是运行时的事情,java总是从子类型中选择实现,但静态
不“执行”子类型,因此在这里不相关。
你拥有的两种direct
方法不一样;在JVM级别,它们有完全不同的名称,所以这只是关于javac
选择了2个direct
方法中的哪一个,因此编译时间是这里唯一重要的时间。
让我明确一点:2direct
方法没有相同的名称,因此在运行时,JVM没有根据类型选择其中一种方法的自由。出于同样的原因,它不能将对foo()
的调用替换为对bar()
的调用,而不是相同的名称。
间接法不知道T是什么。因此,它不可能调用direct(int)
,即使装箱的事情不是这样查找要选择的两个direct
方法中的哪一个不是在运行时完成的。
鉴于:
public class Parent {
void foo(int i) { System.out.println("Parent-int"); }
void foo(Integer i) { System.out.println("Parent-Integer"); }
}
class Child extends Parent {
void foo(int i) { System.out.println("Child-int"); }
}
...
Parent p = new Child();
p.foo(5); // prints Child-int
p.foo(Integer.valueOf(5)); // prints Parent-Integer
你在评论中写道:
“这告诉我,文本1在第一个实例中被隐式转换为int”
java中的整数字面值是int
-java lang规范这样定义它们。您可以编写短x=5;
,这仅仅是因为有一个特殊的豁免规则,声明您不需要强制转换,但是在语言方面,所有非十进制指向(和非0x0p
形式)的数字AST节点都被视为int
。如果需要long
,它们将被隐式强制转换。
你可以让javac在末尾加一个大写字母L,让它把事情处理得一样长。鉴于:
void foo(byte i) {System.out.println("byte");
void foo(short i) {System.out.println("short");
void foo(int i) {System.out.println("int");
void foo(long i) {System.out.println("long");
foo(5); // prints 'int'
foo(5L); // prints 'long'
尽管“5”适合“byte”,但它是一个int,因此选择了int
变量。
问题内容: 示例代码为: 输出为: 的第一个调用会调用带有String参数的方法,根据可以理解。 1)谁能解释我在先前的调用中是基于什么来调用的? 2)再说一次,说一个if条件: 它总是使用 调用方法。 编译器在编译时会计算表达式吗?我想知道表达式是在编译时还是在运行时计算的。谢谢。 问题答案: Java使用早期绑定。在编译时选择最具体的方法。根据参数数量和参数类型选择最具体的方法。在这种情况下,
我想在我的android项目中自动转换视图。所以,我想重写 方法 方法但是java编译不允许这样做,但是重写的方法不会与父方法冲突,并且总是返回视图对象或其子对象。我发现了一些信息,java不允许用泛型方法重写非泛型方法,但我找不到解释。 http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ8
我有一个有界泛型类,我们称之为泛型,它的参数T扩展了抽象类abstract: 泛型类: 抽象类 泛型类中T引用的类 当尝试引用方法 getMap() 时,该方法来自 T 边界内的类(并且根据抽象类定义,T 的所有可能实例都将具有该方法),我收到以下错误: 不能从静态上下文引用非静态方法getMap() 然而,任何地方都没有静态关键字。我错过了什么?? 谢谢!
我一直在尝试泛型,很快我就遇到了一些我无法解释的事情 例如: 我不明白
问题内容: 我想知道用这样的签名调用静态方法的正确方法是什么: 由于某种原因,我很想这样称呼它: 但是除非我将其更改为:否则它不会编译: 我只是想知道为什么它不需要右侧的提示。而是给了我编译错误。它说它期望在右侧的提示后加上分号。第二个方法是调用该方法的正确方法吗?有人可以给我一些启示吗? 问题答案: 如图所示这里,要调用的方法的方法是: 该方法所在的类的名称在哪里。
因此,我有一些带有这些签名的Java方法(为了简单起见,删除了注释和代码体): 我在Kotlin中有一些代码,它调用了'join'方法: 例如,如果我想用“分隔符”参数调用后一个方法签名,问题就来了: 这段代码无法编译。编译器无法决定调用哪个方法。错误: 错误:(5,13)Kotlin:在未完成类型推断的情况下,无法在以下候选项中进行选择:public open fun join(vararg A