java入门(3)

Wesley13
• 阅读 743

函数和方法

如果我们经常要进行一些相似的处理过程,就可以把这个处理过程封装为函数

函数可以被多次重复调用,从而实现代码重用和隔离的目的。

在面向对象的语言中,函数经常和对象绑定在一起,为区分起见,这时它被称为方法

因为java是完全面向对象的,函数必须从属于某个类。所以java中的函数都被称为方法。

如果方法前以 static 修饰,则称为静态方法,可以粗略地认为,它与 c 语言的函数的概念大致相等了。

方法可以在其括号中列出调用它时需要准备的参数,叫形式参数

方法也可以有一个返回值(或没有,此时写void)。

下面,我们调用方法 f,求两个整数的末位是否相同。

 1 public class A0403
 2 {
 3     static boolean f(int a, int b){
 4         int a1 = a % 10;
 5         int b1 = b % 10;
 6         return a1==b1;
 7     }
 8     
 9     public static void main(String[] args){
10         System.out.println(f(101,12));
11         System.out.println(f(65432,12));        
12     }
13 }

这个方法接受两个参数,都是整数,它进行一系列的处理后,返回一个布尔值。

return 语句结束 f 方法的执行,并返回一个指定的值。

在遇到 return 语句后,f 方法的其它代码就不再执行,而是要返回调用它的那个方法中。当然,在此方法中,return 语句后恰好没有更多的语句了。

如果一个方法定义了返回值,它在结束执行之前就一定会遇到 return 语句,否则会引发编译错误。

形参独立原理

如果在被调函数中改变了形参的值,会不会影响调用的一方呢? 不会!

我们看这个例子:

 1 public class A0404
 2 {
 3     static void f(int x){
 4         int sum = x % 10;
 5         x /= 10;
 6         sum = sum * 10 + x % 10;
 7         x /= 10;
 8         sum = sum * 10 + x % 10;
 9         System.out.println(sum);
10         System.out.println("x=" + x);
11     }
12     
13     public static void main(String[] args){
14         int a = 368;
15         f(a);
16         System.out.println("a=" + a);    
17     }
18 }

这里的函数f的功能是:把传给它的3位数 x 的数位反转并输出。

为了观察,我们额外输出了 a 的值,以及 x 的值。

通过结果可以看到,虽然 x 的值在计算过程中发生了变化,但这并不会影响 a 的值。

实际上,在调用 f 之前,要为它准备需要的参数,这些参数必须新创建,所以才称为形式参数。

也就是说,在没有调用 f 函数的时候,这些形参变量是不存在的,在多次调用 f 的时候,这些形参就会被创建多次。

创建形参后,把实参的值(这里就是 a 的值)拷贝给它,然后才开始 f 的执行。

当 f  执行结束后,形参变量会被自动释放掉。

从更底层的机制看,这个形参的分配与释放的过程是通过栈来完成的。

函数调用前,要把返回的位置,需要的参数等信息压栈,在函数执行完毕后,自动弹栈,恢复执行前的样子。

如果被调用的函数还会去调用其它函数,这个过程还会继续上演。

这样,栈可能就会越涨越高,但函数的执行总有结束的时候,那时栈就会落回来。

如果由于某种设计失误,导致函数调用一直没能正确返回,而是不断地调用其它的函数,就会导致栈的溢出,这是很常见的程序错误。

从参数传递的原理上我们看到,实参与形参是各自独立的变量,除了开始的时候,实参拷贝给形参外,它们再不会有任何联系。这叫做

"形参独立原理"。

这种设计为我们省去了许多麻烦,但有时我们可能会想让被调方与主调方共享一个变量,而不是各自独立,这怎么办呢?

答案是传指针,在java中叫做:引用。

引用作为参数

引用的本质是持有另一个对象的地址。

如果对一个引用进行复制,只不过是两个引用指向了同一个对象,并没复制对象本身。

引用与面向对象的体系紧密联系在一起,所以要等到学了初步的面向对象的知识后我们才能更好地理解它。

但这里,我们可以先看看数组的行为,来窥其端倪。

数组就是一种对象类型,我们定义的数组变量,实际上是指向实际数组对象的指针,或说:引用。

 1 public class A0404
 2 {
 3     static void f(int[] x){
 4         for(int i=0; i<x.length; i++){
 5             if(x[i] < 0) x[i] = -x[i];
 6         }
 7     }
 8     
 9     public static void main(String[] args){
10         int[] a = {5, -3, 6, 10, 0, -15};
11         f(a);
12         System.out.println(java.util.Arrays.toString(a));
13     }
14 }

这里的形参 x,实参 a 都不是数组本身,它们是指向数组的引用。

虽然  x 和 a 也是按照同样的规则,不会相互影响,但由于它们指向了同一个对象,这就引起了复杂的现象。

从结果上,我们可以观察到,在 f 方法中修改了数组对象的值,在主调方打印数组时也看到了这些变化。

其原理图:

java入门(3)

引用是一种在主调函数和被调函数间共享数据的常用手段。

在上面的这个例子中,引用变量本身并没有发生变化。发生变化的是引用所指向的对象,所以“形参独立性原理”并没有因此而破坏。

我们可能会看到某些材料上写着: java 有两种传递参数的方式,一种是传值(传拷贝),另一种是传引用。

这可能会产生一些误导。实际上Java只有一种传递参数的方式,就是传值。

而这个被传递的值有可能会恰好是一个引用类型,就会引起一些类似共享变量的效果,其实并没有什么特殊的秘密,也不应该算是“另一种”传递方式。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Stella981 Stella981
3年前
JS 对象数组Array 根据对象object key的值排序sort,很风骚哦
有个js对象数组varary\{id:1,name:"b"},{id:2,name:"b"}\需求是根据name或者id的值来排序,这里有个风骚的函数函数定义:function keysrt(key,desc) {  return function(a,b){    return desc ? ~~(ak
Stella981 Stella981
3年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Wesley13 Wesley13
3年前
Java日期时间API系列30
  实际使用中,经常需要使用不同精确度的Date,比如保留到天2020042300:00:00,保留到小时,保留到分钟,保留到秒等,常见的方法是通过格式化到指定精确度(比如:yyyyMMdd),然后再解析为Date。Java8中可以用更多的方法来实现这个需求,下面使用三种方法:使用Format方法、 使用Of方法和使用With方法,性能对比,使用
Stella981 Stella981
3年前
PythonStudy——魔法函数 Magic Methods
魔法函数python中以双下划线开始和结束的函数(不可自己定义)为魔法函数调用类实例化的对象的方法时自动调用魔法函数(感觉不需要显示调用的函数都叫)在自己定义的类中,可以实现之前的内置函数,比如下面比较元素sorted时用It函数(lt(self,other):判断self对象是否小于other对象;)
Stella981 Stella981
3年前
Python中函数和方法的区别
1、函数要手动传self,方法不用传self2、如果是一个函数,用类名去调用,如果是一个方法,用对象去调用 举例说明:classFoo(object):def__init__(self):self.name"haiyan"deffunc(self):
Stella981 Stella981
3年前
Python基础知识:类
初级篇面向过程:根据业务逻辑从上到下写垒代码函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可面向对象:对函数进行分类和封装,让开发“更快更好更强...”1、面向对象三大特性:封装、继承、多态。封装:将内容封装到某处,从某处调用被封装的内容;