标签:构造器 container 结束 返回 部分 描述 方法递归 逻辑 java语言
@
不论是从定义方法的语法来看,还是从方法的功能来看都不难发现方法和函数之间的相似性,实际上,方法确实是由传统的函数发展而来的,方法与传统的函数有着显著不同:
在 Java 方法不能独立存在,方法必须属于类或对象,如果需要定义方法,则只能在类体内定义,不能独立定义个方法。
一旦将一个方法定义在某个类的类体内:
Java语言是静态的。一个类定义完成后,只要不再重新编译这个类文件,该类和该类的对象所拥有的方法是固定的,永远都不会改变。
方法不能独立存在,所以方法也不能像函数那样被独立执行,执行方法时必须使用类或对象来作为调用者 ,即所有方法都必须使用 类.方法 或 对象.方法 的形式来调用 。
这里可能产生 个问题: 同一个类里不同方法之间相互调用时,不就可以直接调用吗?这里需要指出:同 一个类的一个方法调用另外 个方时,如果被调方法是普通方法, 默认使用this 作为调用者;如果被调方法是静态方法,则默认使用类作为调用者。也就是说,表面上看起来某些方法可以被独立执行,但实际上还是使用 this 或者类来作为调用者。
方法属性总结:
使用 static 修饰的方法属于这个类本身,使用 static 修饰的方法既可以使用类作为调用者来调用,可以使用对象作为调用者来调用。但是因为使用 static 修饰方法还是属于这个类的,因此使用该类的任何对象来调用这个方法时将会得到相同的执行结果,这是由底层依然是使用这些实例所属的类作为调用者。没有 static 修饰的方法属于该类的对象,不属于这个类本身。因此没有 static 饰的方法只能使用对象作为调用者来调用,不能使用类作为调用者来调用 。使用不同对象作为调用者来调用同 一个普通方法,可能得到不同的结果。
前面己经介绍了 Java 里的方法是不能独立存在的,调用方法也必须使用类或对象作为主调者果声明方法时包含了形参声明,则调用方法时必须给这些形参指定参数值,调用方法时实际传给形参的参数值也被称为实参。
那么, Java 的实参值是如何传入方法的呢?这是由 Java 方法的参数传递机制来控制的, Java 里方法参数传递方式只有一种值传递。所谓值传递,就是将实际参数值的副本(复制品)传入方法内,而参数本身不会受到任何影响。
Java 里的参数传递类似于《西游记》里的孙悟空,孙悟空复制个假孙悟空,这个假孙悟空具有和孙悟空相同的能力,可除以被砍头 但不管这个假孙悟空遇到什么事,孙悟空不会受到任何 与此类似,传入方法的是实际参数值的复制品,不管方法中对这个复制品如何操作,实际参数值本身不会受到任何影响。
public class PrimitiveTransferTest {
public static void swap(int a, int b) {
// 下面三行代码实现 的值交换
// 定义一个临时变量来保存a的值
int tmp = a;
// a的值赋给b
a = b;
// 把临时变量 tmp的值赋给b
b = tmp;
System.out.println("swap方法里,a的值是" + a + "; b的值是" + b);
}
public static void main(String[] args) {
int a = 6;
int b = 9;
swap(a, b);
System.out.println("交换结束后,a变量 的值是" + a + "; b变量 的值是 " + b);
}
}
结果:
swap方法里,a的值是9; b的值是6
交换结束后,a变量 的值是6; b变量 的值是 9
从上面运行结果来看, swap()方法里 a和b的值是9、6 ,交换结束后,变量a、b的值依然是6、9 。
从这个运行结果可以看出 main()方法里的变量a和b并不是 wap()方法里的变量a和b。 swap()方法里的a和b只是main()方法里变量a和b的复制品。
实例程序的执行过程:
在内存中的存储示意图如图一所示
在内存中的存储示意图如图二所示。
对比图三与图一两个示意图中main()方法栈区中a、b的值并未有任何改变,程序改变的只是 swap()方法栈区中的a、b。
这就是值传递的实质: 当系统开始执行方法时,系统为形参执行初始化, 就是把实参变量的值赋给方法的形参变量,方法里操作的并不是实际的实参变量。
前面看到的是基本类型的参数传递,Java对于引用类型的参数传递,一样釆用的是值传递方式。下面程序示范了引用类型的参数传递的效果。
class DataWrap {
int a;
int b;
}
public class ReferenceTransferTest {
public static void swap(DataWrap dw) {
// 下面三行代码实现dw的a、b两个成员变量的值交换
//定义一个临时变量来保存dw对象的a成员变量的值
int tmp = dw.a;
// 把dw对象的b成员变量的值赋给a成员变量
dw.a = dw.b;
// 把临时变量tmp的值赋给dw对象的b成员变量
dw.b = tmp;
System.out.println("swap方法里,a成员变量的值是" + dw.a + "; b成员变量的值是" + dw.b);
}
public static void main(String[] args) {
DataWrap dw = new DataWrap();
dw.a = 6;
dw.b = 9;
swap(dw);
System.out.println("交换结束后,a成员变量的值是" + dw.a + "; b成员变量的值是" + dw.b);
}
}
结果:
swap方法里,a成员变量的值是9; b成员变量的值是6
交换结束后,a成员变量的值是9; b成员变量的值是6
从上面运行结果来看,在swap()方法里,a、b两个成员变量的值被交换成功。不仅如此,当swap() 方法执行结束后,main()方法里a、b两个成员变量的值也被交换了。这很容易造成一种错觉:调用swap() 方法时,传入swap()方法的就是dw对象本身,而不是它的复制品。
程序的执行过程:
此时系统内存中的存储示意图如图四所示。
图五显示了 dw传入swap()后的存储示意图。
为了更好地证明main()方法中的dw()和swap()方法中的dw是两个变量,在swap()方法的最后一行增加如下代码:
//把dw直接赋值为null,让它不再指向任何有效地址
dw = null;
执行上面代码的结果是swap()方法中的dw变量不再指向任何有效内存,程序其他地方不做任何修改。main()方法调用了 swap()方法后,再次访问dw()变量的a、b两个成员变量,依然可以输出9、6。 可见main()方法中的dw变量没有受到任何影响。实际上,当swap()方法中增加dw = null代码后,内存中的存储示意图如图五所不。
从图五来看,把swap()方法中的dw赋值为null后,swap()方法中失去了DataWrap的引用,不可再访问堆内存中的DataWraper对象。但main()方法中的dw变量不受任何影响,依然引用DataWrap对象,所以依然可以输岀DataWrap对象的a、b成员变量的值。
JDK 1.5 开始,Java支持传递同类型的可变参数给一个方法。
方法的可变参数的声明如下所示:
typeName... parameterName
在方法声明中,在指定参数类型后加一个省略号(...) 。
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
public class VarargsDemo {
public static void main(String args[]) {
// 调用可变参数的方法
printMax(34, 3, 3, 2, 56.5);
printMax(new double[]{1, 2, 3});
}
//定义了形参可变的方法
public static void printMax( double... numbers) {
if (numbers.length == 0) {
System.out.println("No argument passed");
return;
}
//numbers被当成数组处理
double result = numbers[0];
for (int i = 1; i < numbers.length; i++){
if (numbers[i] > result) {
result = numbers[i];
}
}
System.out.println("The max value is " + result);
}
}
结果:
The max value is 56.5
The max value is 3.0
一个方法体内调用它自身 被称为方法递归 方法递归包含了某种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
例如有如下数学题 己知有 个数列:
其中n是大于大于0的整数,求f(10)的值。这个题可以使用递归来求得。下面程序将定义一个fn方法,用于计算f(10) 的值。
public class Recursive {
public static int fn(int n) {
if (n == 0) {
return 1;
} else if (n == 1) {
return 4;
} else {
// 方法中调用它自身 就是方法递归
return 2 * fn(n - 1) + fn(n - 2);
}
}
public static void main(String[] args) {
// 输出 fn (10) 的结果
System.out.println(fn(10));
}
}
Java允许同一个类里定义多个同名方法,只要形参列表不同就行。如果同一个类中包含了两个或两 个以上方法的方法名相同,但形参列表不同,则被称为方法重载。
从上面介绍可以看岀,在Java程序中确定一个方法需要三个要素。
方法重载的要求就是两同一不同:同一个类中、方法名相同,参数列表不同。至于方法的其他部分, 如方法返回值类型、修饰符等,与方法重载没有任何关系。
public class OverLoad {
//下面定义了两个test()方法,但方法的形参列表不同
//系统可以区分这两个方法,这被称为方法重载
public void test() {
System.out.println("无参数");
}
public void test(String msg) {
System.out.println("重载的 test 方法 " + msg);
}
public static void main(String[] args) {
OverLoad ol = new OverLoad();
//调用testO时没有传入参数,因此系统调用上面没有参数的testO方法
ol.test();
//调用testO时传入了一个字符串参数
//因此系统调用上面带一个字符串参数的testO方法
ol.test("hello");
}
}
Java 允许重载任何方法, 而不只是构造器方法。因此,要完整地描述一个方法,需要指出方法名以及参数类型。这叫做方法的签名(signature)。
参考:
【1】:《疯狂Java讲义》
【2】:《Java核心技术 卷一》
【3】:https://www.runoob.com/java/java-methods.html
标签:构造器 container 结束 返回 部分 描述 方法递归 逻辑 java语言
原文地址:https://www.cnblogs.com/three-fighter/p/13052532.html