# Java方法
[TOC]
## 導學
什么是方法,其實我們從一開始就接觸到了方法。這個方法就是我們的主方法。主方法是一個比較特殊的方法,它是程序執行的入口。之前我們還提到可以使用`.`去調用方法,像`System.out.println();`中,`println()`就是一個方法。
所謂方法(函數),**就是就是用來解決一類問題的代碼的有序組合,是一個功能模塊。**
## 方法聲明
語法:
~~~
訪問修飾符 返回類型 方法名(參數列表) {
方法體
}
~~~
示例:
~~~
public static void main(String[] args) {
System.out.println("Hello,World!");
}
~~~
訪問修飾符就是方法允許被訪問的范圍;返回類型可以是void和其他任何類型的數據(包括自己創造的數據類型);方法名需要滿足標識符的全部規則外還需要滿足駝峰原則;參數列表可以省略,既沒有參數,同樣參數可以有多個,每個參數之間使用逗號間隔,參數由數據類型和參數名構造,類似變量的定義;
根據參數和返回值,方法可以分為四類:
1. 無參無返回值
2. 無參有返回值
3. 帶參無返回值
4. 帶參有返回值。
本節課我們就根據這四個分類來給大家介紹方法的具體信息。
## 方法類型
### 無參無返回值方法
首先我們來看一道例題,打印如下所示的圖形

這樣的圖形只需要使用`System.out.println()`就可以打印輸出出來,但是我們發現該例題會要求我們進行重復的打印輸出該圖形。對于這樣一種重復的行為,我們希望將這條打印語句放置在一個方法里面,然后每次遇到同樣的要求,只需要調用方法就可以了。
那么,方法的使用意義就出來了,我們希望使用方法來減少代碼的量!就如同我們之前給大家講過冒泡排序的問題,如果我們每次遇到要冒泡排序的問題,只需要調用一個方法,是不是就方便很多。
~~~
public class One {
// 打印輸出星號的方法
public void printStar() {
System.out.println("********************************");
}
// 一行打印輸出一串星號
public static void main(String[] args) {
//創建一個One類的對象MyOne
One MyOne=new One();
//使用對象名.方法名()去調用方法
MyOne.printStar();
System.out.println("歡迎來到Java的世界!");
MyOne.printStar();
}
}
~~~
在本章節中,我們會碰到很多的概念和語法,這些概念和語法需要我們同學反復記憶。其實關于這些概念和語法的問題沒有為什么,Java的語法規則就是這么規定的,編譯器就只認這些語法。
### 無參有返回值的方法
我們依舊通過一個例題完成:
**求一個長寬都是整數的長方形面積?**
~~~
public class Rectangle {
public int area() {
int length=10;
int width=5;
int area=length*width;
return area;//返回語句,變量名和方法名可以一致,同時注意方法返回值需要和規定的返回值一致。
}
public static void main(String[] args) {
Rectangle rc=new Rectangle();
System.out.println("長方形的面積為:"+rc.area());
}
}
~~~
什么是返回值,返回值其實是本方法求得的結果,這個結果最終可能為其他方法或代碼塊所需要,那么為了將該結果傳遞出去,就需要使用返回值將得出的結果傳遞出去。
### 帶參無返回值方法
例題:
**定義一個求兩個float類型的數據最大值的方法,在方法中將最大值打印輸出**
~~~
public class MaxDemo {
public void max(float a, float b) {//形式參數(形參)
float max;
if(a > b) {
max = a;
} else {
max = b;
}
System.out.println("最大值為:" + max);
}
public static void main(String[] args) {
MaxDemo md = new MaxDemo();
md.max(1.1, 1.3);//實際參數(實參)
}
}
~~~
局部變量的范圍只限于定義它的大括號中,傳遞數值時主方法中可以是變量,也可以是一個字面值,不同類型傳遞會出現類型轉換。
### 帶參有返回值的方法
例題:
定義一個求n!的方法,然后再求1!+ 2!+3!+4!+5!
n!是指階乘,5的階乘就是`1*2*3*4*5`
~~~
public class Four {
//方法不能嵌套定義
//求階乘的方法
public int fac(int n) {
int s=1;
for(int i=1;i<=n;i++) {
s*=i;//s=s*i;
}
return s;
}
public static void main(String[] args) {
Four four=new Four();
int fac=four.fac(3);
System.out.println("3!="+fac);
int sum=0;
//求1!+2!+3!+4!+5!
for(int i=1;i<=5;i++){
fac=four.fac(i);
sum+=fac;
}
System.out.println("1!+2!+3!+4!+5!="+sum);
}
}
~~~
方法的定義必須定義在類的里面,但是不能定義在另外一個方法的里面。方法不能嵌套,帶有返回值的方法是為了參與進一步的運算
## 數組作為方法參數
### 示例一
例題:
**定義方法,打印輸出數組元素的值。**
~~~
public class Five {
//打印輸出數組元素的值
public void printArry(int[] arr) {
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
int[] arr= {10,20,30,40,50,};
Five am=new Five();
am.printArry(arr);
}
}
~~~
### 示例二
例題:
**查找數組元素的值:**
~~~
public class ArraySearch {
//方法參數:數組、要查找的元素
//返回值:Boolean類型
public boolean search(int n,int[] arr) {
boolean flag = false;
for (int i = 0; i < arr.length; i++) {
if(arr[i]==n) {
flag=true;
}
}
return flag;
}
public static void main(String[] args) {
int[] a= {10,20,30,40,50,60};
int b = 30;
ArraySearch as = new ArraySearch();
boolean flag = as.search(b, a);
if(flag) {
System.out.println("存在數據");
} else {
System.out.println("存在數據");
}
}
}
~~~
## 方法重載
方法重載簡單概括就是方法名相同,參數列表不同。

例題:
**定義三個方法,實現int、double和數組類型求和的問題**
~~~
public class MathDemo {
//求兩個int類型數的和
public int plus(int m,int n){
return m+n;
}
//求兩個double類型數的和
public double plus(double m,double n){
return m+n;
}
//求數組元素的累加和
public int plus(int[] arr){
int sum=0;
for(int i=0;i<arr.length;i++){
sum=sum+arr[i];
}
return sum;
}
public static void main(String[] args) {
int m=5,n=10;
int[] arr={1,2,3,4,5,6};
MathDemo mathDemo=new MathDemo();
System.out.println("int類型的和:"+mathDemo.plus(m,n));
System.out.println("double類型的和:"+mathDemo.plus(5.6,7.8));
System.out.println("數組元素的和:"+mathDemo.plus(arr));
}
}
~~~
## 方法的傳值
### 基本數據類型的傳值
例題:
**對兩個變量的值進行交換并打印輸出(傳值問題)**
~~~
public class ExchangeDemo {
//交換方法
public void swap(int a,int b){
int temp;
System.out.println("交換前:a="+a+","+"b="+b);
temp=a;
a=b;
b=temp;
System.out.println("交換后:a="+a+","+"b="+b);
}
public void swapTest(){
//ExchangeDemo ex=new ExchangeDemo();
//普通方法調用方法不需要定義對象,直接調用即可 方法名(實參);
int m=4,n=5;
System.out.println("交換前:m="+m+","+"n="+n);
swap(m,n);
System.out.println("交換后:m="+m+","+"n="+n);
}
public static void main(String[] args) {
ExchangeDemo ex=new ExchangeDemo();
ex.swapTest();
/*int m=4,n=5;
System.out.println("交換前:m="+m+","+"n="+n);
ex.swap(m,n);
System.out.println("交換后:m="+m+","+"n="+n);*/
}
}
~~~
在方法運行之后,我們會發現,m與n的值并沒有發生改變。

這是因為首先創建m,n變量,會在內存中開辟空間存儲對應的值,然后在方法調用的時候把m和n的值傳給變量a,b,這時候只是把4和5這兩個值傳過去了。并不是把m和n的內存地址傳遞過去了。
實際上,這道題目告訴我們,如果方法的參數是基本數據類型,那么在方法內對參數進行修改,不會影響到傳遞的實際參數。
### 數組的傳值
例題:
**定義一個用于修改某個數組元素的方法**
~~~
public class Ten {
//定義一個用于修改某個數組元素值的方法
public void updateArry(int[] a) {
a[3]=15;
System.out.println("數組a的元素為:");
for(int n:a) {
System.out.print(n+" ");
}
System.out.println();
}
public static void main(String[] args) {
Ten b=new Ten();
int[] a1= {1,2,3,4,5};
System.out.println("方法調用前數組a1元素為:");
for(int n:a1) {
System.out.print(n+" ");
}
System.out.println();
b.updateArry(a1);
System.out.println("方法調用后數組a1元素為:");
for(int n:a1) {
System.out.print(n+" ");
}
}
}
~~~
總結:
主方法中聲明變量并傳值到方法中,基本數據類型傳值是把值傳過去,沒有傳變量的地址,所以如果在普通方法中修改了變量的值,對主方法中的普通變量沒有影響。但是如果主方法中聲明的是數組(引用數據類型),則傳值是把變量地址傳過去了(傳過去的是數組的第一個元素的地址),在普通方法中修改變量會影響主方法的變量。傳值都是傳的的變量里的值,基本數據類型的是值本身,引用類型的是對象的地址。但是數組可以修改對象里的東西,字符串不可以。
## 可變參數列表
### 什么是可變參數列表
示例:
~~~
public void sum(int...n) {
}
~~~
可變參數列表指的是參數的數量不固定,但是參數的類型是固定的,參數列表規定了是哪一種類型,隨后的參數就只能是哪一種類型。
示例一:
~~~
public class Demo {
//求和
public void sum(int...n) {
int sum = 0;
for(int i:n) {//其實我們可以將可變參數列表看作為一個數組
sum = sum + i;
}
System.out.println("sum="+sum);
}
public static void main(String[] args) {
Demo de = new Demo();
de.sum(1);
de.sum(1,2);
de.sum(1,2,3);
//de.sum(1,1.2);傳入的必須是int類型
}
}
~~~
示例二:
~~~
public class ArgsDemo1 {
//查找
public void search(int n,int...a){//參數列表中如果有兩個或兩個以上的參數,可變參數一定是在最后的。
boolean flag=false;
for(int a1:a){
if(a1==n){
flag=true;
break;
}
}
if(flag){
System.out.println("找到了"+n);
} else{
System.out.println("沒找到"+n);
}
}
/*public void search(int n, int[] a) {
//可變參數方法換成數組是不算重載的,算重復定義
}*/
/*public void search(int n, int... a, int...b) {
//一個方法中只能有一個可變參數。
}*/
public static void main(String[] args) {
ArgsDemo1 ad1=new ArgsDemo1();
ad1.search(3,1,2,3,4,5);
int[] a={1,2,3,4,5};
ad1.search(3,a);//可變參數列表可以和數組進行兼容,可以將數組傳遞給可變參數列表
}
}
~~~
總結:
1. 可變參數列表指的是參數數量是不確定的,可以隨時變化。有時候也稱可變原參數。
2. 參數列表中如果有兩個或兩個以上的參數,可變參數一定是在最后的。例如:`public void a(int a,int... b){ }`是正確的,但是如果把`int... b`寫前面則是錯誤的。
3. 可以將數組傳遞給可變參數。
4. 一個方法中只能有一個可變參數。
5. 可變參數方法換成數組是不算重載的,算重復定義
### 可變參數列表作為方法參數的重載問題
本節課,我們來看一下當進行方法重載時,可變參數列表方法,調用順序的問題。
~~~
public class Demo {
public int sum(int a, int b) {
System.out.println("不帶可變參數列表的方法被調用");
return a + b;
}
//求和
public int sum(int...n) {
int sum = 0;
for(int i:n) {//其實我們可以將可變參數列表看作為一個數組
sum = sum + i;
}
System.out.println("帶可變參數列表的方法被調用");
return sum;
}
public static void main(String[] args) {
Demo de = new Demo();
System.out.println("和為:" + de.sum(1,2));
System.out.println("和為:" + de.sum(3,4));
System.out.println("和為:" + de.sum(3,4,5));
}
}
~~~
總結:
若有多個重載方法,則可變參數列表所在的方法是最后被訪問的(如果主方法所傳參數其他重載方法可以滿足,則調用其他方法,只有其他方法都不滿足,才會調用可變參數列表所在的方法)
## 再議文檔注釋
至此,對于方法的學習,我們已經完成的差不多了,接下來,我們再來看一看文檔注釋對于整個類使用的幫助
在 javadoc 中也提供了豐富的標記
* @author:指定程序的作者
* @version:指定源代碼的版本
* @param:在方法中指定參數
* @return:在方法中指定返回值
~~~
/**
* <h2>可變參數列表方法重載的應用</h2>
* @author 作者
* @version 版本號
*/
public class Demo {
/**
* <p style="color:red">求和</p>
* @param a 參數
* @param b
* @return 返回值
*/
public int sum(int a, int b) {
System.out.println("不帶可變參數列表的方法被調用");
return a + b;
}
}
~~~
在文檔注釋中可以使用html標簽,但是不能用自封閉的標簽。
使用javadoc命令生成**API文檔**,-d指定生成的目錄地址。
~~~
cmd中執行命令:
javadoc -encoding utf-8 -d apidoc -version -author Demo.java
~~~
在eclipse中執行生成doc文檔
1. 在工具欄project選項中右鍵選擇Generate Javadoc選項

2. 可以選擇生成整個項目的幫助文檔和單獨一個類的幫助文檔,以及選擇輸出地址

3. 生成標題

4. 輸出文檔
各位同學可以嘗試學習Java jdk的幫助文檔:[https://tool.oschina.net/apidocs/apidoc?api=jdk-zh](https://tool.oschina.net/apidocs/apidoc?api=jdk-zh)
## 方法的調試
在方法調用處打上斷點。
~~~
F5進入方法內部執行
F6單步執行
F7由方法內部跳回調用處
~~~
## 練習
一、選擇
1. 下列代碼的運行結果為:

~~~
A. 沒有任何輸出
B. 編譯錯誤
C. 曉明今年7歲了
D. 曉明
~~~
2. 下列代碼運行的結果是()

~~~
A. Hello,My name is Tom.
B. Hello,My name is Peter.
C. Hello,My name is Peter.My name is Tom.
D. My name is Peter.
~~~
3. 下列語句的執行結果為()

~~~
A. 運行異常
B. 運行錯誤
C. 我的英文名字叫Tom
D. 什么都不輸出
~~~
4. 下面這段程序的執行結果為:

~~~
A. 12
B. a+b+c=12
C. a+b+c=16
D. 16
~~~
5. 已知如下代碼,則位置(1)處正確的方法調用代碼為?

~~~
A. method.display(arr);
B. method.display(arr[0]);
C. method.display(a);
D. method.display(a[0]);
~~~
6. 已知方法的定義形式如下:`public void plus(int a,int b){}`
下列選項中哪兩個是合法的重載方法?(多選)
~~~
A. public int plus(int a){}
B. public int plus1(int m,int n){}
C. public void plus(float a,float b){}
D. public int plus(int a,int b){}
~~~
7. 下列代碼,前者與后者是重載關系的是:
~~~
A. public void show(){}和public void show(int num){}
B. public void show(){}和public void print(int num){}
C. public void show(){}和public int show(){}
D. public void show(int a){}和??? public void show1(int b){}
~~~
8. 以下代碼的輸出結果是什么?

~~~
A. 40
B. 8
C. 4
D. 10
~~~
9. 以下代碼的輸出結果是什么?

~~~
A. 2
B. 3
C. 4
D. 6
~~~
10. 關于可變參數列表的描述正確的是
~~~
A. 當可變參數列表作為方法參數時,不能將數組傳遞給可變參數列表
B. 一個方法中,只能有一個可變參數列表作為參數
C. 重載的方法中,可變參數列表作為參數的重載方法不會優先被調用
D. 數組作為方法參數時,可以將多個值同時傳遞給數組
~~~
二、編程
1. 定義一個方法,根據商品總價,計算出對應的折扣并輸出。折扣信息如下:
* 總價<100,不打折
* 總價在100到199之間,打9.5折
* 總價在200以上,打8.5折
任務:
1、定義一個方法,根據商品總價輸出折后總價
2、在主方法中定義對象
3、使用對象調用定義的方法
~~~
public class DisCountDemo {
//根據商品總價輸出折后總價
public static void main(String[] args) {
//定義對象
//定義商品總價存放到變量中
//調用方法,輸出折后商品總價
}
}
~~~
2. 編寫方法,求數組元素的平均值。
任務:
1、定義一個方法,求數組的平均值
2、在主方法中定義對象,并初始化一個float類型的數組,調用方法求數組元素的平均值,并將平均值打印輸出
~~~
public class AverageDemo {
//求數組元素的平均值
public static void main(String[] args) {
//定義對象
//創建float類型的數組并初始化
//調用方法求平均值并打印輸出
}
}
~~~
3. 定義兩個重載的方法,分別求圓和長方形的面積。
任務:
1、 定義兩個求面積的重載方法,圓周率可以使用`Math.path`這個常量代替
2、在主方法中調用方法并輸出
~~~
public class AreaDemo {
//求圓形面積
//求長方形面積
public static void main(String[] args) {
//定義對象
//定義一個double類型的變量存放半徑,并初始化
//定義兩個變量存放長和寬,并初始化
//調用方法,求圓的面積并打印輸出
//調用方法,求長方形面積并打印輸出
}
}
~~~