[Java入门笔记] 面向对象编程基础(二):方法详解
什么是方法?
简介
在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象。
无论是从语法和功能上来看,方法都有点类似与函数。但是,方法与传统的函数还是有着不同之处:
在结构化编程语言里,函数是基本的程序组成单元,一个程序由一个个函数组成;
在面向对象编程语言里,类才是程序的基本单元,方法是属于类或对象的,不能独立存在;
Java语言里方法的特征主要在以下几个方面:
方法不能够独立的存在,方法只能够定义在类里面,所属与某个类或对象;
方法不能够被独立地执行,必须使用类或者对象作为调用者;
方法的分类,在Java中,方法主要分为以下几类:
Java中的方法,主要可以分为构造方法和普通方法,而普通方法可以分为类方法和对象方法;
方法的定义
在前面一篇blog,我们已经知道了方法的定义方式,我们再来回顾一下:
构造方法:
[修饰符] 类名([形参 参数名]){ //功能代码 }
构造方法是你一种特殊的方法,它与普通方法有两个不同之处:方法的名字必须和类名相同,它没有返回值
普通方法:
[修饰符] 返回值 方法名([形参 参数名]){ //功能代码 }
我们可以看到,普通方法的结构主要分为5个部分,
修饰符:设置方法的访问权限,可以是public、protected、private、或者是不填;
返回值:调用该方法完成之后返回的内容,可以是基本的数据类型,可以是引用类型,也可以没有返回值,当没有返回值时,使用void
方法名:自定义的标识符,主要是调用时使用,在类外部或非子类中调用时使用 类.方法名 或者 对象名.方法名
形参:形参调用该方法时所需要传递的参数,可以有0个或多个
方法体{}:方法体内主要用于定义实现功能的代码
看一个完整的例子:
定义一个Person类:
public class Person{ //定义一个Person类 public String name; //String类型的属性name public int age; //int类型的属性age public Person(String n, int a){ //构造方法,有两个参数n和a,在创建对象是如果调用了该构造方法就会将name属性设置为传进来的n,age为a。 name = n; age = a; } public void showName(){ //普通方法,主要功能是显示对象的name System.out.println("我的名字是" + name); } public void setAge(int a){ //普通方法,主要功能是设置对象的age,有一个参数,将对象的age设置为传递进来的a变量 age = a; } public int getAge(){ //普通方法,有一个返回值,返回对象的age return age; } }
使用:
public class Test{ public static void main(String[] args){ Person p = new Person("张三", 20); //实例化一个对象,调用构造方法,传递进去两个参数,将参数设置给了对象的name属性和age属性 p.showName(); //调用p对象的showName方法,执行了方法体里面的代码,打印出了p对象的name p.setAge(25); //调用了p对象的setAge方法,重新设置了p对象的age属性值为25 int pAge = p.getAge(); //调用了p对象的getAge方法,该方法有一个返回值,将p对象的age属性值返回了出来,并将返回值赋值给了pAge变量 } }
方法的调用与参数的传递在内存中的机制
不在关键点上追根问底的程序猿不是一个好厨师,下面我们开看看方法的调用与参数传递在程序运行的内存中是一个什么样子滴情况:
对于JVM运行机制,有兴趣的可以看看这几篇文章:
当然,有兴趣的并且有一定基础的童鞋推荐大家看看一本好书《深入理解Java虚拟机》
我们来看看上面一个例子的代码:
Person p = new Person("张三", 20);
创建对象的分析我们在上篇blog中分析了,有兴趣的可以围观:[Java入门笔记] 面向对象编程基础(一):类和对象 在最后面
对象创建完毕后,在内存中是这样的一个样子:
程序继续向下执行:
p.showName();
调用p对象的showName方法,执行里面的代码:
println也是一个方法,这个是JavaApi中定义的方法,执行在内存中有点麻烦,现在先不看这个,执行完这句话后打印出“我的名字是张三”
继续下下执行
p.setAge(25);
调用p对象的setAge方法
执行到这一步我们发现,这个方法有一个int类型的形参,名字为a,值为25
继续执行setAge方法,将a的值赋值给age
此时p对象的age属性值变化为为25,方法执行完成后清除完成代码的引用,继续下面的代码
int pAge = p.getAge();
执行到这一句会将p对象的age返回,并且赋值给int类型变量pAge,所以pAge的值此时也为25:
方法的重载
什么是方法的重载?
方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。调用重载方法时,Java编译器能通过检查调用的方法的参数类型和个数选择一个恰当的方法。方法重载通常用于创建完成一组任务相似但参数的类型或参数的个数不同的方法。
如何实现方法的重载?
方法的重载要求两同一不同,三不受影响,两同指的是同一个类中相同的方法名,一不同是方法的形参不同,这个不同主要体现在参数个数不同或者类型不同、参数位置不同。
两不受影响是:
修饰符不同不影响方法重载。
方法的返回值类型不能用于区分方法的重载,也就是说,无论返回值相同或者不同,都对判断方法是否重载没有影响。
形参的名字不能用于区分方法是否重载,也就是说,如果形参的类型和个数都相同,只有参数的名字不同,则不构成重载。
构造方法的重载:
构造方法也是一种方法类型,也可以实现重载,也遵循上面的规定。
例:
public class Person{ public String name; public int age; public Person(){} public Person(String n, int a){ name = n; age = a } public void setInfo(){ name = "张三"; age = 20; } public void setInfo(String n){ name = n; } public void setInfo(int a){ age = a; } public void setInfo(String n, int a){ name = n; age = a; } public void setInfo(int a, String n){ name = n; age = a; } }
上面的2个构造方法和4个setInfo都是重载的方法,因为它们满足了重载的要求:相同的类中相同的方法名,不同的参数类型或个数。
如果在上面的例子中添加下面的方法,不是重载:
private int setInfo(){} //修饰符和返回值不同,但是上面已经有一个没有参数的setInfo方法,所以不是重载
public void set(){} //方法名不同,不是重载
public void setInfo(int b){} //参数名不同,类型上面有相同的,不是重载
重载方法的使用:
public class Test{ public static void main(String[] args){ Person p1 = new Person(); Person p2 = new Person("李四", 30); //这两个对象被实例化时第一个没有传递参数,所以调用第一个构造方法,第二个有两个参数,所以调用第二个构造方法 p1.setInfo(); //没有参数,调用第一个setInfo方法 p1.setInfo("王五"); //有一个String类型的参数,调用第二个setInfo方法 } }
形参个数可变的方法
如果我们在实现某个方法不确定方法有多少个参数数,我们应该怎么定义这个方法?
比如,如果我们要写一个实现加法的方法,而我们不仅仅是要实现2个数相加,而是无论是有多少个数,我们都需要将它们加起来,我们应该怎样定义这个方法?显然,用普通的形式定义或者重载都不能很好的实现,而我们可以使用jdk1.5之后增加的一种形参传递方法定义这个方法。
例:
public class Operation{ public static int add(int... num){ int result = 0; for(int i = 0; i < num.length; i++){ result += num[i]; } return result; } }
这个例子中我们可以看到,定义一个可变的形参的方法,只需要在类型后面加三个点即可,调用这个方法时既可传递多个相同类型的是参数。
在使用num参数时我们可以明显的看到,就是用数组的形式在使用,因此这个可变的参数在本质上来说其实就是一个数组,不过在调用时可以比较方便,请看:
public class Test{ public static void main(String[] args){ Operation ope = new Operation(); ope.add(1,2); //计算1加2 ope.add(3,4,5); //计算3加4加5 } }
我们在使用时不需要再创建一个数组对象。