1.关于Java语言本身的一些概念
1.1Java语言跨平台原理
在需要运行Java应用程序的操作系统上,安装一个与操作系统对应的Java虚拟机(JVM)即可。
1.2JRE、JDK、JVM的关系
JRE(Java Runtime Environment):java运行环境。它是java程序的运行时环境,包含JVM和运行时所需的核心类库。若运行java程序,只需安装JRE即可。
JDK(Java Development Kit):java开发工具包。是java程序开发工具包,包含JRE和开发人员使用的工具。(其中的开发工具→编译工具:javac.exe,运行工具:java.exe,打包工具:jar.exe等)
JVM(Java Virtual Machine):是一个虚拟的计算机,具有指令集并使用不同的存储区域,负责执行指令,管理数据、内存、寄存器。
1.3Java的特点
①面向对象
两个基本概念:类、对象 ;三大特性:封装、继承、多态;
②健壮性
吸收了C/C++语言的优点,但去掉了其影响程序健壮性的部分(如指针、内存的申请与释放等),提供了一个相对安全的内存管理和访问机制;
③跨平台性
同一个java程序可在不同操作系统中执行,但每个操作系统中的JVM不一样。
1.4java的核心机制
JVM(Java Virtual Machine)和垃圾回收(Garbage Collection)。
垃圾回收:Java语言提供一种系统级线程跟踪存储空间的分配情况,并在JVM空闲时,检查并释放那些可被释放的存储空间。垃圾回收在java程序运行过程中自动进行,程序员无法精确控制和干预。
1.5JDK、JRE、JVM的关系
1.6Java程序开发运行流程
注:<1>一个源文件最多只能有一个public类,其它类的个数不限,如果源文件包含一个public类,则文件名必须按该类名命名;
<2>字节码文件的文件名是类名,由于一个java程序中可能包含多个类,所以执行javac.exe命令后可能会生成多个class文件。
1.7关于API
API(Application Programming Interface),应用程序编程接口,是java提供的基本编程接口,也就是核心类库。
API文档:告诉开发者如何使用这些类,以及这些类中包含的方法
1.8常用的DOS命令
dir:列出当前目录下的文件以及文件夹
md:创建目录
rd:删除目录(用来删除文件,但只能是空文件夹;rd /s可以用来删除非空的文件夹)
cd:进入指定目录
cd..:退回到上一级目录
cd\:退回到根目录
del:删除文件(用来删除文件;也可以用来删除某一文件夹下的所有文件)
exit:退出DOS命令行
echo:在显示器上显示一段文字;也可以直接在文件中写入要写的内容
2基础语法
2.1关键字与保留字
关键字(keyword):被java语言赋予了特殊含义,用作专门用途的字符串(单词),关键字中所有字母都为小写。
保留字(reserved word):现有java版本尚未使用,但以后的版本可能作为关键字使用。eg:const,goto
2.2标识符(Identifier)
注:凡是自己可以起名字的敌方都叫标识符.
①标识符命名规则(必须要遵守):
<1>由26个英文字母大小写,0-9,_或$组成;
<2>数字不可以开头;
<3>不可以使用关键字和保留字,但能包含在名字其中
<4>Java严格区分大小写
<5>不能包含空格
②标识符命名规范(编程规范)
<1>包名:所有字母都小写:xxxyyyzzz
<2>类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz
<3>变量名、方法名:多单词组成时,第一个单词的首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz
<4>常量名:所有字母都大写,多单词组成时每个单词用下划线连接:XXX_YYY_ZZZ
2.3变量
①数据类型:
②基本数据类型的存储空间占用情况:
注:bit:计算机中的最小存储单位;byte:计算机中的基本存储单元
类型 | 占用存储空间 | 表数范围 |
byte,char | 1byte=8bit | -128—127 |
short | 2byte | - |
int,float | 4byte | - |
double | 8byte | - |
③类型转换
<1>自动类型转换:容量小的数据类型自动转换为容量大的数据类型
注:byte,short,char之间不会相互转换,他们三者在计算时首先转换成int型
<2>强制类型转换:将容量大的数据类型转换为容量小的数据类型。
使用时应加上强制转换符:(),这可能会造成精度降低或溢出。
eg:double num1=1.2; double num2=(int) num1; //(int)后面其实也可以是具体的数值;这里的num2的值为1.0
2.4运算符
①算术运算符:+,-,*,/,%,++,--
算术表达式中包含多个基本数据类型的值的时候,整个算术表达式的类型会自动提升;
②赋值表达式:=,-=,+=,*=,/=,%=
复合赋值表达式隐含了强制类型转换
③自增自减运算符:i++,i--,++i,--i
eg:int n=10; n+=(n++)+(++n); //这里最终的n为32,第二句其实是n=n+(n++)+(++n)=10+10+12=32
④比较(关系)运算符:==,!=,>,>=,<,<=,instanceof(检查是否是类的对象)
⑤逻辑运算符:&(逻辑与),|(逻辑或),!(逻辑非),&&(短路与),||(短路或),^(逻辑异或)
<1>逻辑异或^:左右相同时为false,左右不同时为true
<2>&和&&的区别:单&时,左边无论真假,右边都进行运算;双&&时,若左边为真,右边参与运算,若左边为假,右边不参与运算。|和||同理,对于||,当左边为真,右边不参与运算。
⑥三元运算符:condition ? expression1 : expression2
⑦位运算符:<<,>>,>>>,&,|,^,~
![](https://i-blog.csdnimg.cn/blog_migrate/69154b62d5595ac969949cdcfbf76229.png)
<1>与逻辑运算符有些符号一样,但位运算符对应的运算对象是数字,逻辑运算符对应的是布尔变量;并且它放到了二进制的层面上;
<2>一个数左移x位,相当于这个数乘以2的x次方;
eg:一个十进制数21,二进制表示为:0000 0000 0000 0000 0000 0000 0001 0101,进行21<<2,实际为二进制级别的左移两位,即0000 0000 0000 0000 0000 0000 0101 0100,换算成十进制为84。
注意:当左移时,若最高位符号发生变化,数的符号就变了。
<3>一个数右移x位,相当于这个数除以2的x次方;前面空的位依据原最高位的数字去补,以前最高位为1,则全补1,若以前最高位为0,则全补0。
eg:一个十进制数21,二进制表示为:0000 0000 0000 0000 0000 0000 0001 0101,进行21>>2,实际为二进制级别的右移两位,即0000 0000 0000 0000 0000 0000 0000 0101,换算成十进制为5。
2.5程序流程控制
2.5.1分支结构
①if-else结构
三种类型:<1>if();<2>if()-else;<3>if()-else if()-else if()-else
②switch-case结构
switch(表达式)
{
case 常量1:
语句1;
break;
case 常量2:
语句2;
break;
......
default:
语句n;
break;
}
<1>switch结构中的表达式,只能有6种类型,byte、short、int、String、char、枚举类型;
<2>case后面接的是常量;
<3>case穿透,如果某个case语句后没有break,如果这句case被执行,其后面的case语句也将被执行。
2.5.2循环结构
循环结构的四要素:初始化条件,循环条件,循环体,迭代条件
①for循环
<1>格式:
for(初始化条件;循环条件;迭代条件)
{循环体}
注:for循环的初始化条件部分可以有多个,但必须为同一数据类型
<2>例题:获取两个数的最大公因数和最小公倍数(辗转相除法还不会!!!)
public class GysGbs
{
public static void main(String[] args)
{
Scanner in=new Scanner(System.in);
int num1=in.nextInt(); //第一个数
int num2=in.nextInt(); //第二个数
//找最大公因数
for(int i=(num1>num2?num2:num1);i>1;i--)
if(num1%i==0&&num2%i==0)
{
System.out.println(num1+"和"+num2+"的最大公因数为: "+i);
break;
}
//找最小公倍数
for(int i=(num1>num2?num1:num2);i<num1*num2;i++)
if(i%num1==0&&i%num2==0)
{
System.out.println(num1+"和"+num2+"的最小公倍数为: "+i);
break;
}
}
}
②while循环
<1>格式:
初始化条件
while(循环条件)
{
循环体;
迭代条件;
}
③do-while循环(至少执行一次循环体)
<1>格式:
初始化条件
do
{
循环体;
迭代条件;
}while(循环条件);
④不在循环条件中限制次数的结构:
for(;;)或while(true)
⑤嵌套循环(一般实际开发时不超过三层)
例题:输出10万以内的质数。(这里做了两次优化,见代码注释)
public class PrimeNumber
{
public static void main(String[] args)
{
long start= System.currentTimeMillis(); //代码运行的开始时间
int count=0;
for (int i=2;i<=100000;i++)
{
for (int j=1;j<=Math.sqrt(i);j++) //优化二,只用取除数的开方就可,因为i的开方后面的数能被整除,前面的数肯定也能被整除
{
if (i%j==0&&j!=1&&j!=i)
{
count++;
break; //优化一:当已经初步识别某个数不是质数时,退出循环
}
}
if (count==0) //当j取到了sqrt(j)时,count的值还没有变化,说明此次循环的i是质数
System.out.println(i);
count=0; //进行下一个数是否为质数的识别,需将count重新归0
}
long end= System.currentTimeMillis(); //代码运行的结束时间
System.out.println("waste time:"+(end-start)); //代码运行的消耗时间
}
}
⑥break和continue关键字的使用
<1>比较
使用范围 | 循环中的作用(不同点) | 相同点 | |
break | switch-case结构,循环结构 | 结束当前循环 | 该关键字后面不可声明执行语句 |
continue | 循环结构 | 结束当次循环 |
<2>用于带标签语句
eg:label1: for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
{
if (j==5) break label1; //直接结束外层for循环
}
3.数组(Array)
3.1数组的概述,特点
①数组的定义:是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。
②数组的特点:
<1>数组是序排列的;
<2>数组属于引用数据类型的变量。数组的元素,既可以是基本数据类型,也可以是引用数据类型;
<3>创建数组对象会在内存中开辟一整块连续的空间,数组名引用的是这段连续空间的首地址;
<4>数组的长度一旦确定,就不能修改。
3.2一维数组的使用
①声明
eg:int[] arr1; String[] arr2;
②初始化
<1>动态初始化:数组声明且为数组元素分配空间与对元素的赋值操作分开进行
eg:int[] arr=new int[3];
arr[0]=1;arr[1]=2;arr[2]=3;
<2>静态初始化:在定义数组的同时就为数组元素分配空间并赋值
eg:int[] arr=new int[]{1,2,3};
③默认初始化值
④一维数组的内存解析
<1>内存结构
<2>举例图解说明一维数组的内存解析
3.3多维数组的使用(以二维为例)
①二维数组的声明与初始化
<1>动态初始化
情况1:int[][] arr1=new int[4][3]; //指定了数组arr1有4个一维数组,每个一维数组有3个元素
情况2:int[][] arr2=new int[4][]; //仅指定了数组arr2有4个一维数组,每个一维数组包含元素个数未说明
<2>静态初始化
int[][] arr3=new int[][]{{1,2},{1,2,3,4},{5,6,7}}; //静态初始化时,红色部分可删除,因为有类型推断
②默认初始化值
eg:
对于:int[][] arr1=new int[2][3]; //外层元素arr[1]的值为地址值,内层元素arr[0][1]的值为0
对于:int[][] arr2=new int[2][]; //外层元素arr2[1]的值为null,内层元素arr[0][1]的值不存在,会报错,报java.lang.NullPointerException,即空指针异常
③举例图解说明二维数组的内存解析
④例题:用二维数组的知识输出一个10行的杨辉三角
public class YangHuiTriangle
{
public static void main(String[] args)
{
int[][] arr=new int[10][];
for (int i=0;i<10;i++) //两个for循环搭建框架
{
arr[i]=new int[i+1]; //每一行的元素个数递增1
for (int j = 0; j < i + 1; j++) //对每一行进行处理
{
if (j==0||j==i)
arr[i][j] = 1; //每一行的第一列和最后一列元素都为1
else
arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1]; //每一行的其他元素的值等于上一行该列的元素和前一列的元素之和
}
}
for (int i=0;i<10;i++) //杨辉三角的输出
{
for (int j=0;j<arr[i].length;j++)
System.out.print(arr[i][j]+"\t");
System.out.println();
}
}
}
3.4数组中涉及的常见算法(复制、反转、查找)
①复制
<1>情况1:地址都直接复制
eg:int[] arr1=new int[]{1,2,3};
int[] arr2=arr1; //此时改变arr2的元素值,a1也会随之改变,因为此时arr1和arr2的地址值一样
<2>情况2:仅是元素的复制
eg:int[] arr1=new int[]{1,2,3};
int[] arr2;
for(int i=0;i<arr1.length;i++)
arr2[i]=arr[i];
②反转
public class ArrayReverse
{
public static void main(String[] args)
{
int[] arr=new int[]{1,2,3,4,5,6,7,8,9};
/*方法一
for(int i=0;i<arr.length/2;i++)
{
int temp=arr[i];
arr[i]=arr[arr.length-1-i];
arr[arr.length-i-1]=temp;
}*/
//方法二
for(int i=0,j=arr.length-i-1;i<j;i++,j--)
{
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
for(int i=0;i<arr.length;i++)
System.out.print(arr[i]+"\t");
}
}
③查找(二分法查找)
二分法查找:每次用特定值跟中间值比较,折半的方式检索。前提是数组必须有序!
代码:
public class BinarySearch
{
public static void main(String[] args)
{
int[] arr=new int[]{1,2,5,7,9,12,15,57,79,102,342,564,767,989,1011}; //从小到大排列的有序数组
int num=989; //待查找元素
boolean isFlag=false;
int head=0; //初始首索引位置
int end=arr.length-1; //初始尾索引位置
while(head<=end)
{
int mid=(head+end)/2;
if(arr[mid]==num)
{
System.out.println(num+"已找到,位于数组的第"+(mid+1)+"位");
isFlag=true;
break;
}
else if(arr[mid]>num) //mid位置对应的数值比num大,则向左找
end=mid-1;
else //mid位置对应的数值比num小,则向右找
head=mid+1;
}
if(isFlag==false)
System.out.println("未在数组中找到数"+num);
}
}
3.5数组中涉及的常见算法(排序)
①一些概念
<1>衡量排序算法的优劣:
1)时间复杂度;2)空间复杂度;3)稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。
<2>排序算法分类:内部排序和外部排序
内部排序:所有排序操作都在内存中完成;
外部排序:彩玉排序的数据非常多,数据量非常大,无法仅在内存中完成,必须借助于外部存储器(如磁盘)。外部排序最常见的是多路归并排序,可认为外部排序是由多次内部排序而成。
<3>十种排序算法
<4> 各种排序算法的性能对比:
②冒泡法排序(Bubble)
<1>基本思想:每次比较相邻的两个元素,如果它们的顺序不符合排序要求就把它们交换过来,最终最后的一个元素会是期待的最大或最小的元素,重复上述步骤,最终可得到有序数列。
<2>代码:
public class BubbleSort
{
//这里从小到大排序
public static void main(String[] args)
{
int[] arr=new int[20]; //声明数组
for (int i=0;i<20;i++)
arr[i]=(int)(Math.random()*100); //随机初始化
for(int i=0;i<arr.length;i++) //原始的未排序的数组
System.out.print(arr[i]+"\t");
System.out.println();
//下面是两个for循环是冒泡法的核心
for(int i=0;i<arr.length-1;i++)
for(int j=0;j<arr.length-1-i;j++)
{
if(arr[j]>arr[j+1])
{
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
for(int i=0;i<arr.length;i++) //排从小到大序后的数组
System.out.print(arr[i]+"\t");
}
}
③快速排序(QuickSort)
<1>基本思想:假定从小到大排序,从数列中挑出一个基准元素(pivot),重排元素,所有比pivot小的元素都排到pivot前面,所有比pivot大的元素都排到pivot后面,在该分区操作结束后,pivot将位于中间位置(分区操作)。然后递归地将两个子数列进行排序。
<2>代码:注:这里对swap函数有疑问,见代码注释!!(已解决,见注释!)
public class QuickSort
{
public static void swap(int[]a,int i,int j)
{
int temp=0;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
/****************************************
这里不太明白,我把swap函数写成如下形式时,在subSort函数中调用时,无法完成交换,这跟c++一样,也涉及到形参实参之类的概念吗??
//回答:学完后面的知识后,发现这里设计到方法参数的值传递,像面这样,形参是两个基本数据类型,根本无法完成两个实参的数值交换,因为形参仅仅接收到的时实参的数据值,而非地址值!!!
public static void swap(int i,int j)
{
int temp=i;
i=j;
j=temp;
}
******************************************/
public static void subSort(int[]arr,int start,int end)
{
if(start<end) { //这句代码也很关键,不然会出现第一个数恰好最小或最后一个数恰好最大时,超过了数组索引范围
int pivot = arr[start];//这里把第一个元素记为pivot,并且是从小到大排列
int low = start;
int high = end + 1;
while (true)//low从左往右走,high从右往左走,当low大于high时,循环退出
{
while (low < end && arr[++low] - pivot <= 0) ;
while (high > start && arr[--high] - pivot >= 0) ;
if (low < high)
swap(arr, low, high);
else
break;
}
swap(arr, start, high);
subSort(arr, start, high - 1);
subSort(arr, high + 1, end);
}
}
public static void quickSort(int[] arr)
{
subSort(arr,0,arr.length-1);
}
public static void main(String[] args) {
int[] arr=new int[]{1,3,5,8,2,89,76,90,56,74,35,78,23,124};
quickSort(arr);
for(int i=0;i<arr.length;i++)
System.out.print(arr[i]+" ");
}
}
3.6Arrays工具类的使用
一些常用方法:
<1>static String toString(xxx[] arr):返回包含数组arr中元素的字符串;调用方式:Arrays.toString(arr);
<2>static void sort(xxx[] arr):使用快排对数组arr进行排列;调用方式:Arrays.sort(arr);
<3>static int binarySearch(xxx[] arr,int start,int end,xxx v):使用二分法在有序数组arr中查找值v,若找到,返回对应的下标;否则,返回一个负数值r,-r-1时v应插入的位置(为保持arr有序)
eg:
public class ArraysTest
{
public static void main(String[] args)
{
int[] arr=new int[]{1,3,5,8,2,89,76,90,56,74,35,78,23,124};
Arrays.sort(arr);
int local=Arrays.binarySearch(arr,90);
System.out.println(local); //local为排序后90元素的下标数,注意
}
}
3.7数组的常见异常
<1>数组角标越界异常:ArrayIndexOutofBoundsException
<2>空指针异常:NullPointerException