Java--方法

来源:互联网 发布:ubuntu访问windows盘 编辑:程序博客网 时间:2024/06/06 04:04
方法(method),在面向过程的语言中称作函数(function),在汇编语言中称作子程序,是一个代码功能块,实现某个特定的功能。在实际的程序开发中,方法是一种基础的组织代码的方式。本部分就介绍方法相关的概念、相关语法以及实际使用时需要注意的问题。
方法概述
方法的概念来源于数学上的函数,在数学中,当数据具有一定的规律时,就是用一个函数来代码该数字的规律,例如f(n)=n 则代表1、2、3、……这样的一个数列。在数学上n 是参数,对于确定的n 值只有一个f(n)的值和它对应。方法是一组为了实现特定功能的代码块的集合。方法在语法上的功能主要有以下两个:
①:结构化代码
将代码按照功能进行组织,使代码的结构比较清晰,容易阅读和修改,也就是程序的可维护性强。
②:减少代码重复
一个固定的功能,可能会在程序中多次使用,在使用时只需要调用写好的方法,而不用重复书写对应的功能代码。
方法在书写时需要注意以下两点:
①:逻辑严谨
方法实现的一个完整的功能,所以在书写时要考虑到各种可能的情况,并对每种情况做出恰当的处理。
②:通用性强
方法实现的是一种功能,在实际实现时,可以根据需要,使方法具备一定的通用性,除非必要,否则不要写专用的方法。在Java 语言中,恰当的使用方法,将使程序更加优雅,便于阅读和使用。
下面就来介绍方法声明的语法格式。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
方法声明
方法声明写在代码中类声明的内部,方法声明的外部,伪代码如下:
public class Hello{
方法声明1
方法声明2
……
}
在Java 语言中,方法声明之间没有顺序。方法声明,就是声明一种新的功能,或者说创造一种新的功能。
例如以下是一个求int 数据绝对值的方法声明代码:
public int abs(int n){
        if(n > 0){
            return n;
        }else{
            return -n;
        }
}
这里就实现了求int 值绝对值的功能,为了使该功能通用,使用一个参数n 代表需要求绝对值的数值,在方法内部使用求绝对值的逻辑:正数的绝对值是自身,负数的绝对值是相反数,使用return 语句将方法运算的结果返回。
具体方法声明的语法格式如下:
访问控制符[修饰符] 返回值类型方法名称(参数列表){
            方法体
}
在实际声明一个方法时,需要依次确定以上内容。下面是具体的说明:
一、访问控制符
访问控制符限定方法的可见范围,或者说是方法被调用的范围。方法的访问控制符有四种,按可见范围从大到小依次是:public、protected,无访问控制符,private。其中无访问控制符不书写关键字即可。具体的范围在后续有详细介绍。
二、修饰符
修饰符是可选的,也就是在方法声明时可以不书写。
修饰符是为方法增加特定的语法功能,对于方法实现的逻辑功能无影响。方法的访问控制符有五个,依次是:
static——静态的
final——最终的
abstract——抽象的
synchronized——同步的
native——本地的
具体修饰符的作用在后续内容中将详细介绍。
三、返回值类型
返回值类型是指方法功能实现以后需要得到的结果类型,该类型可以是Java 语言中的任意数据类型,包括基本数据类型和复合数据类型。如果方法功能实现以后不需要反馈结果,则返回值类型书写为void。在实际书写方法时,需要首先考虑一下方法是否需要反馈结果,如果反馈结果,则结果的类型是什么?这个根据方法的需要进行确定,例如上面求绝对值的方法,int 类型的绝对值还是int 类型,所以把返回值类型做成int 型。在方法声明里声明返回值类型,便于方法调用时获得返回值,并对返回值进行赋值以及运算等操作。
四、方法名称
方法名称是一个标识符,用来代表该功能块,在方法调用时,需要方法名称来确定调用的内容。为了增强代码的可读性,一般方法名称标识符和该方法的功能一直,例如实现数组排序的方法,可以将方法名称设定为sort。在Java 编码规范中,要求方法的首字母小写,而方法名称中单词和单词间隔的第一个字母大写,例如bubbleSort。
五、参数列表
参数列表是声明方法需要从外部传入的数据类型以及个数,例如上面求int 类型绝对值的方法,每次需要从外部传入一个int 类型的值,这就需要在参数列表部分进行声明,语法格式为:
数据类型    参数名称
多个参数时的格式为:
数据类型    参数名称1,数据类型    参数名称2,……
声明参数时,类型在前,名称在后,如果有多个参数时,参数和参数之间使用逗号进行分割。参数的值在方法调用时进行指定,而在方法内部,可以把参数看作是已经初始化完成的变量,直接进行使用。参数列表部分是方法通用性的最主要实现部分,理论上来说,参数越多,方法的通用性越强,在声明方法时,可以根据需要确定参数的个数,以及参数的类型。参数在参数列表中的排列顺序只和方法调用时有关。
六、方法体
方法体是方法的功能实现代码。方法体部分在逻辑上实现了方法的功能,该部分都是具体的实现代码,不同的逻辑实现代码区别会比较大。在方法体部分,如果需要返回结果的值,则可以使用return 语句,其语法格式为:
return 结果的值;
或无结果返回时:
return;
如果方法的返回值类型不是void,则可以使用return 返回结果的值,要求结果值的类型和方法声明时返回值类型必须一致。如果返回值类型是void 时,可以使用return 语句实现方法返回,而不需要返回值。当代码执行到return 语句时,方法结束,所以return 语句的后续书写顺序的代码,例如:
return 0;
int n = 0; //语法错误,永远无法执行到该语句
另外,如果返回值类型不是void 时,需要保证有值返回,例如下面的方法就有语法错误:
public int test(int a){
        if(a < 0){
                return 0;
        }
}

则该方法的声明代码中,当a 的值大于等于零时,则没有返回值,这语法上称作返回值丢失,这个也是在书写return 语句时需要特别注意的问题。
------------------------------------------------------------------------------------------------------------------------------------------------------------------
方法声明示例
方法实现的是功能,在实际声明方法时,不仅要根据需要确定访问控制符、修饰符、返回值类型、方法和参数列表这些信息,还要按照功能要求的逻辑实现方法体的代码。在实际设定时每个内容都需要根据功能的结构选择最恰当的内容。
下面通过一系列的示例来演示如何进行选择和设定。
判断某个整数是否是偶数
功能要求:判断一个整数是否是偶数
简单分析:为了实现判断任意的整数,需要在判断时从外部传入一个整数,在方法声明时,需要将该整数声明为参数。判断的结果是偶数或不是偶数,只有2 个状态,可以使用能够代表2 个状态的数据类型进行代表,最直观的就是boolean 类型了。
该方法实现的代码如下:
public boolean isEven(int n){
        return n % 2 == 0;
}
根据逻辑的需要,访问控制符选择public,修饰符为空,返回值类型做成boolean,参数列表部分传入一个整型的参数, 这样方法声明的结构就做好了。偶数的判断,只需要判断一下余数是否为零即可,如果余数为零则成立,否则不成立,直接把比较表达式的值作为方法的返回值返回。
数组排序
功能要求:实现整数数组数据从小到大(升序)的排序
简单分析:为了实现通用性,需要每次传递需要排序的数组进入方法内部,所以方法声明中需要有一个整型数组参数。为了直观,可以把排序以后的数组返回。说明:随着后续的学习,这个返回值不是必须的。
该方法实现的代码如下:
public int[] bubbleSort(int[] m){
        for(int i = 0;i < m.length - 1;i++){
                for(int j = 0;j < m.length - 1 - i;j++){
                        if(m[j] > m[j + 1]){
                                int temp = m[j];
                                m[j] = m[j + 1];
                                m[j + 1] = temp;
                        }
                }
        }
        return m;
}

在该方法内部,使用冒泡法实现数组的排序,最后将排序完成的数组作为返回值反馈回来。在实际使用时,可以将数组看成是一种普通的数据类型,也可以作为方法的返回值以及参数列表中的类型进行使用。
------------------------------------------------------------------------------------------------------------------------------------------------------------------
方法调用
方法声明是创建一个新的功能,声明出来的方法在需要的时候可以通过调用执行该方法的功能,方法只有被调用才能被执行。
在Java 程序中有一个基本的main 方法,其方法声明如下:
public static void main(String[] args)
该方法包含在开始的代码框架中,这是一个特殊的方法。Java 语法规定,J2SE 的代码都从该方法开始执行,如果一个代码中没有main 方法,则该代码不能被直接运行。所以main 方法也称作J2SE 程序的入口方法,在运行程序时,虚拟机调用对应代码中的main 方法开始程序的执行。由于上面讲述的原因,所以一个方法如果需要得到执行,则需要直接或间接在main 方法中进行调用。在调用方法时,程序的执行流程会进入方法的内部,当执行到方法内部的return 语句或执行完方法内部的代码以后,则返回到调用该方法的位置继
续向下执行。
方法调用的语法分为以下两种:
①:一个类内部的方法调用:指调用以及被调用的方法都在一个类的内部。
②:不同类之间的方法调用:指调用以及被调用的方法位于不同的类内部。
由于类的概念现在还没有涉及到,所以这里指讲一个类内部的方法调用语法,关于不同类之间的方法调用则在后续的章节中进行介绍。
一个类内部方法调用语法在前面的代码框架中,以下代码就是声明类的结构:
public class 文件名{ 
在该声明后续大括号内部的代码,称作一个类的内部。在进行方法调用时,调用的语法格式和static 修饰符有关,所以按照一个方法在声明时是否有static 修饰分为两类:
①:有static 修饰的称作静态方法
②:没有static 修饰的称作非静态方法
这样一个类内部的方法调用就存在四种情况:
①:在非静态方法内部调用非静态方法
②:在非静态方法内部调用静态方法
③:在静态方法内部调用静态方法
④:在静态方法内部调用非静态方法

其中前三种情况的调用都是直接调用,直接调用的语法格式为:
方法名(参数1 值,……);
这里方法名为被调用的方法名称,后续紧跟一对小括号,括号内部依次书写调用该方法时传入参数的值,语法上要求传入参数的个数、每个参数的类型都必须和方法声明时保持一致。而这里调用的表达式就代表方法的返回值,可以根据需要使用返回值进行赋值。
示例代码如下:
public class CallMethod{
        public static void main(String[] args){
                int a = 10;
                int b = 2;
                int c = 3;
                int d = 32;
                max(a,b);                     //只比较,比较以后返回值丢失
                int n = max(5,a);         //比较,并把返回值赋值给变量n
                int m = max(c,d);         //比较,并把返回值赋值给变量m
                int maxNumber = max(max(a,b),max(c,d));              //比较a、b、c、d 四个数字的最大值
        }               
        public static int max(int a,int b){
                if(a > b){
                        return a;
                }else{
                        return b;
                }
        }
}
该示例在静态的main 方法内部调用静态的max 方法,因为max 方法在声明时参数列表为2 个int 的参数,则调用的时候必须传入2 个int 值,可以是int 的变量也可以是int 数值。则调用的基本格式为:
max(参数值1,参数值2)
调用的表达式可以在代码中单独成行,当方法的返回值类型不是void时,可以接收方法的返回值,也可以不接收。方法的返回值是一个确定类型的值,所以在以上比较时,方法调用之间可以进行嵌套。
int maxNumber = max(max(a,b),max(c,d));
其中max(a,b)是获得a 和b 的最大值,max(c,d)是获得c 和d 的最大值,然后比较两个获得的最大值,该代码的功能和以下代码的功能相同:
int maxNumber = max(a,max(b,max(c,d)));
总得来说,前三种情况的调用都是使用该种格式。对于最后一种情况,也就是在静态方法内部调用非静态的结构在语法上则比较复杂,以下是一个简单的示例:
public class CallMethod2{
        public static void main(String[] args){
                CallMethod2 cm = new
                CallMethod2();
                int n = cm.max(1,2);
        }
        public int max(int a,int b){
                if(a > b){
                        return a;
                }else{
                        return b;
                }
        }
}

在该代码涉及的语法格式在后续的代码中将进行讲解,这里只做简单的说明。其中:
CallMethod2 cm = new CallMethod2();
该行代码声明并创建了一个CallMethod2 类型的对象cm。接着的代码:
int n = cm.max(1,2);
在调用max 方法时,则使用对象名.方法名调用对应的方法,这里参数的规则和上面介绍的相同。
方法调用后的执行流程
在方法调用时,程序的执行流程和以前的结构就有所区别。简单说,就是当遇到方法调用时,程序的执行流程将跳转到被调用的方法内部,直到被调用的方法返回时,才从调用的位置继续向下执行。以下是一个演示调用过程的示例代码:
public class CallMethod3{
        public static void main(String[] args){
                System.out.println(1);
                printTest();
                System.out.println(2);
                max(10,20);
                System.out.println(3);
        }
        public static int max(int a,int b){
                System.out.println("进入max 方法内部!");
                if(a > b){
                        return a;
                }else{
                        return b;
                }
        }
        public static void printTest(){
                System.out.println("进入printTest 方法内部!");
                int a = 10;
                System.out.println("printTest 方法执行完毕!");
        }
}
则该代码执行时的输出如下:
①:进入printTest 方法内部!printTest 方法执行完毕!
②:进入max 方法内部!
③:从程序执行的输出就可以清晰的看出方法调用时代码的执行顺序。

--------------------------------------------------------------------------------------------------------------------------------------------------------------
方法重载和参数传递
方法相同
在Java 语言中,方法相同的概念和其它程序设计语言不尽相同,Java语言中的方法相同指方法名称和参数列表都相同,其中参数列表相同指参数个数、参数类型和参数排列顺序等相同,参数名称可以不相同。相同的方法访问控制符、返回值类型可以不相同。
以下是一下相同的方法:
public void test(int a,double[] d)
private int test(int i,double[] d1)

在同一个类内部,不能声明相同的方法,否则将出现语法错误。
方法重载
方法重载(overload)是一种语法现象,指在一个类内部出现了多个方法名相同,但是参数列表不同的方法。
方法重载的作用是将功能相同,但是参数列表不同的方法采用相同的方法名称,便于程序员使用。根据方法相同的概念,重载的方法都是不相同的方法。
在Java 提供的API 中,大量应用重载的概念,方便程序员对于系统功能方法的实际使用。恰当的使用重载,可以增强代码的可维护性。
以下是方法重载的示例:
public void a(int a){}
public int a(){}
public void a(int a,String s){}

在以上示例方法中,方法的名称都是a,而参数列表却各不相同,这些方法实现了重载的概念。但是仔细观察可以发现,这些重载的方法的返回值不尽相同,因为返回值类型和方法的重载无关。通常情况下,重载的方法在访问控制符、修饰符和返回值类型上都保持相同,这个不是语法的要求,只是将这些制作成一致以后,便于实际使用。
参数传递
在方法调用时,需要根据方法声明传入适当的参数,通过每次调用方法时传参,极大的增强了方法的统一性,避免了方法内部功能代码的重复。但是在实际传递参数时,如果在方法内部修改了参数的值,则调用时使用的变量是否发生改变呢?
例如如下代码:
/**
* 参数传递代码示例
*/
public class TransferValueDemo {
        public static void main(String[] args) {
                int m = 10;
                int[] a = {1,2,34};
                test(m,a);
                System.out.println(m);
                System.out.println(a[0]);
        }
        public static void test(int n,int[] t){
                n = 0;
                t[0] = 123;
        }
}

则执行该程序以后,程序的输出结果是:10 123。则在调用test 方法时,同样都是传入参数,为什么变量m 的值未改变,而a[0]的值发生了改变呢?下面就来说明该问题。
在参数传递时,一般存在两种参数传递的规则,在Java 语言中也是这样,这两种方式依次是:
一、 按值传递(by value)
按值传递指每次传递参数时,把参数的原始数值拷贝一份新的,把新拷贝出来的数值传递到方法内部,在方法内部修改时,则修改的时拷贝出来的值,而原始的值不发生改变。
说明:使用该方式传递的参数,参数原始的值不发生改变。
二、按址传递(by address)
按址传递指每次传递参数时,把参数在内存中的存储地址传递到方法内部,在方法内部通过存储地址改变对应存储区域的内容。由于在内存中固定地址的值只有一个,所以当方法内部修改了参数的值以后,参数原始的值发生改变。
说明:使用该方式传递的参数,在方法内部修改参数的值时,参数原始的值也发生改变。
在Java 语言中,对于那些数据类型是按值传递,那些数据类型是按址传递都作出了硬性规定,如下所示:
①:按值传递的数据类型:八种基本数据类型和String。
②:按址传递的数据类型:除String 以外的所有复合数据类型,包括数组、类和
接口。
按照这里的语法规则,则上面的代码中变量m 的类型是int,属于按值传递,所以在方法内部修改参数的值时m 的值不发生改变,而a 的类型是数组,属于按址传递,所以在方法内部修改参数的值时,原始的值发生了改变。按值传递和按址传递在实际使用时,需要小心,特别是在方法内部需要修改参数的值时。有些时候,对于按值传递的参数需要修改参数的值,或者按址传递时,不想修改参数的值,下面是实现这两种方式时的示例代码。
按值传递时通过返回值修改参数的值:
/**
* 按值传递的类型通过返回值修改参数的值
*/
public class TransferValueDemo1 {
        public static void main(String[] args) {
                int m = 10;
                m = test1(m); //手动赋值
                System.out.println(m);
        }
        public static int test1(int n){
                n = 15;
                return n;
        }
}

说明:
在该示例代码中,通过把修改以后的参数n 的值返回,来为变量m 赋值,强制修改按值传递参数的值,从而达到修正参数值的目的。
按址传递时通过重新生成变量避免修改参数的值:
/**
* 按址传递时通过重新生成变量避免修改参数的值
*/
public class TransferValueDemo2 {
        public static void main(String[] args) {
                int[] a = {1,2,3};
                test2(a);
                System.out.println(a[0]);
        }
        public static void test2(int[] m){
                int[] n = new int[m.length];
                for(int i = 0;i <m.length;i++){
                        n[i] = m[i];
                }
                n[0] = 10;
        }
}

说明:
在该示例代码中,通过在方法内部创新创建一个数组,并且把传入数组中每个参数的值都赋值给新创建的数组,从而实现复制数组内容,然后再修改复制后数组中的值时,原来的参数内容就不发生改变了。
这里系统介绍了Java 语言中参数传递的规则,深刻理解这些规则将可以更加灵活的进行程序设计。例如使用复合数据类型按址传递的特性可以很方便的实现多参数的返回,代码示例如下:
public int test3(int[] m,int[] n){……}
则该方法中,实际上返回了三种值,一个int 的返回值,数组m 的值,数组n 的值,这只是参数传递的一种基本使用,在JDK 提供的API 文档中也大量的存在该方法。
原创粉丝点击