Java方法

什么是方法

Java方法是语句的集合,方法将语句集合在一起,执行一个功能。

  • 方法是解决一类问题的步骤的有序组合
  • 方法包含于类或对象中
  • 方法在程序中被创建,在其他地方被引用

设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成1个功能,这样立于我们后期的扩展。

System.out.println()方法来分析。System是系统的类,out是System下的输出对象,println就是方法。诸如xxx()都是方法。可以理解为调用系统类标准输出对象里的println方法。

方法命名规则:驼峰命名法,第一个字母小写,第二个单词字母大写。

方法的定义及调用

Java的方法类似于其他语言,是一切用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法:

  • 方法包含一个方法头和一个方法体。下面是一个方法的所有部分:

    • 修饰符(public\private\static):修饰符是可选的,告诉编译器如何调用该方法,定义了该方法的访问类型。
    • 返回值类型(void\int\double…):方法可能会返回值,return ValueType是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下, return Type是关键字void。
    • 方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
    • 参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值称为实参或变量。参数列表是指方法的参数类型、顺序和参数个数。参数是可选的,方法可以不包含任何参数。
      • 形式参数:在方法被调用的是哦湖用于接受外界传入的数据;
      • 实参:调用方法时实际传给方法的数据;
    • 方法体:方法体包含具体的语句,定义该方法的功能。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package com.everweekup.Method;

    public class Demo1 {
    // main方法
    public static void main(String[] args){
    // 实际参数,实际调用给它的参数
    int sum = add(1, 2);
    System.out.println(sum);
    }

    //加法
    // 给方法加个static使其成为类别量就可以在main中调用了
    // 形式参数用于定义
    public static int add(int a, int b){

    return a+b;
    }
    }

方法调用

调用方法:对象名.方法名(实参列表)。

java支持两种调用方法的方式,根据方法是否返回值来选择。当方法返回一个值的时候,方法调用通常被当作一个值。例如:

1
int larger = max(30, 40);

如果方法返回值是void,方法调用一定是一条语句。例如:

1
System.out.println("This is a method return void")

重点:java都是值传递!(理解引用传递)

方法重载

重载就是在一个类中,有相同的函数名称,但形参不同的函数。

方法重载的规则:

  • 方法名称必须相同
  • 参数列表必须不同(个数不同、类型不同、参数排列顺序不同等)
  • 方法返回的类型可以相同也可以不想同
  • 仅仅返回类型不同不足以成为方法的重载

实现理论:方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。

方法重载就是一个类里面有两个相同名字的方法,他们的区别只有方法参数数据类型不同,返回值类型不同。

练习—方法重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.everweekup.Method;

import java.util.Scanner;

public class Demo02 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入num1:");
int num1 = scanner.nextInt();
System.out.println("请输入num2:");
int num2 = scanner.nextInt();
System.out.println("请输入num3:");
int num3 = scanner.nextInt();

// 若定义的max变量类型是double,即使传入参数是int,仍然走的是返回值是double的max方法
double max = max(num1, num2, num3);
System.out.println(max);
}

// static是指方法属于类的,是一个类变量
public static int max(int i, int j){
int result = 0;
if (i > j){
result = i;
}else if (i == j){
// return还可以用于终止方法
System.out.println("==");
return 0;
}else{
result = j;
}

// return要放在最下面
return result;
}

// 方法重载
// 主要是根据传入的参数来判断运行哪个方法
public static double max(int i, int j, int k){
double result = 0;
if (i > j){
result = i;
}else if (i == j){
// return还可以用于终止方法
if(i>k){
result = i;
}else if(i == k){
System.out.println("===");
return 0;
}else{result = k;}

}else{
result = j;
if(j >= k){
result = j;
}else{result = k;}
}

// return要放在最下面
return result;
}
}

命令行传参

有时候你希望运行一个程序的时候再传递给它消息,这要靠传递命令行参数给main()函数来实现。

练习—命令行传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.everweekup.Method;

public class CommandArgs {
public static void main(String[] args) {
for(int i=0; i<args.length; i++){
System.out.println("args["+i+"]="+args[i]);
}
// 增强型for
for(String x : args){
System.out.println("args: "+x);
}
}
}

命令行编译运行要注意退到package的src目录下执行java才可。

可变参数

有时候利用方法重载,仅因为参数的一些小细节,需要写较多的重载方法,这时就会用到可变参数,取避免这些冗余的操作。

从JDK1.5开始,java支持传递同类型的可变参数给一个方法,在方法声明中,在指定参数类型后加一个省略号(…)。

一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前申明。

练习—可变参数

练习1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.everweekup.Method;

public class ChangableArgs {
public static void main(String[] args) {
// changableargs方法存在类里,所以需要从类里调用方法需要先new一个对象
ChangableArgs test1 = new ChangableArgs();
test1.test(1, 2, 3, 4, 5);
}
// 可变长参数通过一个数组来接收可变参数,可变长参数必须是方法最后一个参数
public void test(int a, int... i){
for(int x : i){
System.out.print(x+"\t");
}
}
}

练习2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.everweekup.Method;

public class ChangableArgs {
public static void main(String[] args) {
// changableargs方法存在类里,所以需要从类里调用方法需要先new一个对象
ChangableArgs test1 = new ChangableArgs();
// test1.test(1, 2, 3, 4, 5);
// 类里的static方法可以new类对象来引用,也可以直接调用
test1.printMax(1.0, 3.0, 35, 55, 3, 2, 4, 88, 88);
// 也可以new一个double数组对象传参
printMax(new double[] {1.0, 5, 7, 88, 9});

}
public static void printMax(double... num){
double max = 0;
int gap = 1;
if (num.length == 0){
System.out.println("None args, You need to input some numbers!");
}
for(double arg : num){
// 存放第一个arg
max = arg;
// 过度掉第一个循环,从第二次开始比较
if (gap == 1){
gap++;
continue;
}
if (arg>=max){
max = arg;
}
}
System.out.println("The Max Value Is :"+max);
}

public void test(int a, int... i){
for(int x : i){
System.out.print(x+"\t");
}
}

}

递归

递归就是方法调用自身。

利用递归可以用简单的程序来解决一些复杂的问题。它通常把一个大型复杂的向题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。

递归的能力在于用有限的语句来定义对象的无限集合。

递归结构包括两个部分:

  • 递归头:什么时候不调用自身方法。如果没有头,将陷入死循环。
  • 递归体:什么时候需要调用自身方法。

练习—递归方法

练习1.阶乘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.everweekup.Method;

public class Recursion {
public static void main(String[] args) {
System.out.println(f(3));
}

public static int f(int n){
// 2!=1*2
// 3!=1*2*3
if (n == 1){
return 1;
}else{
// 3 * f(2)
// 3 * 2 * f(1)
return n*f(n-1);
}
}
}

总练习

计算器

写ー个计算器,要求实现加减乘除功能,并且能够循环接收新的数据,通过用户交互实现。

◆思路推荐:

◆写4个方法:加減乘除

◆利用循环+ switch进行用户交互

◆传递需要操作的两个数

◆输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package com.everweekup.Method;

import java.util.Scanner;

public class Calculator {
public static void main(String[] args) {
// 设置一个全局的输入流
Scanner scanner = new Scanner(System.in);

Calculator calTest = new Calculator();

calTest.Calculate(scanner);

scanner.close();

}
public void Calculate(Scanner scanner){
int status = 1;

// Scanner scanner = new Scanner(System.in);
System.out.println("请输入您要进行的运算: "+"加法 "+"减法 "+"除法 "+"乘法 "+"退出 ");
String str = scanner.nextLine();

System.out.println("请输入要计算的数1: ");
double num1 = scanner.nextDouble();
System.out.println("请输入要计算的数2: ");
double num2 = scanner.nextDouble();


switch(str){
case "加法":
Addition(num1, num2);
break;
case "减法":
Subtraction(num1, num2);
break;
case "乘法":
Multiplication(num1, num2);
break;
case "除法":
Division(num1, num2);
break;
default:
System.out.println("您没有输入任何选项,机器进入休眠模式~");
status = 0;
}
System.out.println("是否继续进行运算?: 是 ? 否");

// 此scanner用于接受前面nextDouble方法产生的换行符,避免出现scanner方法直接跳过的问题。
String _ = scanner.nextLine();

String judge = scanner.nextLine();

// 测试用
// System.out.println(judge);

if(judge.equals("是")){
//注意,这里不能关闭输入流,关闭会报错“Exception in thread "main" java.util.NoSuchElementException: No line found”
// scanner.close();
Calculate(scanner);
}else{
System.out.println("感谢您的使用,祝您生活愉快~");
// scanner.close();
}
}

public void Addition(double... x){
double sum = 0;

for(double i : x){
sum += i;
}
System.out.println("求和运算的结果为: "+sum);
}
public void Subtraction(double... x){
double sn = 0;
for(double i : x){
if (sn == 0){
sn = i;
continue;
}
sn -= i;
}
System.out.println("减法运算的结果为: "+sn);
}
public void Multiplication(double... x){
double mn = 0;
for(double i : x){
if (mn == 0){
mn = i;
continue;
}
mn *= i;
}
System.out.println("乘法运算的结果为: "+mn);
}
public int Division(double... x){
double dn = 0;
if (x[1] == 0.0){
System.out.println("被除数不能为0,请重新输入。");
return 0;
}
for(double i : x){
if (dn == 0){
dn = i;
continue;
}
dn /= i;
}
System.out.println("除法运算的结果为: "+dn);

return 0;
}
}

遇到的问题

1.Exception in thread “main” java.util.NoSuchElementException: No line found

原因:Scanner input = new Scanner(System.in) 中Scanner打开的是标准流, 一旦执行关闭在下次循环中将无法打开,建议使用全局配置,最后在main方法中一次性关闭,而我这里只是设置了局部的流,即在Calculate方法内部设置了流,且关闭后就会出错。

修正:设置全局流,在main方法设置流,并将流传入Calculate使得其能够使用输入输出流,当Calculate方法递归完成后,即可关闭流。

2.有时候scanner没有停顿输入数据,程序就直接跳过了

原因:原因是 nextLine() 方法不能放在 nextDouble() 等类似方法的代码段的后面,其实,他不是跳过你了,而是他已经有内容了,内容就是 \n。因为 nextDouble() 接收一个整型字符,不会读取 \n,nextline() 读入一行文本,会读入 \n 字符。

修正:nextDouble()方法后和nextLine()方法之前再设置一个nextLine()方法用于接受多余的字符,确保下一行的nextLine()语句顺利执行。