Java是完全面向对象,安全可靠,与平台无关的语言。
Java的版本有:
环境变量:JavaEE(J2EE)企业版:为开发企业环境下的应用程序提供的一套解决方案
J2SE标准版(基础版):开发普通桌面和商务应用程序
J2ME小型版:针对电子消费产品和嵌入式设备提供的解决方案
在运行Java程序前,需要先配置环境变量,将Java中的.exe文件配置到path中,方便在Java中各个工具的运行。程序运行时,需要配置classpath,将.class文件配置到classpath,告知虚拟机到该路径下寻找。
JRE:Java运行环境。
JDK:Java开发工具包。为开发人员提供,其中也包括JRE。
JVM:Java虚拟机,用于运行Java程序。
Java言由关键字、标识符、注释、常量与变量、运算符、语句、函数与数组组成。
第一部分:关键字
Java中的关键字是Java中定义的具有特殊意义的单词(小写)。包括权限修饰符,类、方法及变量修饰符,程序流程控制语句,基本数据类型,void,异常处理,包相关等。(在相关的章节会重点介绍)
第二部分:标识符
1、标识符是在程序中自定义的一些名词。
2、由26个英文字母(大小写),数字:0-9,符号:_$组成。
3、定义合法标识符的规则。
a、数字不可以开头。
b、不可以使用关键字。
4、Java中严格区分大小写,在起名时,为了提高阅读性,要尽量有意义。
注意:main不是关键字,main函数是程序的入口,能被虚拟机识别。
总结:Java中的名称规范
1、包名:xxyyzz(多个单词组成时,所有字母小写)。
2、类名及接口名:XxxYyyZzz(多个单词组成时,所有单词首字母大写)。
3、变量名或函数名:xxxYyyZzz(多个单词组成时,第一个单词首字母小写,其余单词字母大写)。
4、常量名:XXX_YYY_ZZZ(多个单词组成时,所有单词字母均大写,两个单词间用"_"连接)。
第三部分:注释
注释用于调试程序或者注解代码。注释分为以下三种:
注意事项:
1、 多行注释中可以加单行注释,但是不能加多行注释。
2、 文档注释用于生成API文档。
3、 写代码时尽量养成写注释的习惯。(包括要求、思路、步骤及功能等)
第四部分:常量
1、 常量表示不能被改变的值。
2、 Java中常量的分类:
1) 整数常量:所有整数。
2) 小数常量:所有小数。
3) 布尔型常量:较为特殊,只有两个值:true false
4) 字符常量:将一个数字、字母或者符号用单引号 ’ ’ 标识。
5) 字符串常量:将一个或者多个字符用双引号 “ ” 标识。
6) null常量:只有一个数值:null。
对于整数,Java有三中表现形式:
十进制:0-9,满10进1;
八进制:0-7,满8进1,用0开头;
十六进制:0-9,A-F,满16进1,用0x开头。
二进制:
二进制由电信号(开关,1与0)演变而来,任何数据在计算机中都是以二进制的形式存在的,一个整数在内存中一样也是二进制的,但是使用一大串的1或者0组成的数字使用很麻烦,于是就将一大串数字缩短,变出现了八进制、十六进制。
进制转换:
十进制与二进制之间的转换:
9的二进制表现形式:余数倒着写,为1001。
二进制1001转换为10进制:
二进制与八进制之间的转换:(3个二进制位表示1位)
二进制与十六进制之间的转换:(4个二进制位表示一位)
负数的二进制表现形式:正数的二进制取反加1。如-6的二进制:
第五部分:变量
用于存储同类型的不确定的数。
格式:
数据类型 变量名 = 初始化值;
Java是强类型的语言,对于每一种数据都定义了明确的具体数据类型,在内存中分配了不同大小的空间存储。
数据类型:
1、 基本数据类型:
数值型:整数(byte,short,int,long)、浮点数(float,double)
字符型:char
布尔型:boolean
2、 引用数据类型:
类(class)
接口(interface)
数组([])
各类型数据所占内存
Java中存在着强类型转换:
如:byte b = 3;
b = b+2;//报错,等号右边强制提升为int型
b = (byte)(b+2);//将int型数据强转为byte
注意:float与int类型数据做运算时,结果为float类型,因其精度高。
第六部分:运算符
1、 算数运算符
注意:当有负数参与%运算时,结果只看被模数的符号。
2、 赋值运算符
注意:byte b = 4;
b = b+2;//报错
b += 2;//正确,为一个运算符
3、 逻辑运算符
注意:
||与|的区别:
|两边都参与运算;||左边为true右边不参与运算。
&&与&的区别:
&两边都参与运算;&&左边为false时右边不参与运算。
4、 位运算符
注意:
1)>>与>>>的区别:
>>:右移时最高位是什么就补什么(如负数最高位补1)。
>>>:无论最高位是什么都补零。
2)一个数异或一个数两次,结果为原来的数。
交换两个数的值的方法:
1)通过第三方变量,如:
int m = 6,n = 7; int temp; temp = m; m=n; n=temp;
2)不通过第三方变量
int m=7,n=8; n=m+n; m=n-m; n=n-m;
3)异或的方式
int m=4,n=7; n=n^m; m=n^m; n=n^m;
示例代码:
/* 需求:演示位运算符 */ class Demo1 { public static void main(String[] args) { //定义一个int类型的变量 int num = 60; //与运算 int n1=num&15; //将结果强转为char类型 System.out.println((char)(n1-10+'A')); //右移运算 int temp = num>>4; System.out.println(temp); } }
运算结果为:
图解:
5、 三元运算符
格式:(条件表达式)?表达式1:表达式2
如果条件为true,则结果为表达式1。
如果条件为false,则结果为表达式2。
6、 转义字符
注意:
1)在Windows系统中,回车符由\r\n组成。
2)要想得到\,在输入时需要输入\\。
第七部分:程序流程控制
一、判断结构
格式1: if(条件表达式) { 执行语句; } 格式2: if(条件表达式) { 执行语句; }else { 执行语句; } 格式3: if(条件表达式) { 执行语句; }else if(条件表达式) { 执行语句; } ... ... else { 执行语句; }
总结:
1、if/else结构简写格式:三元运算符,变量 = (条件表达式)?表达式1:表达式2
2、三元运算符可以简化代码,但因其是一个运算符,必须要有结果。
package demo; /* 需求:演示if与三元运算符 */ class Demo1 { public static void main(String[] args) { //调用指定的函数 ifDemo(); arichDemo(); } //if演示 public static void ifDemo(){ int x=6; if(x==6){ System.out.println("x = "+6); }else{ System.out.println("x = "+x); } } //三元运算符演示。二者等效 public static void arichDemo(){ int x = 7,y; y = (x==7)?7:x; System.out.println("y = "+y); } }
结果为:
二、选择结构
格式: switch(表达式){ case 取值1: 执行语句; break; case 取值2: 执行语句; break; ... ... default 执行语句; break; }
switch语句的特点:
1、 被选表达式只接受4中类型:byte,int,short,char。
2、 switch语句中case与default没有顺序,但执行顺序是固定的,即先执行case,再执行default。
3、 switch语句可以以break和}结束。
4、 如果匹配的case或者default没有对应的break,那么程序就会继续向下执行,不再判断case,并运行可以执行的语句,直到遇到break或switch语句结尾结束。
5、多个case可以对应同一个执行语句。
示例代码:
/* 需求:switch 语句演示 */ class SwitchDemo { public static void main(String[] args) { int x=1; switch(x) { //多个选项对应同一条输出语句 case 3: case 4: case 5: System.out.println(x+"春季"); break; case 6: case 7: case 8: System.out.println(x+"夏季"); break; case 9: case 10: case 11: System.out.println(x+"秋季"); break; case 12: case 1: case 2: System.out.println(x+"冬季"); break; default: <span style="white-space:pre"> </span>break; } } }
swith与if的区别:
1、 if除了能判断数值外,还可以判断区间;switch判断区间很麻烦。
2、 对于运算结果为boolean的,if能判断,switch不能。
因此,对具体数值进行判断,并且数值不多时,且类型符合byte,short,int,char时,可以使用switch完成。其他情况用if。
三、循环结构(遍历)
循环有while循环、do/while循环和for循环,依次介绍。
1、while循环:
格式1:while循环 while(条件表达式){ 执行语句: } 格式2:do/while循环 do{ 执行语句: }while(条件表达式)
注意:
1)while的特点:先判断循环条件,只有条件满足再执行循环体。
2)do/while的特点:先执行循环体,在判断条件,只有条件满足再继续执行循环体。
也就是说do/while的循环体至少会执行一次。
2、for循环:
for循环语句格式: for(初始化表达式;条件表达式;循环后的操作表达式){ 执行语句; }
for与while的区别:
1)for语句中的变量作用域为当前for循环,不能在for循环外面使用该变量。
2)for循环中的循环条件表达式必须要有真假结果。
因此,当变量仅仅由于控制循环次数,作为循环增量存在,用for语句更合适(内存更优化);用while语句时,循环结束后变量仍然存在,其仍占用内存。(本质上两者可以直接互换)
示例代码:
/* 需求:while循环、do/while循环与for循环演示 */ public class Demo2 { public static void main(String[] args){ //调用指定的函数 whileDemo(); doWhileDemo(); forDemo(); } public static void whileDemo(){ int x = 0; //while循环 while(x<4){ if(x==3){ System.out.println("x = "+x); //跳出当前循环 break; } x++; } } public static void doWhileDemo(){ int y = 0; //do while循环(循环体至少执行一次) do{ System.out.println("y = "+y); }while(y>3); } public static void forDemo(){ //for循环 for(int z=0;z<=3;z++){ System.out.print(z+" "); } //System.out.println(z);编译报错,变量不存在 } }
运行结果为:
无线循环的最简单的表现形式:
for(;;){}
while(true){}
累加思想:
使用循环,并通过一个变量记录数据的状态变化后的结果,这就是累加思想。
/* * 需求:求1+2+...+100的和 * * 思路: * 典型的累加思想,定义一个计数器记录数据的变化,通过for循环来控制变化。 */ public class CountDemo{ public static void main(String[] args){ int sum = getSum(100); System.out.println("sum = "+sum); } private static int getSum(int num) { //计数器 int sum = 0; for(int x=0;x<=num;x++){ sum = sum+x; } return sum; } }
结果:
3、循环嵌套
所谓循环嵌套就是循环中还有循环,这在java中很常见。
/* 需求:打印如下图形 * ** *** **** ***** 思路: 1、输出矩阵,采用for循环嵌套的形式 2、外循环控制行,内循环控制列(5行5列) 3、列数在随着外循环的变化而变化,改变循环条件,让其随之改变。 */ public class Demo3 { public static void main(String[] args){ for(int x=0;x<5;x++){ for(int y=0;y<=x;y++){ System.out.print("*");//不换行 } <span style="white-space:pre"> </span>//一行结束再换行 System.out.println(); } } }
小规律:1)输出图形的尖朝上,可以改变内循环条件,让条件随着外循环变化。
2)尖朝下,可以改变内循环初始化值,让初始化值随着外循环变化。
示例代码:
package demo; /* 需求:输出九九乘法表 思路: 1、与上一题类似,采用forfor循环嵌套的形式,改变内循环的循环条件,让其随着外循环的变化而变化。 2、输出结果成了两个数的成绩。 */ public class Demo4 { public static void main(String[] args){ for(int x=1;x<=9;x++){ for(int y=1;y<=x;y++){ //输出x*y,并加入制表符优化格式 System.out.print(x+"*"+y+"="+x*y+"\t"); } System.out.println(); } } }
输出结果:
4、其他流程控制语句
1)break:应用于选择结构和循环结构。
2)continue:应用于循环结构。
注意:
1)这两个语句离开应用范围是没有任何意义的。
2)这两个语句单独存在时,下方不可以有语句,因为执行不到。
3)continue语句表示结束本次循环,继续下次循环;break是跳出当前循环。
4)标号的出现,可以让两个语句左右于指定的范围。(标号只能用于循环上)
class Demo { public static void main(String[] args) { //w循环 w:for(int x=0;x<5;x++) { //q循环 q:for(int y=0;y<3;y++) { if(y==2) { //跳出break循环 break w; } System.out.print("*"); } System.out.println(); } } }
第八部分:函数
一、函数的定义
函数就是定义在类中的具有特定功能的一段独立小程序。其格式如下:
修饰符 返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数2,... ...) { 执行语句; return 返回值; } 返回值类型:函数运行后的结果的数据类型 参数类型:形式参数的数据类型 形式参数:是一个变量,用于存储调用函数时传递给函数的实际参数 实际参数:传递给形式参数的具体数值 return:用于结束函数 返回值:返回给调用者的值
注意:
1、一般函数只有被调用才会执行,且函数必须写在类里面。
2、函数中只能调用函数,不能在函数内部定义函数。
3、定义函数时,函数的结果应返回给调用者,让调用者进行处理。
二、函数的特点
1、定义函数可以将功能代码进行封装。
2、便于对该功能进行复用。
3、函数只有被调用才会执行。
4、函数的出现提高了代码的复用性。
5、若函数中没有具体的返回值,返回值类型用关键字void表示,那么该函数中的return语句如果在最后一行可以省略不写。
三、函数的应用
函数是java中最小的功能单元,在写代码时要先将功能封装在函数中,什么时候需要该功能,调用即可,主函数中尽量不要写过多的代码。
如果定义函数?
1、明确需要实现的功能。
2、明确返回值类型。
3、明确参数列表。
四、函数的重载
1、重载的概念
在同一个类中,允许存在两个以上的同名函数,只要它们的参数个数或参数类型不同即可。
2、重载的特点与返回值类型无关,只看参数列表。(参数有顺序之分)。
3、重载的好处
方便于阅读,优化了代码。
当定义的功能相同,但是参与运算的未知内容不同时,则定义同一个函数名称以表示其功能,方便阅读,而通过参数列表的不同来区分不同的函数。
4、重载示例
/* 需求:利用函数的重载特性,定义多个功能用于打印不同类型的数据 */ public class Demo5 { public static void main(String[] args){ //调用指定的函数 print(); print(5); print(7,9.23); } //定义函数用于输出abc public static void print(){ System.out.println("abc"); } //定义函数用于输出int 型数据 public static void print(int num){ System.out.println("num = "+num); } //定义功能用于数据int 与 double 型数据 public static void print(int a,double b){ System.out.println("a = "+a+"b = "+b); } }
第九部分:数组
一、数组的定义
数组就是同一种类型数据的集合,它是一个容器。
数组可以自动给数组中的元素从0开始编号,方便操作这些元素。
数组的格式:
格式1: 元素类型[] 数组名 = new 元素类型[元素个数或数组的长度] 示例:int[] arr = new int[6]; 格式2: 元素类型[] 数组名 = new 元素类型[]{元素1,元素2,...}; 示例:int[] arr = new int[]{3,4,5}; int[] arr = {3,4,5};
二、数组的内存分配及特点
1、内存结构
Java程序在运行时,需要在内存中开辟空间,为了提高运算效率,对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
栈内存(栈区):
用于存储局部变量(定义在for循环、函数、方法参数中的变量均为局部变量)。
栈内存的特点:内存自动是释放(数据使用完毕后)
堆内存(堆区):
用于存储数组和对象,通过new建立的实体都存在与堆内存中。
堆内存的特点:
内存地址值、默认初始化值、垃圾回收机制。
Java垃圾回收机制:
程序员不用手动清除垃圾,只要对象或实体在内存中变成垃圾,JVM就会自动启动垃圾回收机制,将堆内存中的不再被使用的实体清除掉(不定时)。
方法区、本地方法区、寄存器
示例:
class ArrayDemo{ public static void main(){ int[] arr = new int[3];//新建一个长度为2的int类型数组 } }
代码在内存中的体现:
三、数组操作常见问题
1、角标越界异常。操作数组时,访问到了数组中不存在的角标。(编译时并不会报错)
2、空指针异常。当引用没有任何指向(null)时,该引用还在操作实体。
四、数据常见操作
数组中有一个属性可以获取到数组中元素的个数,即 数组名.length
在操作数组时,通常会用到for循环对数组进行遍历。
1、选择排序
package demo; /* 需求:对数组进行选择排序。 选择排序:选择一个固定位置和其他位置进行比较,符合条件就交换(最值出现在头角标位) */ public class ArrayDemo1 { public static void main(String[] args){ int[] arr ={6,3,2,9,5}//定义一个数组 print(arr); //对数组进行排序 selectSort(arr); //打印排序后的数组 print(arr); } //功能:对数组进行选择排序 public static void selectSort(int[] arr) { for(int x=0;x<arr.length-1;x++){//-1避免角标越界 for(int y=x+1;y<arr.length;y++){ //arr[x]>arr[y]就交换 if(arr[x]>arr[y]) swap(arr,x,y); } } } //功能:交换数组中两个元素的位置 public static void swap(int[] arr,int a,int b){ int temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; } //功能:输出数组 public static void print(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(" ]"); } }
结果为:
图解:
2、冒泡排序
package demo; /* 需求:对数组进行冒泡排序。 冒泡排序:相邻连个函数进行比较,符合条件就换位(最值出现在最后一位) */ public class ArrayDemo2 { public static void main(String[] args){ int[] arr = {3,9,6,2,4}; //输出数组 print(arr); //对数组进行排序 bubbleSort(arr); print(arr); } //功能:对数组进行冒泡排序 public static void bubbleSort(int[] arr) { for(int x=0;x<arr.length-1;x++){//-1避免角标越界 for(int y=0;y<arr.length-1-x;y++){//-x代表每次少比一个元素 //相邻两个元素比较 if(arr[y]>arr[y+1]) swap(arr,y,y+1); } } } //功能:交换数组中两个元素的位置 public static void swap(int[] arr,int a,int b){ int temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; } //功能:输出数组 public static void print(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(" ]"); } }
排序后结果为:
图解:
注意:
选择排序与冒泡排序在数据较多时,处理效率较低。
实际开发中采用java.util.Array类进行操作。
3、折半查找
package demo; /* 需求:对有序数组进行折半查找。 前提:数组有序 思路: 1、将需要查找的值key与中间角标的值arr[mid]进行比较。 若key>arr[mid],则将小角标min移动到中间角标+1 若key<arr[mid],则将大角标max移动到中间角标-1 2、当key==arr[mid],说明找到值,角标为中间角标 当min>max,说明没有找到,返回-1 */ public class ArrayDemo3 { public static void main(String[] args){ int[] arr = {3,4,7,9,10}; printArr(arr); //分别查找7和8在数组中存在的位置 int index1 = halfSearch(arr,7); int index2 = halfSearch(arr,8); System.out.println("index1 = "+index1+"\r\nindex2 = "+index2); } public static int halfSearch(int[] arr, int key) { //定义两个角标,头角标为0,尾角标为最大角标 int max = arr.length-1; int min = 0; //获取中间角标 int mid = (max+min)/2; //当中间角标对应的值不是索要查找的值时 while(key!=arr[mid]){ if(key>arr[mid]) min = mid+1;//key比中间值大,小角标=min+1 else if(key<arr[mid]) max = mid-1key//比中间值小,大角标=min-1 //循环一次就改变一次中交角标 mid = (max+min)/2; if(min>max){ return -1;//未找到,返回-1 //return mid//返回key插入的位置 } } //其他情况说明key==arr[min],返回中间角标 return mid; } public static void printArr(int[] arr) { System.out.print("["); for(int x=0;x<arr.length;x++){ if(x==arr.length-1) System.out.println(arr[x]+"]"); else System.out.print(arr[x]+", "); } } }
运行结果:
图解:
注意:若要在有序数组中插入元素,则返回的角标-1应为mid。
五、二维数组
1、定义及格式
格式1:int[][] arr = new int[3][4]; 含义: 1)定义一个名称为arr的二维数组。 2)二维数组中有3个一维数组。(二维数组的长度为3) 3)每一个一维数组中有4个元素。 4)一维数组的名称为arr[0],arr[1],arr[2] 格式2:int[][] arr = new int[2][]; 含义: 1)二维数组中有2个一维数组。 2)每个一维数组的初始化值为null。 3)可以对这2个一维数组进行初始化: arr[0] = new int[3]; arr[1] = new int[5]; 格式3:int[][] arr = {{3,2,4},{2,1},{5,7,1}}; 含义: 1)二维数组中有3个一维数组。 2)三个一维数组分别为{3,2,4},{2,1},{5,7,1} arr.length()为二维数组的长度,arr[0].length()为二维数组中第1个元素的长度
2、内存中的体现
六、数组的综合利用(查表法)
/* * 查表法完成进制转换。 * * 思路: * 1、通过分析发现,进制的转换其实就是相对应的数进行&运算然后右移指定的位数,依次循环,直到最后的数为0 * 每次循环都会得到一个索引。 * 2、可以定义一个字符数组0-9,A-F,然后利用索引取查该表。 * 3、最后当得到的字符反向输出即可。 * * 步骤: * 1、定义一个功能来实现进制转换 * 2、在该函数中定义一个字符数组(表,0-9,A-F) * 3、定义一个字符串缓冲区用于存储查表后所得到的数据 * 4、对数进行遍历,在循环中进行不断的&基数和右移运算,获取指针并查表,并将查到的数字存入字符串缓冲区中 * 5、对字符串缓冲区中的数据进行输出。 */ public class ChangeRadix { public static void main(String[] args) { toBin(6); toHex(60); } //转换成16进制 public static void toHex(int num) { changeRadix(num, 15, 4); } //转换成2进制 public static void toBin(int num) { changeRadix(num,1,1); } //进制转换共同代码 private static void changeRadix(int num,int base,int offset){ //表格 char[] chs = {'0','1','2','3','4','5','6','7', '8','9','a','b','c','d','e','f'}; //字符串缓冲区,用于存储数据 StringBuilder sb = new StringBuilder(); while(num!=0){ //获取每一段数据,并使用该数据取查表 int pos = num&base; sb.append(chs[pos]); num = num>>>offset; } System.out.println(sb.reverse()); } }
运行结果为: