------- android培训、java培训、java学习型技术博客、期待与您交流! ----------
第一讲 程序的流程控制
简述
控制流程(也称为流程控制)是计算机运算领域的用语,意指在程序运行时,个别的指令(或是陈述、子程序)运行或求值的顺序。不论是在声明式编程语言或是函数编程语言中,都有类似的概念。在声明式的编程语言中,流程控制指令是指会改变程序运行顺序的指令,可能是运行不同位置的指令,或是在二段(或多段)程序中选择一个运行。
1.判断结构 if语句
- if语句的三种格式
- if(true){ 执行语句 ;}
- if(条件表达式){执行语句;} else{执行语句;}
- if(条件表达式){执行语句;} else if(条件表达式){执行语句;}.... else{执行语句;}
- if语句的特点
- 每一种格式都是单条语句。
- 第二种格式与三元运算符的区别:三元运算符运算完要有值出现。好处是:可以写在其他表达式中。
- 条件表达式无论写成什么样子,只看最终的结构是否是true 或者 false;
- 每一种格式都是单条语句。
- 格式
switch(表达式)
{
case 取值1:
执行语句;
break;
case 取值2:
执行语句;
break;
…...
default:
执行语句;
break;
}
- 原理
- 用小括号中的变量的值依次和case后面的值进行对比,和哪个case后面的值相同了,就执行哪个case后面的语句,如果没有相同的则执行default后面的语句;
- 特点
- switch语句选择的类型只有四种:byte,short,int ,char。
- case之间与default没有顺序。先执行第一个case,没有匹配的case执行default。
- 如果将default语句放在了第一行,则不管expression与case中的value是否匹配,程序会从default开始执行直到第一个break出现。
- 结束switch语句的两种情况:遇到break,执行到switch语句结束。
- 如果匹配的case或者default没有对应的break,那么程序会继续向下执行,运行可以执行的语句,直到遇到break或者switch结尾结束。
- switch语句选择的类型只有四种:byte,short,int ,char。
3.循环结构 代表语句 for while do-while
- for循环
- 格式
for(初始化表达式;循环条件表达式;循环后的操作表达式)
{
执行语句;(循环体)
}
- 特点
- for里面的两个表达式运行的顺序,初始化表达式只读一次,判断循环条件,为真就执行循环体,然后再执行循环后的操作表达式,接着继续判断循环条件,重复找个过程,直到条件不满足为止。
- 特点
- 示例
for(int i = 0;i < 3;i++)
{
System.out.println(i);
}
- while循环
- 格式
while(条件表达式)
{
执行语句;
}
- 特点
- 先进行条件判断,再执行循环体。如果条件不成立,退出循环。
- 特点
- 示例
int x = 3;
while(x<5)
{
x++;
System.out.println(x);
}
- do-while循环
- 格式
do
{
执行语句;
}while(条件表达式);
- 特点
- 先执行循环体,再进行条件判断,循环体至少执行一次。
- 特点
4.其他语句 break continue语句
- break语句
- 作用:用于switch ,和循环语句,用于跳出,或者称为结束。
- 注意:break语句单独存在时,下面不要定义其他语句,因为执行不到,编译会失败。当循环嵌套时,break只跳出当前所在循环。要跳出嵌套中的外部循环,只要给循环起名字即可,这个名字称之为标号。
- continue语句
- 作用:只作用于循环结构,继续循环用的。结束本次循环,继续下次循环。
- 注意:该语句单独存在时,下面不可以定义语句,执行不到。
- 当判断固定个数的值的时候,可以使用if,也可以使用switch。
- 但是建议使用switch,效率相对较高。
- 当判断数据范围,获取判断运算结果boolean类型时,需要用if。
- 当某些语句需要执行很多次,就用循环结构。
- while和for可以进行互换。区别在于:如果需要定义变量控制循环次数,建议使用for。因为for循环完毕,变量在内存中释放。
第二讲 函数
简述
为了提高代码的复用性,可以将其定义成一个单独的功能,该功能的体现就是java中的函数。函数就是体现之一。
- Java中函数的定义格式
修饰符 返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数1,…){
执行语句;
return 返回值;
}
- 当函数没有具体的返回值时,返回的返回值类型用void关键字表示。
- 如果函数的返回值类型是void时,return语句可以省略不写的,系统会帮你自动加上。
- return的作用:结束函数。结束功能。
- 如何定义一个函数,函数其实就是一个功能,定义函数就是实现功能,通过两个明确来完成:
- 明确该功能的运算完的结果,其实是在明确这个函数的返回值类型。
- 在实现该功能的过程中是否有未知内容参与了运算,其实就是在明确这个函数的参数列表(参数类型&参数个数)。
- 函数的作用:
- 用于定义功能。
- 用于封装代码提高代码的复用性。
- 函数的特点:
- 函数只有被调用才会被执行。
- 对于函数没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的return语句如果在最后一行可以省略不写。
- 注意:函数中只能调用函数,不能定义函数。
- 主函数:
- 保证该类的独立运行。
- 因为它是程序的入口。
- 因为它在被jvm调用。
- 函数定义名称是为什么
- 为了对该功能进行标示,方便于调用。
- 为了通过名称就可以明确函数的功能,为了增加代码的阅读性。
- 函数的重载(overload)
- 概念:在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不同即可。
- 特点:与返回值类型无关,只看参数列表。
- 好处:方便于阅读,优化了程序设计。
- 示例:
/返回两个整数的和
int add(int x,int y){return x+y;}
//返回三个整数的和
int add(int x,int y,int z){return x+y+z;}
//返回两个小数的和
double add(double x,double y){return x+y;}
- 好处:可以对该容器中的数据进行编号,从0开始。数组用于封装数据,就是一个具体的实体。
- 数组的声明:
- type varName[]; 或 type[] varName;(推荐)
- 数组的初始化:
- 动态初始化:初始化时由我们指定数组的长度,由系统为数组元素分配初始值。
- 格式:元素类型[] 变量名 = new 元素类型[元素的个数];
- 示例:int[] arr = new int[5];
- 格式:元素类型[] 变量名 = new 元素类型[元素的个数];
- 静态初始化:初始化时由我们自己指定每个数组元素的初始值,由系统决定需要的数组长度。
- 格式:
- 元素类型[] 变量名 = {元素1,元素2...};
- 元素类型[] 变量名 = new 元素类型[]{元素1,元素2...};
- 示例:int[] arr = {4,5,9,7}; int[] arr = new int[]{2,5,1,7};
- 格式:
- 动态初始化:初始化时由我们指定数组的长度,由系统为数组元素分配初始值。
- 特点:
- 数组必先初始化才可以使用。
- 数组是固定长度的。
- 数组可以存储基本数据类型,也可以存储引用数据类型。
- 数组存储的元素必须是同一个数据类型。
- 二维数组
- 其实是一个一维数组,它的每一个元素又是一个一维数组。
- 声明:
- type varName[][]; 或 type[][] varName;(推荐)
- 动态初始化:
- int[ ][ ] arr = newint[2][3];
- 静态初始化:
- int[ ][ ] arr = new int[][]{{1,2},{3,4},{5,6}};
- int[ ][ ] arr ={{1,2},{3,4},{5,6}};
- int[ ][ ] arr = new int[][]{{1,2},{3,4},{5,6}};
内存结构
Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,有对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
- 栈内存
- 用于存储局部变量,当数据使用完,所占空间会自动释放。
- 堆内存
- 数组和对象,通过new建立的实例都存放在堆内存中。
- 每一个实体都有内存地址值。
- 实体中的变量都有默认初始化值。
- 实体不在被使用,会在不确定的时间内被垃圾回收器回收。
- 方法区,本地方法区,寄存器
- 一维数组内存结构
- 二维数组内存结构
- 数组操作常见问题
- 数组脚标越界异常(ArrayIndexOutOfBoundsException)
int[] arr = new int[2];System.out.println(arr[3]);
访问到了数组中的不存在的脚标时发生。
- 空指针异常(NullPointerException)
int[] arr = null;
System.out.println(arr[0]);
arr引用没有指向实体,却在操作实体中的元素时。
数组的常见操作
- 获取最值(最大值、最小值)
- 这里简单写下获取最大值
public class ArrayTest { public static void main(String[] args) { // TODO Auto-generated method stub int [] arr = {4,6,8,3,18,9,17}; System.out.println(getMax(arr)); System.out.println(getMax_2(arr)); } //获取数组中最大值 /* * 思路: * 1,获取最值需要进行比较,每一次比较都会有一个较大的值,因为值不确定, * 通过一个变量进行存储。 * 2,让数组中的每一个元素都和这个变量的值进行比较。 * 如果大于了变量中的值,就用该变量记录较大值。 * 3,当所有的元素都比较完成,那么该变量中存储的就是数组中的最大值。 * * 步骤: * * 1,定义变量,初始化为数组中任意一个元素即可。 * 2,通过循环语句对数组进行遍历。 * 3,在遍历过程中定义判断条件,如果遍历到的元素比变量中的元素大, * 就赋值给该变量。 * * 需要定义一个功能来完成,以便提高复用性。 *1,明确结果,数组中的最大元素 int... *2,位置内容:一个数组 int[] * */ public static int getMax(int[] arr) { int max = arr[0]; for(int x = 1 ; x< arr.length;x++) { if(arr[x] > max) { max = arr[x]; } } return max; } public static int getMax_2(int[] arr) { int max = 0; for(int x = 1 ; x< arr.length;x++) { if(arr[x] > arr[max]) { max =x; } } return arr[max]; } }
- 排序(选择排序,冒泡排序)
- 选择排序
- 原理:先用0角标上的元素依次与其他元素进行比较,将较小值元素存放到0角标。然后再拿1角标上的元素依次进行比较,以此类推。
- 特点:内循环结束一次,最值出现在头角标位置上。
- 原理图解:
- 选择排序
- 冒泡排序
- 原理:
- 先从头角标相邻两个元素之间进行比较,将最值存放在后一个元素中,然后再与后一个元素的进行比较,直至最值存放到最后一个元素中。再从1角标开始再重复以上操作,每次计较次数减一,一圈比完后存放的最值元素不再参与比较。
- 特点:内循环结束一次,最值出现在尾角标位置上。
- 原理图解:
- 原理:
- 冒泡排序
- 排序小练习
public class ArrayTest { public static void main(String[] args) { // TODO Auto-generated method stub int [] arr1 = {4,6,8,3,9,17}; selectSort(arr1); printArray(arr1); int [] arr2 = {10,7,8,5,9,6}; bubbleSort(arr2); printArray( arr2); } /* * 选择排序 * 内循环结束一次,最值出现在头角标位置上 * */ public static void selectSort(int[] arr) { //用一个外循环控制每次用哪个角标与后面的元素进行比较 for(int x = 0 ; x< arr.length -1;x++) { //用一个内循环使选定的元素与它后面的每个元素进行比较换位 for(int y= x+ 1 ; y< arr.length;y++) { if(arr[x] > arr[y]) { int temp = arr[x]; arr[x] = arr[y]; arr[y] = temp; } } } } /* * 冒泡排序 * 特点 内循环结束一次,最值出现在尾角标位置上 * */ public static void bubbleSort(int[] arr) { for(int x = 0 ; x< arr.length -1;x++) { //y< arr.length - x -1防止角标越界 //-x目的:让每一次比较的元素减少 //-1目的:避免角标越界 for(int y= 0 ; y< arr.length - x -1;y++) { if(arr[y] > arr[y+1]) { int temp = arr[y]; arr[y] = arr[y+1]; arr[y+1] = temp; } } } } //遍历数组 public static void printArray(int[] arr) { System.out.print("["); for (int x=0;x<arr.length;x++) { if(x!=arr.length-1) System.out.print(arr[x]+","); else System.out.print(arr[x]+"]"); } //换行 System.out.println(); } }
- 折半查找(二分查找)
- 前提:数组中元素必须是有序的。
- 原理:
- 定义两个变量,一个初始化0角标,作为最小值,一个初始化为最后角标,作为最大值,再定义一个变量,存储最小值与最大值的一半,也就是中间位置,然后将要查找的元素与中间值位元素进行比较。
- 如果比中间值元素大,则将最小值变为中间值加1,继续取最小值与最大值的中间值元素与要查找元素进行比较,以此反复。
- 如果比中间值元素小,则将最大值变为中间值减1,继续取最小值与最大值的中间值元素与要查找元素进行比较,以此反复。
- 练习:
public class HalfSeachDemo { /** * 需求:将一个已知元素插入到一个有序数组中,要求不改变数组顺序,打印元素应该插入数组位置的角标。 * 思路:因为数组是有序的,可以使用二分查找,查找到插入元素在数组中的位置。 * @param args */ public static void main(String[] args) { int[] arr={6,9,11,17,23,31}; //打印数组 printArray(arr); //用第一种折半方式输出插入的角标值 System.out.println("25插入数组中的位置:" + halfseach_1(arr,25)); //用第二种折半方式输出插入的角标值 System.out.println("15插入数组中的位置:" + halfseach_2(arr,15)); } public static int halfseach_1(int [] arr , int key) { int min,max,mid; min = 0 ; max = arr.length-1; mid = (max+min)/2; while(key != arr[mid] ) { if(min>max) return min; else if(key>arr[mid]) min=mid+1; else max = mid - 1; mid = (max + min)/2; } return mid; } public static int halfseach_2 (int [] arr , int key) { int min,max,mid; min = 0 ; max = arr.length-1; mid = (max + min)/2; while(min <= max) { mid = (max + min)/2; if(key > arr[mid]) min = mid+1; else if(key< arr[mid]) max = mid - 1; else return mid; } return min; } //遍历数组 public static void printArray(int[] arr) { System.out.print("["); for (int i = 0; i < arr.length; i++) { if(i != arr.length - 1) System.out.print(arr[i] + ","); else System.out.println(arr[i] + "]"); } } }