一、语言基础---4.方法和数组
(一)方法设计
循环操作:解决的是代码重复的问题,用来处理重复做某一件事情。此时的重复:有规律,语句格式是相同的,有规律的
循环操作能解决所有的重复吗?
针对某一种功能的重复操作,循环解决不了,此时得使用方法
078、方法定义和基本调用操作
方法(method),函数(function):指一个特定的功能操作,程序中完成独立功能,可重复使用的一段代码的集合;
方法定义格式:
[修饰符] 方法的返回值类型 方法名称([形式参数1,形式参数2,...])
{
方法体;
[return 值]; //方法需要给调用者返回一个结果
}
方法必须要调用才能生效(看着菜单点菜),main方法专门由JVM来负责调用,我们只管启动JVM
如果方法使用了static修饰:此时使用方法所在类的名称.方法名(参数);
如果方法没有使用了static修饰:此时使用方法所在类的对象来调用(面向对象)
方法定义的位置:
1)在类中定义,在Java中最小的程序单元是类
2)方法定义在其他方法之外,方法和方法是兄弟关系
3)方法定义的先后顺序不影响
//方法的定义和调用
public class MethodDemo
{
//把共同的200行代码,抽离到方法中
static void doWork()
{
System.out.println("共同的200行代码");
}
public static void main(String[] args) //主方法
{
System.out.println("代码片段A");
MethodDemo.doWork(); //调用方法
System.out.println("代码片段B");
MethodDemo.doWork(); //调用方法
System.out.println("代码片段C");
MethodDemo.doWork(); //调用方法
System.out.println("代码片段D");
}
}
079、方法中的专业术语
修饰符:public,static等,决定了方法的访问权限。static表示方法属于类,直接使用类名调用即可,现在都使用static修饰
返回值类型:方法其实是完成一个功能。该功能操作完毕之后,是否需要给调用者返回一个结果(过程/结果)
如果不需要给调用者返回结果,使用关键字void来声明,无返回的意思
方法名称:遵循标识符的规范。使用动词短语表示,首字母小写,若是多个单词组成,使用驼峰表示,例如:doWork
形式参数:方法圆括号中的变量,仅仅只是占位而已。参数的名称其实无所谓,形式参数可以有多个
参数列表:参数列表==参数类型+参数个数+参数顺序
方法签名:方法签名==方法名称+方法参数列表。在同一个类中,方法签名是唯一的
方法体:方法{}中的代码,表示具体完成该功能的代码
返回值:在方法内部,使用return关键字。功能1:给调用者返回一个结果,此时该方法不能使用void修饰;功能2:结束当前方法
实际参数:调用者在调用某一个具体方法的时候,实际传递的参数值
方法的调用者:在哪里调用某一个方法,那么哪里就是该方法的调用者
080、如何定义/设计方法
如何定义方法:
1)到底要定义什么功能方法,刚开始不要太纠结,慢慢来
2)是否需要定义返回值类型?
方法其实就是在完成某一个功能, 那么完成该功能之后,是否需要给调用者返回一个结果数据,如果不需要返回结果数据,此时使用void声明(无返回)
如果需要返回一个结果数据,就把该结果数据的类型作为该方法的返回值类型
打印操作:在乎的是方法执行的过程,而不是结果,所以此时使用void声明
求两个数之和:此时在乎的是方法执行的过程,并且执行完毕之后,需要给调用者一个反馈
3)是否需要形式参数?
该方法在完成该功能的过程中,是否有未知的因素参与,如果有请作为参数传递,如果没有则没有形参
求两个数之和:这两个数到底是多少,对于方法来说是未知的,仅仅是调用者知道,而且不同的调用者传递不同的参数值
针对于有返回值的方法,调用者应该定义一个变量去接收返回的结果。
//方法的定义和调用
public class MethodDemo2
{
//a无参数无返回
//需求:定义一个方法,专门打印-------
static void p()
{
System.out.println("------------");
}
//b有参数无返回
//需求:定义一个方法,打印任意值
static void pValue(String val)
{
System.out.println(val);
}
//c无参数有返回
//需求:返回年龄(17)
static int getAge()
{
return 17;
}
//d有参数有返回
//需求:求两个数之和
static int getSum(int a, int b)
{
return a + b;
}
public static void main(String[] args)
{
MethodDemo2.p(); //调用方法
MethodDemo2.pValue("123"); //调用pValue方法,传递123字符串
int age = MethodDemo2.getAge(); //定义age变量,接收getAge方法返回结果
System.out.println(age);
int sum = MethodDemo2.getSum(1 , 2); //定义sum变量,接收getSum方法返回结果
System.out.println(sum);
}
}
081、方法的执行流程分析
082、方法设计练习(发短信和登录)
083、方法重载设计
重载方法(overload):在同一个类中,某方法允许存在一个以上的同名方法,只要他们的参数列表不同即可
作用:屏蔽了同一功能的方法由于参数不同所造成方法名称不同的差异
原则:两同一不同。同类中,方法名相同;方法参数列表不同(参数类型、参数个数、参数顺序)
注意:重载方法和方法的返回值类型无关,只是一般要求返回值类型一致
参数列表和参数名称没有关系,方法的重载和形参没有关系
//方法的定义和调用
// 方法重载
public class OverLoadDemo
{
//求两个整数之和
static int getSum(int x, int y)
{
return x + y;
}
//求两个小数之和
static double getSum(double x, double y)
{
return x + y;
}
//打印string
static void p(String data)
{
System.out.println(data);
}
//打印int
static void p(int data)
{
System.out.println(data);
}
static void p()
{
}
public static void main(String[] args)
{
OverLoadDemo.getSum(1 , 2); //调用getSum(int x, int y)
OverLoadDemo.getSum(1.0 , 2.0); //调用getSum(double x, double y)
OverLoadDemo.p(123);
OverLoadDemo.p("asd");
}
}
084、方法重载在JDK中的使用
同一个类中,不能存在两个相同的方法
085、方法的递归操作
自己调用自己
//递归操作
public class RecursionDemo
{
public static void main(String[] args)
{
int ret = fn(5);
System.out.println(ret);
}
//斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*)
static int fn(int n)
{
if (n == 0)
{
return 0;
}
else if(n == 1)
{
return 1;
}
else
{
return fn(n - 1) + fn(n - 2);
}
}
}
(二)JVM内存模型
086、JVM内存模型
JVM内存划分,人为的根据不同内存空间的存储特点以及存储的数据
1)程序计数器:当前线程所执行的字节码的行号指示器
2)本地方法栈:为虚拟机使用的native方法事务
3)Java虚拟机栈(Stack):描述Java方法执行的内存模型,每个方法被执行的时候都会同时创建一个栈帧用于存储局部变量表、操作栈、动态链接、方法出口等信息(last in,first out)
每一个方法,创建一个栈帧,栈帧存放了当前方法的数据信息(局部变量),当方法调用完毕,该方法的栈帧就被销毁了
4)Java堆(Heap):被所有线程共享的一块内存区域,在虚拟机启动时创建。所有对象实例以及数组都要在堆上分配(使用new关键字,就表示在堆中开辟一块新的存储空间)
5)方法区:线程共享的内存区域,存储已被虚拟机加载的类信息、常量、静态变量即时编译器编译后的代码数据等(这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载)
GC(Garbage Collection):垃圾回收器。Java的自动垃圾回收机制:当JVM发现内存资源紧张的时候,就会自动地去清理无用对象(没有被应用到的对象)所占用的内存空间。
(Java的自动垃圾回收器,自动回收的是堆空间的内存;而栈空间内存会随着该方法的执行结束,自动释放该方法的栈帧内存)
(三)一维数组
087、引出数组和数组的定义
数组:一组(堆)数据。所谓数组,是在程序设计中,为了方便处理,把具有相同类型的若干变量按有序的形式组织起来的一种数据形式。按一定顺序排列的同类型数据的集合称为数组。
数组中的每一个数据称为数组元素,数组中的元素以索引来表示其存放的位置,索引从0开始,步长是1,逐行递增。
数据类型:基本数据类型(byte、short、int、long、float、double、char、blooean)和引用数据类型(类、接口、数组)
变量的定义:数据类型 变量名;如:int age;
数组的定义:
方式1:数组元素的类型[] 数组名; 如:int [] ages;
方式2:数组元素的类型 数组名[]; 如:int ages[];
数组必须先初始化才能使用,因为初始化表示在内存中分配空间
//数组的定义
public class ArrayDemo
{
public static void main(String[] args) //args:参数(arguments)
{
//表示一个变量
int age;
//表示全班同学的年龄
int[] ages1; //推荐,把int[]看成是一种int类型的数组类型
int ages2[];
//System.out.println(ages1); //ArrayDemo.java:12: 错误: 可能尚未初始化变量ages1
}
}
088、数组的静态初始化和内存分析
Java中数组必须初始化后才能使用,所谓初始化就是给数组元素分配内存,并为每个元素赋初始值
初始化数组,不论哪种初始化,一旦初始化完成,数组的长度就固定了,不能改变,除非重新初始化(数组是定长的(数组元素的个数固定))
1)数组的静态初始化:为每一个数组元素设置初始值,而数组的长度由系统(JVM)分配
//数组的初始化
public class ArrayInitDemo
{
public static void main(String[] args) //args:参数(arguments)
{
//语法:数组元素类型[] 数组名 = new 数组元素类型[] {元素1,元素2, 元素3,......};
int[] nums = new int[]{1,3,5,7,9};
//简单写法:int[] nums = {1,3,5,7,9};必须声明之后,立即初始化,不能先声明后初始化
System.out.println(nums.length); //5 打印出数组的长度
nums = new int[] {2,4,8};
System.out.println(nums.length); //3
}
}
内存分析:
2)数组的动态初始化:设置数组的元素个数(数组长度),而每一个数组元素的初始值由系统决定
//数组的初始化
public class ArrayInitDemo2
{
public static void main(String[] args) //args:参数(arguments)
{
//语法:数组元素类型[] 数组名 = new 数组元素类型[length];
int[] nums = new int[3];
System.out.println(nums.length); // 3
nums = new int[5];
System.out.println(nums.length); // 5
}
}
不能同时使用静态初始化和动态初始化
什么时候使用静态初始化?什么时候使用动态初始化?
当事先知道需要存储哪一些数据的时候,选用静态初始化;事先不知道需要存储哪一些数据的时候,选用动态初始化
090、获取、设置、遍历数组元素
数组的基本操作:
1.获取元素:元素类型 变量 = 数组名[index]
2.设置元素:数组名[index] = 值;
3.遍历数组元素:建议使用for循环,事先知道循环的次数
4.数组长度:数组名.length; length是属性,不是方法
5.索引范围:从0开始,逐一递增。 [0,数组名.length]
//数组的操作
public class ArrayOperateDemo
{
public static void main(String[] args) //args:参数(arguments)
{
int[] nums = new int[]{1,3,5,7,9};
System.out.println("数组的长度=" + nums.length); //数组的长度=5
System.out.println("数组的第一个元素=" + nums[0]); //数组的第一个元素=1
System.out.println("数组的最后一个元素=" + nums[4]); //数组的最后一个元素=9
nums[0] = 100; //修改nums数组的第一个元素
System.out.println("数组的第一个元素=" + nums[0]); //数组的第一个元素=100
//遍历数组元素
for (int index = 0; index < nums.length ; index ++ )
{
System.out.println(nums[index]); //100/3/5/7/9
}
boolean[] bs = new boolean[3];
for (int index = 0; index < bs.length ; index ++ )
{
System.out.println(bs[index]); //false/false/false
}
String[] str = new String[3];
for (int index = 0; index < bs.length ; index ++ )
{
System.out.println(str[index]); //null/null/null
}
double[] db = new double[3];
for (int index = 0; index < db.length ; index ++ )
{
System.out.println(db[index]); //0.0/0.0/0.0
}
}
}
091、操作数组的常见异常
1. NullPointerException:空指针异常(空引用)。当数组还没有初始化,就直接操作数组
2.ArrayIndexOutOfBoundsException:数组索引越界异常
//数组的常见异常
public class ArrayExceptionDemo
{
public static void main(String[] args) //args:参数(arguments)
{
//空指针异常
int[] nums = null;
//System.out.println(nums.length); // Exception in thread "main" java.lang.NullPointerException
nums = new int[] {2,4,8};
System.out.println(nums[1]); //4
//数组索引越界异常
System.out.println(nums[5]); //Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
}
}
092、获取数组中的最大和最小元素
//数组的操作
public class ArrayOperateDemo2
{
//获取数组最大元素
static int getMax(int[] nums)
{
int max = nums[0]; //假设第一个元素是最大值
for (int index = 1; index < nums.length ; index ++ )
{
if (nums[index] >max)
{
max = nums[index]; //把最大值存储在max变量里
}
}
return max;
}
//获取数组最小元素
static int getMin(int[] nums)
{
int min = nums[0]; //假设第一个元素是最小值
for (int index = 1; index < nums.length ; index ++ )
{
if (nums[index] < min)
{
min = nums[index]; //把最小值存储在min变量里
}
}
return min;
}
public static void main(String[] args) //args:参数(arguments)
{
int[] nums = new int[]{-3,5,0,2,1,10};
int max = ArrayOperateDemo2.getMax(nums);
System.out.println(max); //10
System.out.println(ArrayOperateDemo2.getMin(nums)); //-3
}
}
093、按格式打印数组元素
直接打印数组,打印出来的是hashcode。如数组{-3,5,0,2,1,10}打印结果为:[I@1db9742
//数组的操作
public class ArrayPrintDemo
{
public static void main(String[] args) //args:参数(arguments)
{
String[] nums = new String[]{"-3","5","0","2","1","10"};
System.out.println(nums); //[Ljava.lang.String;@1db9742
ArrayPrintDemo.printArray(nums); //[-3,5,0,2,1,10]
}
static void printArray(String[] arr)
{
if (arr == null)
{
System.out.println("null");
return; //结束方法
}
String ret = "[";
for (int index = 0; index < arr.length ; index ++ )
{
ret = ret + arr[index];
if (index != arr.length - 1) //如果当前index不是最后一个索引,则拼接“,”
{
ret = ret + ",";
}
}
ret = ret +"]";
System.out.println(ret);
}
}
094、逆序排列数组元素
//数组的逆序排序
public class ArrayReverseDemo
{
public static void main(String[] args) //args:参数(arguments)
{
String[] arr = {"A","B","C","D","E","F"};
ArrayReverseDemo.reverse(arr); //调用逆序方法
String[] newArr = ArrayReverseDemo.reverse(arr);
ArrayReverseDemo.printArray(newArr);
}
static void printArray(String[] arr)
{
if (arr == null)
{
System.out.println("null");
return; //结束方法
}
String ret = "[";
for (int index = 0; index < arr.length ; index ++ )
{
ret = ret + arr[index];
if (index != arr.length - 1) //如果当前index不是最后一个索引,则拼接“,”
{
ret = ret + ",";
}
}
ret = ret +"]";
System.out.println(ret);
}
static String[] reverse(String[] oldArr)
{
//创建一个新的数组,存放逆序之后的元素
String[] newArray = new String[oldArr.length];
for (int index = oldArr.length - 1; index >=0 ; index -- )
{
newArray[oldArr.length - 1 - index] = oldArr[index];
}
return newArray;
}
}
095、元素出现索引(线性搜索)
//元素出现索引
public class ArraySearchDemo
{
/*
int[] arr = {10,20,30,10,50,30,10};
获取元素10在arr数组中第一次出现的索引(indexOf); //0 从前往后找,第一个
获取元素10在arr数组中最后一次出现的索引(lastIndexOf); //6 从后往前找,第一个
*/
public static void main(String[] args)
{
int[] arr = {10,20,30,10,50,30,10};
int beginIndex = ArraySearchDemo.indexOf(arr, 10);
System.out.println(beginIndex); //0
System.out.println(ArraySearchDemo.lastIndexOf(arr, 10)); //6
}
/*查询key元素在arr数组中第一次出现的位置
参数:
arr:从哪一个数组中去做查询
key:当前去查询的元素
返回:如果key存在与arr数组中,则返回第一次出现的索引。key不存在于arr数组中,则返回-1
*/
static int indexOf(int[] arr, int key)
{
for (int index = 0; index < arr.length; index ++ )
{
if(arr[index] == key);
{
return index;
}
}
return -1;
}
//判断key在arr数组中最后出现的次数
static int lastIndexOf(int[] arr, int key)
{
for (int index = arr.length -1; index >= 0 ; index -- ) //先找最后一个元素,一直进行减减操作
{
if(arr[index] == key);
{
return index;
}
}
return -1;
}
}