Java 方法
文章目录
方法
- 语句的集合,在一起执行一个功能
- 解决一类问题的步骤的有序组合
- 包含于类或对象中
- 在程序中被创建,在其他地方被引用
设计原则
原子性:一个方法只完成一个功能,利于后期扩展
优点:
- 使程序变得更简短而清晰
- 有利于程序维护
- 提高程序的开发效率
- 提高了代码的重用性
命名规则
- 第一个单词应以小写字母作为开头,后面单词则用大写字母开头,不使用连接符。例如:
setByName()
- 下划线可能出现在JUnit的测试方法名称中用以分隔名称的逻辑组件;典型模型:
test<MethodUnderTest>_<state>
。
例如:testPop_emptyStack
方法的定义
修饰符 返回值类型 方法名(参数类型 参数名){
方法体
return 返回值;
}
public static int age(int birthday){
return birthday;
}
public static int max(int num1, int num2){
return num1 > num2 ? num1 : num2;
}
方法包含一个方法头和方法体
-
主函数
main
方法的头部是不变的- 带修饰符
public
和static
- 返回
void
类型 - 方法名字是
main
, String[]
类型参数:String[]
表明参数是字符串数组
- 带修饰符
-
其它语言中方法指过程和函数
- 返回非
void
类型返回值的方法称为函数 - 返回
void
类型返回值的方法叫做过程
- 返回非
-
方法头
-
修饰符:可选的,告诉编译器如何调用该方法,定义了该方法的访问类型
-
返回值类型:方法可能会返回值
returnValueType
是方法返回值的数据类型- 方法执行没有返回值,
returnValueType
是关键字void
-
-
方法名:方法的实际名称;方法名和参数表共同构成方法签名
-
参数:参数像是一个占位符
- 当方法被调用时传递值给参数,这个值被称为实参或变量
- 参数列表指方法的参数类型、顺序和参数的个数
- 参数是可选的,方法可以不包含任何参数
-
方法体:包含具体的语句,定义该方法的功能
方法调用
main
方法是被JVM
调用的,此外main
方法和其它方法没区别Java
支持两种调用方法的方式,根据是否有返回值选择- 程序调用一个方法时程序的控制权交给了被调用的方法
- 当被调用方法的返回语句执行
- 或到达方法体闭括号时候交还控制权给程序
- 当方法返回一个值的时候,方法调用通常被当作一个值
int larger = max(10,20);
- 如果方法返回值是void,方法调用一定是一条语句
System.out.println("欢迎访问");
public static void main(String[] args) {
int i = 5;
int j = 2;
int k = max(i, j);
System.out.println(i+"和"+j+" 比较; 最大值是: "+k);}
/** 返回两个整数变量较大的值 */
public static int max(int num1, int num2){
return num1 > num2 ? num1 : num2;
}
/**
运行结果:
5和2 比较; 最大值是: 5
*/
递归
方法自身调用自身
- 递归头:必须有结束调用的时候,若没有会陷入死循环
- 递归体:调用自身方法的时候
-
连续调用 → 边界结束 → 值返回
-
缺点:深度越大时空复杂度越高;对性能要求很高
void关键字
void类型方法,不返回值
public static void main(String[] args) {
printGrade(78.5);
}
public static void printGrade(double score) {
if (score >= 80.0)
System.out.println('B');
else if (score >= 70.0)
System.out.println('C');
else
System.out.println('F');}
运行结果:C
//一个void方法的调用一定是一个语句; 所以它被在main方法中以语句形式调用:就像任何以分号结束的语句一样
通过值传递参数
如果调用一个方法需要提供参数,必须按照参数列表指定的顺序提供
public static void main(String[] args) {
int a = 1; int b = 2;
System.out.println("原a值:"+a+",原b值:"+b);
swap(a, b); // 调用swap方法
System.out.println("现a值:"+a+",现b值:"+b);}
/** 交换两个变量的方法 */
public static void swap(int n1, int n2) {
System.out.println("交换前n1的值"+n1+",n2的值"+n2);
// 交换 n1 与 n2的值
int temp = n1;
n1 = n2;
n2 = temp;
System.out.println("交换后n1的值"+n1+",n2的值"+n2);
}
/**
运行结果:
原a值:1,原b值:2
交换前n1的值1,n2的值2
交换后n1的值2,n2的值1
现a值:1,现b值:2
*/
//传递两个参数调用swap方法,方法被调用后,实参的值并没有改变
- Java 基本数据类型传递参数时是值传递
- 传递数值的副本,对原数据无影响
- 引用类型传递参数时是引用传递
- 引用
z = null
只是将引用z
不指向任何对象 ,并不会对原先指向的对象数据进行修改- 但原数据若没有其他引用将无法找回变成垃圾
- 引用传递的是引用地址,在此对数据进行此操作会影响原数据
- 引用
重载(Overload)
定义
- 在一个类里,方法名相同、参数不同,返回类型可相同也可不同
- 每个重载的方法(构造函数)都必须有独一无二的参数列表
- 最常用的就是构造器的重载(不同数量的参数)
public static int max(int num1, int num2){
return num1 > num2 ? num1 : num2;
}
public static double max(double num1, double num2) {
return num1 > num2 ? num1 : num2;
}
-
两个同名
max()
方法,根据实际调用时传递的参数类型判断被调用的方法int
或double
类型参数Java
编译器根据方法签名判断哪个方法应该被调用。
-
方法重载可以让程序更清晰易读
- 执行密切相关任务的方法应该使用相同的名字
重载规则
- 重载必须改变参数列表(参数个数或类型不一样)
- 重载可以改变返回类型、访问修饰符
- 重载可以声明新的或更广的检查异常
- 方法能够在同一个类中或者在一个子类中被重载
- 无法以返回值类型作为重载函数的区分标准
public class Overloading {
public int test(){
System.out.println("无参,返回int类型");
return 1;
}
public void test(int a){
System.out.println("一个int类型参数,无返回值");
}
//以下两个参数类型顺序不同
public String test(int a,String s){
System.out.println("test3");
return "returntest3";
}
public String test(String s,int a){
System.out.println("test4");
return "returntest4";
}
public static void main(String[] args){
Overloading o = new Overloading();
System.out.println(o.test()); // 调用第一个方法
System.out.println(o.test(1)); // 调用第二个方法
System.out.println(o.test(1,"test3")); // 调用第三个方法
System.out.println(o.test("test4",1)); // 调用第四个方法
}
}
重写(Override)
- 外壳不变,核心重写
- 子类对父类的允许访问的方法的实现过程进行重新编写
- 返回值和形参都不能改变
- 子类根据需要定义特定于自己的行为
- 即子类可以根据需要实现父类的方法
- 面向对象的原则里,重写意味着可以重写任何现有方法
class Anima{
public void move(){
System.out.prontln("动物可以动")
}
}
class Dog{
public void move(){
System.out.println("小狗可以跑")
}
public void eat(){
System.out.println("这是一个测试")
}
}
public class Test{
public static void main(String[] args){
Animal a = new Animal();
Animal b = new Dog();
a.move;
b.move;
b.eat; //编译错误,因为Animal类中没有eat方法
}
}
//在编译阶段,只是检查参数的引用类型
//在运行时,Java虚拟机(JVM)指定对象的类型且运行该对象的方法
/**
运行结果:
动物可以动
小狗可以跑
*/
重写规则
-
参数列表不允许改变
-
返回类型可以不完全一样
- 但必须是父类返回值的派生类
- java5 及更早版本返回类型要一样,java7 及更高版本可以不同
-
访问权限不能降低
-
父类的成员方法只能被子类重写
- 如果不能继承一个类,则不能重写该类的方法
-
声明为
final
、private
的方法不能被重写 -
构造方法不能被重写
-
声明为 static 的方法不能被重写,但是能够被再次声明
-
子类和父类在同一个包中
- 子类可以重写父类所有方法
- 除了声明为
private
和final
的方法
-
子类和父类不在同一个包中
- 子类只能重写父类的声明为
public
和protected
的非 final 方法
- 子类只能重写父类的声明为
-
重写的方法能够抛出任何非强制异常,无论原方法是否抛出异常
- 但不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以
- 例如: 父类的方法申明了一个检查异常
IOException
- 重写的时候不能抛出
Exception
异常 - 因为
Exception
是IOException
的父类,只能抛出IOException
的子类异常
- 重写的时候不能抛出
super关键字
需要在子类调用父类的方法时,要使用super关键字
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
super.move(); // super.调用父类的方法
System.out.println("狗可以跑和走");
}
}
public class TestDog{
public static void main(String args[]){
Animal b = new Dog(); // Dog 对象
b.move(); //执行 Dog类的方法
}
}
/**
运行结果:
动物可以移动
狗可以跑和走
*/
重写和重载
区别
区别点 | 重载方法 | 重写方法 |
---|---|---|
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可以修改 | 完全一样或原返回值的子类类型 |
异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或者更广的异常 |
访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
总结:
-
方法的重写和重载是java多态性的不同表现
- 重写是父类与子类之间多态性的一种表现
- 重载可以理解成一个类的多态性表现形式
-
方法重载:一个类中定义了多个方法名相同,参数不同的方法
- 根据传入的参数不同,调用不同方法
-
方法重写:子类方法与父类的方法的名字相同,参数、返回值也相同的方法
- 重写就是将父类的方法重新实现
重载
- 同一方法名的方法
- 必须改变参数列表
- 返回值类型可以改变
- 方法体可以不变
- 访问权限可以更改,异常范围可以更改
重写
- 需要有继承关系,才可以有子类重写父类的方法
- 方法名、参数列表完全相同;返回值类型需要完全一样或父类返回值的的派生类
- 访问权限可以放开但不能降低、
- 抛出的异常范围可以缩小但不可扩大
参数作用域
变量的范围是程序中该变量可以被引用的部分:
- 方法内定义的变量被称为局部变量
- 局部变量的作用范围从声明开始,直到包含它的块结束
- 局部变量必须声明才可以使用
- 方法的参数范围涵盖整个方法
- 参数实际上是一个局部变量
- for循环的初始化部分声明的变量,其作用范围在整个循环
- 但循环体内声明的变量其适用范围是从它声明到循环体结束
可以在一个方法里,不同非嵌套块中多次声明一个具有相同名称的局部变量,但不能在嵌套块内两次声明相同名称局部变量
命令行参数
运行一个程序时候再传递给它消息要靠传递命令行参数给main()函数实现
命令行参数是在执行程序时候紧跟在程序名字后面的信息
public static void main(String args[]){
int[] a = new int[10];
for(int i=0; i<a.length; i++){
System.out.println("a[" + i + "]: " + a[i] + "\t");
}
}
运行结果:
a[0]: 0 a[1]: 0 a[2]: 0 a[3]: 0 a[4]: 0 a[5]: 0 a[6]: 0 a[7]: 0 a[8]: 0 a[9]: 0
可变参数
JDK1.5开始Java支持传递同类型可变参数给一个方法
- 在方法声明中,在指定参数类型后加一个省略号(…)
- 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数
- 任何普通的参数必须在它之前声明
- 对于可变参数,编译器会将其转型为一个数组
- 所以在函数内部可变参数名即可看作数组名
//声明可变参数typeName... parameterName 类似于 typeName[] parameterName
public class Test {
void func(String... args){}
void func(String [] args){} //这两个方法的命名是相等的,不能作为方法的重载
public static void main(String[] args) {
Test t = new Test();
test.func("Wallen","John","Smith");
test.func(new String[3]); //可变参数,即可向函数传递 0 个或多个参数
//这两种调用方法效果一样
}
}
//对于可变参数的方法重载保证参数列表不一样
void func(String... args);
void func(String args1,String args2);
func("Wallen","John");//优先匹配固定参数的方法
finalize()方法
Java 允许定义这样的方法,
finalize( )
- 在对象被垃圾收集器析构(回收)之前调用
- 用来清除回收对象
- Java 的内存回收可以由 JVM 来自动完成
- 如果手动使用,则可以使用上面的方法
例如:你可以使用 finalize() 来确保一个对象打开的文件被关闭了。
在 finalize() 方法里,必须指定在对象销毁时候要执行的操作。
finalize() 一般格式是:
protected void finalize() { /* 在这里终结代码 */ }
关键字 protected 是一个限定符,确保 finalize() 方法不会被该类以外的代码调用
构造方法
- 当一个对象被创建时候,构造方法用来初始化该对象
- 构造方法和所在类的名字相同,但构造方法没有返回值
- 通常会使用构造方法给一个类的实例变量赋初值
- 或者执行其它必要的步骤来创建一个完整的对象。
- 所有的类都有构造方法,Java 自动提供了一个默认构造方法
- 默认构造方法的访问修饰符和类的访问修饰符相同
- 类为
public
,构造函数也为public
;类改为protected
,构造函数也改为protected
- 类为
- 但定义了自己的构造方法之后,默认构造方法就会失效
- 默认构造方法的访问修饰符和类的访问修饰符相同
public class Puppy{
public Puppy(){ //无参构造函数(无构造方法时的默认构造方法)
}
public Puppy(String name){ //有参构造函数,这个构造器仅有一个参数:name
}
public static void main(String[] args){
Puppy p = new Puppy(); //调用构造方法初始化一个对象
PupPy p1 = new Puppy("张三"); //调用有参构造方法初始化一个对象
}
}