举个例子,假设“植物大战僵尸”程序的实现代码中,每个豌豆射手发射炮弹的代码为100行,那么每种植一个豌豆射手都需要重复编写这100行的代码,这样程序会变得很臃肿,可读性也非常差。
为了解决代码重复编写的问题,可以将发射炮弹的代码提取出来放在一个{}中,并为这段代码起个名字,这样在每次发射炮弹的地方通过这个名字来调用发射炮弹的代码就可以了。上述过程中,所提取出来的代码可以被看作是程序中定义的一个方法,程序在需要发射炮弹时调用该方法即可。
对于一些复杂的代码逻辑,如果希望重复使用这些代码,并且做到“随时任意使用”,那么就可以将这些代码放在一个大括号“{}”当中,并且起一个名字。使用代码的时候,直接找到名字调用即可。
方法就是完成特定功能的代码块
在很多语言中都有方法的定义,在其他语言当中也可能被称为“函数”,但是在咱们JAVA语言中,我们将其称之为“方法”。
修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2 ....){
方法体;
return 返回值;
}
方法的格式详细说明
(1)修饰符: 比较多,后面会详细介绍。目前使用 public static
(2)返回值类型: 用于限定返回值的数据类型
(3)方法名: 就是一个名称,它的存在是为了方便我们调用方法
(4)参数类型: 限定调用方法时传入参数的数据类型
(5)参数名: 是一个变量,接收调用方法时传入的参数
这里的参数其实有一个专业的名词,被称之为形式参数,它的作用是用来接收实际参数的。
(6)方法体: 完成功能的代码
(7)return: 结束方法以及返回方法指定类型的值
(8)返回值: 就是功能的结果,由return带回,带回给调用者
案例演示
1.
public class Demo {
//主方法,是一个程序的入口。主方法是JVM来调用的,一个类中只能有一个主方法!
public static void main(String[] args) {
System.out.println("这是main方法");
//直接调用我们自己定义的方法
hello();//(1)
}
//方法:就是对一段功能逻辑的封装,以实现重复调用。
//1.方法定义在类中,方法跟方法是平级关系,不能嵌套定义
//2.方法不调用不执行
//void 表示无明确返回值类型
public static void hello(){
//方法体,你具体要实现的功能
System.out.println("Hello world!");
}
}
2.求两个数据之和
public class Demo {
public static void main(String[] args) {
//当我们去调用一个有参数的方法时,必须传入与之相对应的实际参数,简称实参(参数个数要对应,数据类型要对应)
//传常量,变量都可以
int s= add(1,2);//(2)
int aa=10;
int bb=90;
int r =add(aa,bb);
System.out.println(s);
System.out.println(r);
//如果一个方法有返回值,我们可以直接输出调用,打印返回的结果
System.out.println(add(3,4));//(3)
}
//定义方法括号里面的参数,叫做形式参数,简称形参。
//形参的作用是,调用方法时,接收传过来的实参
//多个形参用逗号隔开
//一个方法一旦明确了返回值类型,必须由return带回一个与明确的类型一致的结果
//如果一个方法的返回值类型是void,那么这个return可以省略
public static int add(int a,int b) {
int sum=a+b;
return sum;//return 结束方法,并带回一个结果
}
}
3.获取两个数中的较大值
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入第一个数");
int x = sc.nextInt();
System.out.println("请输入第二个数");
int y = sc.nextInt();
int m = getMax(x,y);
System.out.println("两数较大值为:"+m);
}
public static int getMax(int a,int b){
int max=a>b?a:b;
return max;
}
}
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入第一个数");
int x = sc.nextInt();
System.out.println("请输入第二个数");
int y = sc.nextInt();
boolean flag=isEqual(x,y);
if(flag){
System.out.println("相等");
}
else{
System.out.println("不相等");
}
}
public static boolean isEqual(int a,int b){
if(a==b){
return true;
}
else{
return false;
}
}
}
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数字");
int x = sc.nextInt();
printTable(x);
}
public static void printTable(int a){
for(int i=1;i<=a;i++){
for(int j=1;j<=i;j++){
System.out.print(i+"x"+j+"="+i*j+" ");
}
System.out.println();
}
}
}
如何写一个方法
两个明确
1.返回值类型 明确功能结果的数据类型
2.参数列表 你要传递几个参数,以及每一个参数的数据类型
方法调用(有明确返回值的调用)
a:单独调用:例如上文(1)处,一般来说没有意义,所以不推荐。
b:赋值调用:例如上文(2)处,推荐方案,能获取到方法的返回值。
c:输出调用:例如上文(3)处,不够好,因为我们可能需要针对结果进行进一步的操作。
注意事项
1.方法不调用不执行
2.方法与方法是平级关系,不能嵌套定义
3.方法定义的时候参数之间用逗号隔开
4.方法调用的时候不用再传递数据类型
5.如果方法有明确的返回值,一定要由return带回一个值
方法重载概述
在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表其中之一不同,就构成重载,与返回值类型无关。
参数列表不同即:
(1)参数个数不同
(2)参数类型不同
注意:仅仅是方法的返回值类型不同不构成重载。
public class Demo {
public static void main(String[] args) {
//调用add方法的时候,会根据参数个数和参数类型去匹配是哪一个add方法
int s1=add(1,2);
double s2=add(1,4.5);
int s3=add(4,5,6);
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}
//下面的三个add方法同名但不报错,这是利用了方法重载
public static int add(int a,int b){
return a+b;
}
/*方法重载:允许一个类中,可以出现多个同名方法,
只要他们的参数个数不同,或者参数类型不同,
就构成重载,不拿返回值类型来区分
*/
public static double add(int a,double b){
return a+b;
}
public static int add(int a,int b,int c){
return a+b+c;
}
}
数组是存储同一种数据类型多个元素的集合。也可以看成是一个容器。
数组既可以存储基本数据类型,也可以存储引用数据类型(后篇讲解)。
格式1: 数据类型[] 数组名;
格式2: 数据类型 数组名[];
举例:
int[] a;
定义了一个int类型的数组a;
int a[];
定义了一个int类型的a数组;
推荐使用第一种定义方式。
Java中的数组必须先初始化,然后才能使用。
所谓初始化,就是为数组中的数组元素分配内存空间,并为每个数组元素赋值。
(1)动态初始化: 只指定长度,由系统给出初始化值
(2)静态初始化: 给出初始化值,由系统决定长度
注意事项: 这两种方式,只能使用一种,不能进行“动静结合”
数据类型[] 数组名 = new 数据类型[数组长度];
数组长度其实就是数组中元素的个数。
举例: int[] arr = new int[3];
定义了一个int类型的数组arr,这个数组可以存放3个int类型的值。
案例演示
public class ArrayDemo {
public static void main(String[] args) {
//数组:用来存储一组相同数据类型的数据。
//数组的定义语法
//方式1:动态初始化:动态的定义方式,由我们规定数组的长度,由系统赋默认值
//创建一个int类型的数组
//当我们创建好了数组后,系统会给分配索引(角标)从0开始
int[] arr=new int[3];
//往数组中放入数据 通过数组的索引往里面存数据
arr[0]=10;
arr[1]=20;
//取数组中的元素
int num=arr[0];
System.out.println(num);
System.out.println(arr[1]);
System.out.println(arr[2]);//默认值
System.out.println(arr);//存放数组arr的空间的地址
boolean[] arr1=new boolean[2];
arr1[0]=true;
System.out.println(arr1[0]);
System.out.println(arr1[1]);//默认值
}
}
(1)栈: 存放的是局部变量
局部变量:在方法定义中或者方法声明上的变量都是局部变量。
(2)堆: 存放的是所有new出来的东西
特点:
(3)方法区:(后篇讲解)
(4)本地方法区:(和系统相关)
(5)寄存器:(cpu使用)
案例演示
/*栈内存(存局部变量),堆内存(存每个new出来的数据,
并为他分配内存地址,以及给数据赋初始化值),
方法区(加载.class文件先到方法区),本地方法区(与系统相关),
寄存器(CPU使用)
*/
public class ArrayDemo {
public static void main(String[] args) {
int[] arr = new int[3];
arr[0] = 10;
arr[1] = 20;
int num = arr[0];
int num2 = arr[2];
System.out.println(num);
System.out.println(num2);
}
}
内存解析:
首先,程序编译好后生成了字节码文件(.class文件),JVM将字节码文件加载进方法区,而main方法是程序的入口,需要被执行,于是调用main方法进栈执行。接着,执行第一句代码,创建了一个长度为3的int型数组,于是堆内存为该数组开辟空间(每new一次都会在堆内存重新开辟空间),并为3个元素都初始化为0,内存空间地址为0x12345678(此处随意写的一个地址);开辟完空间以后将该地址赋给arr这个数组的引用,于是名为arr的这个数组便指向了地址为0x12345678的空间。然后执行第二句代码,先找到arr引用指向的空间,再通过下标索引0找到该元素,给该元素赋值为10,覆盖了先前的初始值0,第三句代码同理。然后后面的代码便是将数组元素赋给变量并输出。至此,main方法执行完毕,main方法弹栈,即从栈中弹走。此时就没有引用指向堆内存中地址为0x12345678的空间了,于是最后垃圾回收器回收了该空间,释放内存。
练习
int[] arr1 = new int[3];
arr1[0]=10;
arr1[2]=200;
int[] arr2 = new int[3];
arr2[0]=11;
arr2[1]=19;
int[] arr3=arr1;
arr3[0]=108;
arr3[1]=106;
arr1[1]=177;
现在,三个数组的元素值分别是多少?
答案
int[] arr3=arr1;
arr3指向存放数组arr1的空间地址,因此对arr3的元素进行赋值,同时也会覆盖掉arr1的元素值。
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…};
举例: int[] arr = new int[]{1,2,3};
简化格式:
数据类型[] 数组名 = {元素1,元素2,…};
举例: int[] arr = {1,2,3};
案例演示
public class ArrayDemo {
public static void main(String[] args) {
//数组静态初始化:由我们赋值,由系统计算长度
//数组一旦定义好,长度就固定了
int[] arr = new int[]{10, 20, 30};
boolean[] arr2 = new boolean[]{true, false, true, true};
char[] arr3 = new char[]{'a', 100, 'b'};
byte[] bytes = new byte[]{127, 100, 0, -128};
long[] longs = new long[]{1L, 100L};
float[] floats = new float[]{1F, 2.9F};
//静态初始化的简写方式
int[] arr6 = {10, 20, 30};
//数组有一个长度属性
int length = arr.length;
System.out.println(length);
int length1 = arr2.length;
System.out.println(length1);
// 数组中最后一个元素的索引=数组长度-1;
int num=bytes[bytes.length-1];
System.out.println(num);
}
}
案例演示
1.
public class Demo {
public static void main(String[] args) {
int[] a=new int[]{1,2,3};
System.out.println(a[3]);
}
}
public class Demo2 {
public static void main(String[] args) {
int[] arr = new int[]{10, 20};
arr = null;// 人为置空
int length = arr.length;
System.out.println(length);
}
}
1.ArrayIndexOutOfBoundsException:数组索引越界异常
原因:你访问了不存在的索引。
2.NullPointerException:空指针异常
原因:数组创建失败或在数组被访问前被人为置空,即数组已经不再指向堆内存了。
public class ArrayDemo {
public static void main(String[] args) {
int[] arr={1,20,5,3,25};
//数组的遍历
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println("---------------------------");
//反向遍历
for(int i=arr.length-1;i>=0;i--){
System.out.println(arr[i]);
}
}
}
public class ArrayDemo2 {
public static void main(String[] args) {
//获取数组中的最大值或最小值
int[] arr = {10, 30, 5, 40, 12};
int max = getMax(arr);
System.out.println("最大值是" + max);
int min = getMin(arr);
System.out.println("最小值是" + min);
}
public static int getMax(int[] arr){
//定义一个参照值
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
public static int getMin(int[] arr){
int min=arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i]<min){
min = arr[i];
}
}
return min;
}
}
方法1
public class ArrayDemo3 {
public static void main(String[] args) {
//数组元素反转(就是把元素对调)
int[] arr = {10, 20, 30, 40, 50};
for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
public class ArrayDemo3 {
public static void main(String[] args) {
//数组元素反转(就是把元素对调)
int[] arr = {10, 20, 30, 40, 50};
//首尾交换,遍历一半
for (int i = 0; i < arr.length / 2; i++) {
//采用中间变量进行值交换
int t = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = t;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
根据键盘录入索引, 查找对应星期
public class ArrayDemo{
public static void main(String[] args) {
//数组查表法(根据键盘录入索引, 查找对应星期)
//根据索引查元素
String[] arr = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"};
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个整数 1----7");
int index = scanner.nextInt();
String str = getElementByArray(index, arr);
System.out.println(str);
}
public static String getElementByArray(int index, String[] arr) {
if (index >= 1 && index <= 7) {
return arr[index - 1];
} else {
return "查无此元素";
}
}
}
根据键盘录入星期, 查找对应索引
public class ArrayDemo{
public static void main(String[] args) {
//根据元素查索引
String[] arr = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"};
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个星期");
String str = scanner.nextLine();//获取用户输入的字符串
int index = getIndex(str, arr);
System.out.println("该元素的索引是" + index);
}
public static int getIndex(String str, String[] arr) {
//遍历数组
for (int i = 0; i < arr.length; i++) {
if (str.equals(arr[i])) { //字符串的比较不能用等于号
return i;
}
}
return -1; // 一般用-1 代表查找失败
}
}