我实际上来自python背景,我一直在研究Java中的“破解编码面试”。在第51页,我遇到了
void permutation(String str){
permutation(str,"");
}
void permutation(String str, String prefix){
if(str.length()==0){
System.out.println(prefix);
} else{
for(int i=0;i<str.length();i++){
String rem=str.substring(0,i)+str.substring(i+1);
permutation(rem,prefix+str.charAt(i));
}
}
}
当尝试以Python的方式思考时,我有点困惑。我的要点是,第一个排列函数接受一个字符串,然后调用第二个排列函数来完成所有工作。但是,第二个排列不是在重新定义第一个排列函数吗? Java将如何识别和使用第一个排列函数?而不是覆盖它?
java如何识别和使用第一个排列函数?
当您调用该方法时,Java将看到您尝试传递给它的内容。根据您传递的参数,它将决定您尝试使用的方法的“版本”。
[就像其他人说的一样-这是方法重载
[与Python不同,在Java中,这两个声明并存-第二个声明不能代替第一个。在Java中,规则大致是:当您调用具有多个定义的方法(又称“重载”方法)时,Java会查找与您调用的参数最匹配的方法并运行该方法。因此,permutation("hi")
调用第一个版本,permutation("hi", "")
调用第二个版本。
这里的根本区别在于,您可以想象在Python中解释器一次读取一个定义,并在每次获得新定义时替换其整体定义permutation
。在Java中,您必须将其视为一次读取all permutation
的定义,并为任何给定的调用调用最合适的定义。
((这样的结果是Java还在编译时检查方法的每个重载版本都是可调用的:例如,如果您编写了两个都仅以字符串作为参数的permutation
版本,则编译器会给您一个错误,并且根本不会编译您的程序。在python中,您将获得第二个定义。)
要解释语义是什么,我们需要看一下Java方法是如何区分的。
在Java中,方法由其签名标识。 JLS §8.4.2指定
如果两个方法具有相同的名称和参数类型,则它们具有相同的签名。
要注意的是,方法的返回类型是方法签名的not一部分。因此,如果有人会写:
public class Foo {
void bar(String baz) {
}
String bar(String baz) {
}
}
两个方法都具有相同的签名。在Java中,这将导致编译错误,因为不允许在同一类中使用两个具有相同签名的方法。
如果我们将继承权引入图片中,行为就会改变:
public class Foo {
void bar(String baz);
}
public class Zoo extends Foo {
@Override
void bar(String baz);
}
在这种情况下,类别Zoo
的类别overrides bar(...)
方法Foo
。请注意,注释不负责行为,仅负责编译时检查,以确保至少一个父类中存在方法void bar(String baz)
。
所提供的代码有两个名称相同但签名不同的方法。在Java中称为Overloading。因此,该方法被视为不相等。您可以重命名这些方法之一,它们不会或多或少地“相等”。
为了使事情变得更加奇怪,如果方法被重载,则在编译时为要调用的方法签名。这意味着只能考虑静态类型的参数。让我们看下面的代码,弄清楚结果是什么:
public class Test {
public static void main(final String... args) {
final String s = "foo";
final Object o = s;
print(s);
print(o);
}
private static void print(final String s) {
System.out.println("Called with String parameter");
}
private static void print(final Object o) {
System.out.println("Called with Object parameter");
}
}
现在s
的静态类型是什么?这是左侧的类型,其中声明了s
,因此调用了print(final String s)
,并打印了"Called with String parameter"
。 o
的静态类型是什么?同样,它是左侧的类型,其中声明了o
,因此调用了print(final Object o)
,并打印了"Called with Object parameter"
。有人可能会争辩说,在这个琐碎的示例中,编译器可能会发现o
的类型只能是String
,但这种行为基于编译器在编译时识别类型的能力,只会使其更加混乱。
在Java中,整个类在执行方法之前已加载。
这意味着在执行第一种方法之前已加载/准备好第二种方法,而在执行第二种方法之前已加载/准备好了第一种方法。>>
这允许递归调用方法,并调用稍后将声明的方法。
此外,方法是重载
。在Java中,如果参数不同,则可以在同一类中创建多个具有相同名称的方法。这些方法将被视为不同的方法,它们将传递给该方法的参数脱离顺序。
换句话说,名称本身并没有定义调用哪个方法,而是签名
,包括参数(不是返回值)