JAVA编程基础
一、数据类型
1.JAVA数据类型概述
JAVA是一门强类型语言,每个变量都需要指定数据类型,JAVA数据类型分为基本数据类型和引用数据类型。
2.基本数据类型
1.2.1基本数据类型
Java基本类型共有八种,基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。JAVA中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。实际上,JAVA中还存在另外一种基本类型void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作。基本数据类型如下图所示。
1.2.2数据类型占用空间
基本数据类型除了字符型和布尔型之外,其余六个都是表示数字的统称为数值型,每种基本数据类型在内存中的存储方式和占用方式都不同,数据类型占用空间如下表所示。
数据类型 | 占用空间 | 备注 |
---|---|---|
byte | 1B | -2^7~2^7-1(-128~127) |
short | 2B | -2^15~2^15-1(-32768~322767) |
int | 4B | -2^31~2^31-1 |
long | 8B | -2^63~2^63-1 |
float | 4B | -3.403x10^38~3.403x10^38 |
double | 8B | -1.798x10^308~1.798x10^308 |
boolean | 官方没有明确指出 | 只有true和false两个值 |
char | 2B | 能够表示任何Unicode的字符,并且在一定范围内可以与int互相转换。 |
二、运算符与表达式
2.1算数运算符
算数运算符是JAVA中最简单,最常用的运算符,它主要提供了数值的加减乘除以及求余运算的功能,算数运算符分为一元运算符和二元运算符,如下表所示。
运算符 | 描述 | |
---|---|---|
二元运算符 | + | 可以进行加法运算,也可以进行字符串的拼接 |
- | 减法运算 | |
* | 乘法运算 | |
/ | 除法运算,需要注意整数之间,除法运算的结果依然是整数 | |
% | 取模运算,即求余数 | |
一元运算符 | num++ | 自增运算符,先返回num的值,再将num加1 |
++num | 自增运算符,先将num加1,再返回num的值 | |
num-- | 自减运算符,先返回num的值,再将num减一 | |
--num | 自减运算符,先将num减1,再返回num的值 |
2.2赋值运算符
运算符 | 描述 | 运算符 | 描述 |
---|---|---|---|
= | 将右边的值赋给左边的变量 | *= | 如num*=5,相当于num=num*5 |
+= | 如num+=5,相当于num=num+5 | /= | 如num/=5,相当于num=num/5 |
-= | 如num-=5,相当于num=num-5 | %= | 如num%=5,相当于num=num%5 |
2.3关系运算符
当需要比较两个数值的大小时可以使用关系运算符,关系运算符也称作比较运算符,关系运算符的运算结果为布尔类型。
运算符 | 描述 | 运算符 | 描述 |
---|---|---|---|
> | 大于 | >= | 大于或等于 |
< | 小于 | <= | 小于或等于 |
== | 等于,注意,一个等于是赋值运算符 | != | 不等于 |
2.4逻辑运算符
逻辑运算符用于连接多个布尔值,一般与比较运算符一起使用,表示与或非的关系。
运算符 | 描述 |
---|---|
& | 与运算,当两边表达式都为true,结果为true,否则为false |
| | 或运算,当两边表达式都为false时,结果为false,否则为结果为true |
^ | 异或运算,当两边结果不同时,结果为true,否则结果为false |
! | 非运算,如果表达式结果为true,那么计算结果为false,反之亦然 |
&& | 短路与运算,计算结果与&运算符一致,但当第一个表达式为false时,第二个表达式就不再运算 |
|| | 短路或运算,计算结果与|运算符一致,但当第一个表达式为true时,第二个表达式就不再运算 |
2.5位运算符
虽然高级编程语言中都提供了算数运算符,但实际上计算机中的计算都是二进制的,这意味着使用算术运算符虽然简单,但存在着性能的损失,而未运算是直接对二进制进行的运算,性能极高,很多框架中都会运用位运算。
运算符 | 描述 |
---|---|
<< | 将二进制位左移指定位数。移动n位,就相当于乘上2的n次方 |
>> | 将二进制位右移指定位数。移动n位就相当于除以2的n次方 |
>>> | 无符号右移,结果会连同二进制最高位的符号位也移动 |
& | 与运算,类似于逻辑运算符。参与运算的两个数值为都为一,结果才为一,否则结果为零 |
| | 或运算,类似于逻辑运算符。参与运算的两个数字位都为零,结果才为0,否则结果为一 |
^ | 异或运算,类似于逻辑运算符。若参与运算的两个数字位不相同,则结果为一,若参与运算的两个数字位相同,则结果为零 |
~ | 按位取反运算,二进制数中的每一位如果为0就变成一,如果为一就变成零 |
2.6三元运算符
三元运算符又称三步运算符,是连接三个表达式的运算符,语法格式如下。
条件表达式?表达式1:表达式2;
当条件表达式为true时,执行表达式一,否则执行表达式二。
2.7运算符的优先级
优先级 | 描述 | 运算符 | 结合性 |
---|---|---|---|
1 | 括号 | () | |
2 | 正负号 | +,- | 从右到左 |
3 | 一元运算符 | ++,--,! | 从右到左 |
4 | 乘除 | +,- | 从左到右 |
5 | 加减 | +,- | 从左到右 |
6 | 移位运算 | >>,>>>,<< | 从左到右 |
7 | 比较大小 | >,<,>=,<= | 从左到右 |
8 | 比较是否相等 | ==,!= | 从左到右 |
9 | 按位与运算 | & | 从左到右 |
10 | 按位异或运算 | ^ | 从左到右 |
11 | 按位或运算 | | | 从左到右 |
12 | 逻辑与运算 | &&(简洁逻辑与),&(非简洁逻辑与) | 从左到右 |
13 | 逻辑或运算 | ||(简洁逻辑或),|(非简洁逻辑或) | 从左到右 |
14 | 三元运算符 | ?: | 从右到左 |
15 | 赋值运算符 | = | 从右到左 |
三、程序控制结构
3.1选择结构
从结构化程序设计角度出发,JAVA有三种结构,顺序结构,选择结构,循环结构。JAVA的基本结构就是顺序结构,除非特别指明,否则就按照顺序从上往下一句一句的执行,顺序结构是最简单的算法结构,语句与语句之间,框与框之间是按从上到下的顺序进行。
选择结构用于在代码中做一些逻辑判断,当满足某些条件时,执行某段代码。If语句是选择结构的代表。
3.1.1 if语句
if语句的语法格式如下所示
if(条件表达式 1){
//代码块 1
}else if(条件表达式2){
//代码块 2
}else if(条件表达式 3){
//代码块 3
}else {
//代码块 n
}
if语句在使用过程中还需要注意以下两点。
(1)如果if选择结构只需执行一条语句,那么可以省略{}。为了提高代码的易读性,建议不省略{}。
(2){}中的代码语句也称为代码块,在代码块定义的常量或变量的作用域仅限于代码块中,在代码块之外不能使用。
3.1.2 switch语句
除了让语句外,switch 语句也是选择结构。switch 语句一般用于做一些精确值的判
所,其语法格式如下所示。
switch(变量){
case 值 1:
代码块 1;
break;
case 值 2:
代码块 2;
break;
case值 3:
代码块3;
break;
default:
代码块 n;
break;
}
switch语句会根据表达式的值从相匹配的case 标签处开始执行,一直执行到break处或者 switch 语句的末尾。如果 case 全都不匹配,则进入 default语句。
3.1.3 选择结构的嵌套
选择结构在使用上可以嵌套,if中的代码块也可以是switch 语句,switch 语句中的代码也可以是if语句。通过嵌套,可以判断更加复杂的逻辑。
3.1.4 两种选择结构的对比
if语句和 switch语句都可以实现逻辑判断,但它们的使用场景有所不同。if语句一使用于区间值的判断,而switch 语句只能用于确定值的判断。凡是switch 语句能够实现的、if语句都可以实现,反之则不行。
3.2循环结构
3.2.1 for语句
循环结构是 Java三大结构之一,它可以在满足某些条件下一直执行某一段程序,从而简化代码。
for循环是最常见的循环结构,它的语法格式如下,
for(循环初始化表达式;循环条件表达式;循环后的操作表达式){
//循环体
}
首先执行一次循环初始化表达式,接着判断循环条件表达式,如果为 false, 则结束循环。如果为 true, 则执行循环体,之后执行循环后的操作表达式,重复以上操作,直到条件表达式的值为 false 为止。
3.2.2 while语句
while语句相较于 for循环更加简单,它的语法格式有点类似于if语句,如下所示。
while (条件表达式){
//循环体
}
while语句的执行规则也很简单,只要条件表达式的值为true, 就会执行循环体,直到条件表达式的值为 false时才退出循环。while 循环一般用于不确定循环次数的场景。
3.2.3 do…while语句
不管是for 循环还是 while 循环,都会在循环之前判断循环条件,如果条件刚开始就为false,那么循环体就不会被执行。实际开发中,可能存在需要循环体至少执行一次的场景,此时就可以使用 do…while 循环语句。do...while语句的语法格式如下所示。
do{
//循环体
}while(条件表达式);
首先执行循环体,之后再判断条件表达式,如果结果为 true, 就重复上述步骤,直到条件表达式的值为 false为止。do…while语句的语法比较简单,但需要注意的细节是条件表达式最后有一个分号。
3.2.4 break和continue语句
在任何循环语句的主体部分,均可用 break 控制循环的流程。break 用于强行退出循环,不执行循环中剩余的语句。而 continue 则只能终止某次循环,继续下一次循环。
3.2.5 循环语句的嵌套
同选择结构一样,循环结构也可以任意嵌套。
3.2.6 三种循环语句的应用场景
三种循环在任何场景下都是可以互相替换的,但实际开发中应当根据合适的需求场景选择不同的循环语句。如果能够确定循环次数,建议使用for循环;如果不能确定循环次数,或者想让循环永远执行,建议使用 while 循环;如果想让循环体至少执行一次,建议使用while 循环。
四、数组
4.1数组概述
数组就是一种能够存放相同数据类型的有序集合,或者说它是一个存储数据的容器。
在JAVA中,数组的创建方式分为三种,语法格式如下。
//方式一、创建出指定长度的数组,数组有多长,就能存储多少数据
数据类型[ ] 数组名= new 数据类型[数组长度];
//方式二、创建数组的同时向数组中存储数据,此时不需要指定数组长度,有多少元素则数组就多 //长
数据类型[ ] 数组名=nev 数据类型[ ]{元素1,元素2, .…,};
//方式三、方式二的简写方式
数据类型[ ] 数组名={元素1,元素 2, 元素 3 …};
其中数据类型可以是任意的基本数据类型和引用类型。
4.2数组的常见操作
4.2.1通过索引操作元素
数组元素的操作都是通过索引(也称作下标)进行的,当创建了一个长度为n的数组后,它的索引范围是[0, n-1]。
4.2.2数组的遍历
当数组元素很多时,不可能一个一个使用索引获取元素,而是希望能够通过循环的方式取出数组中的每一个元素,这个操作称作遍历。
4.2.3获取数组的最值
当需要获取数组的最大值或最小值时,通过常规的思路可能不太好处理,此时可以使用“假设法”。首先假设索引0处的元素是最大值,之后遍历整个数组,每次遍历取出当前元素与所假设的最大值进行比较,如果当前元素比假设的最大值还大,就再假设该元素是最大值,直到数组遍历完毕为止,最后所假设的最大值就是真正的最大值。
4.2.4通过值获取索引
有时可能需要查询数组中某个值所在的索引位置,这个操作也可以通过遍历实现,但需要注意,待查找的值可能在数组中不存在,因此需要先假设待查找值的索引为-1。因为-1这个值不可能是数组的索引,因此当遍历结束后如果索引还是-1,就说明没有找到该值。
4.2.5数组元素的反转
有时候可能需要反转一个数组,将数组元素首尾互换,这可以借助一个新的数组。
4.3数组的排序方法
4.3.1冒泡排序
冒泡排序的核心思想是,在要排序的序列中,对当前还未排好序的全部元素,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的数往上冒,就好像水泡上浮一样,如果它们的顺序错误,就把它们交换过来。代码如下。
package com.yyds.unit2.demo;
public class Demo31ArraySort {
public static void main(String[ ] args){
int[ ] arr = new int[ ](10, 5, 12, 13, 7, 4, 2, 15,9);
bubblesort(arr);
System.out.printlIn(”排序后数组为:");
for(int num: arr){
System.out.print(num + " ");
}
}
public static void bubblesort(int[ ] arr) {
//外层循环控制趟数
for(int i= arr.length - 1;i> 0;i--){
//节点比较,只比较到第i个元素即可
for(int j= 0;j< i;j++){
//交换元素
if(arr[j]> arr[j + 1]){
int temp = arr[j];arr[j]= arr[j+ 1];arr[j+ 1] = temp;
}
}
}
}
}
运行结果:排序后数组:2 4 5 7 9 10 12 13
4.3.2选择排序
选择排序的核心思想是:在要排序的一组数中选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数中再找最小(或者最大)的与第2个位置的数交换,以此类推,直到第n一1个元素(倒数第2个数)和第n个元素(最后一个数)比较为止,每一轮排序都是找出它的最小值或者最大值的过程。代码如下。
package com.yyds,unit2.demo;
public class Demo32Arraysort {
public static void main(String[ ] args) {
int[ ]arr = new int[ ]{10, 5,12,13, 7, 4, 2, 15, 9};
selectSort(arr);
system.out.println("排序后数组为:");
for(int num: arr){
System.out.print(num+ " ");
}
}
public static void selectSort(int[ ] arr){
//毎次从剩下的元素中选择最小值放到第一个位置
for(int i= 0; i< arr.length - 1;i++){
//记录每一趟的最小值坐标
int min = i;
//寻找每一趟的最小值,先找到坐标,最后再交换,减少交换次数
for(int j= i+ 1;j < arr.length;j++){
if(arr[j]< arr[min]){
min= j;
}
}
//元素交换
if(min!= i){
int temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
}
}
}
运行结果:排序后数组:2 4 5 7 9 10 12 13
4.3.3二分查找法
前面通过遍历的方式查找元素所在的索引,这样虽然能够实现目标,但是当数组过大时性能可能偏低。而二分查找法是性能更高效的查找算法。二分查找法又称折半查找法,其算法思想是每次查找数组最中间的值,通过比较大小关系,决定再从左边还是右边查询,直到查找到为止。二分查找法的优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插人、删除操作困难。因此,折半查找法适用于不经常变动而查找频繁的有序列表。
4.4二维数组
二维数组的每一个元素都是一个数组,简单来说,二维数组就是“数组的数组”。创建二维数组的语法格式如下所示。
数据类型([ ][ ] 数组名=new 数据类型[m][n];
其中,m 表示这个数组的长度,n表示这个数组中每个元素的长度。创建二维数组时,n也可以不指定,后续动态创建。
4.5 Arrays工具类
Arrays是Java 中提供的操作数组的工具类,通过 Arrays类可以很方便地操作数组。
方法签名 | 描述 |
---|---|
static string toString(Type[ ] arr) | 按照特定的格式将数组转化为字符串 |
static boolean equals(Type[ ] arr1,Type[ ] arr2) | 比较两个数组中的所有内容是否相同 |
static void sort(Type[ ] arr) | 对数组元素进行排序 |
static int binarySearch(Type[ ] arr,Type value) | 二分法查找某个值在数组中的索引位置 |
package com.yyds.unit2.demo;
import java.util.Arrays;
public class Demo36Arrays (
public static void main(String[ ] args) {
int[ ] arr1 = new int[ ]{10, 5, 12, 13, 7, 4, 2, 15,9};
int[ ] arr2= {2,4, 5, 7, 9, 10,12, 13,15};
/ /直接使用 Arrays.方法名调用
System.out.printIn("排序前arrl:"+ Arrays.tostring(arr1));
Arrays.sort(arr1);
System.out.println("排序后 arr1:"+ Arrays.toString(arrl));
boolean equals = Arrays.equals(arrl, arr2);
System.out.printlIn("arr1与arr2 比较:"+ equals);
int index= Arrays.binarySearch(arrl,7);
System.out.printIn("元素7在arr1中的位置为:"+ index);
}
}
运行结果:排序前arr1:[10, 5,12,13, 7, 4,2,15,9]
排序后arr1:[2,4,5,7,9,10,12,13,15]
arr1与arr2比较:true
元素7在arr1中的位置为:3
面向对象
一、面向对象的概念
1.1什么是面向对象
面向对象将构成问题的事物分解成各个对象,这些对象是为了描述某个事物在整个问题解决步骤中的行为。 面向对象以对象为核心,强调事件的角色、主体,在宏观上使用面向对象进行把控,而微观上依然是面向过程,如果说面向过程的思想是执行者,那么面向对象的思想就是指挥者。
1.2面向对象的特性
面变对象具有抽象,封装,继承,多态的特性,更符合程序设计中“高内聚低耦合”的主旨,编写的代码的可维护性,可读性,复用性,可扩展性,远比面向过程思想编写的代码强,但是性能方向比面向过程要低一些。
- 封装:只隐藏对象的属性和实现细节,仅对外提供公共的访问方式。
- 继承:继承就是子类继承父类的特征和行为,使得子类对象具有父类的实例属性和方法或子类重复类继承方法,使得子类具有父类相同的行为。
- 多态:指的是同一个方法调用,由于对象不同可能会有不同的行为。
二、类
2.1类和对象
- 类:对某一类事物的描述,是抽象的、概念上的定义。类由数据成员(也称为属性、域变量、成员变量等)和函数成员(类的行为,也称方法)封装而成,类描述了对象的属性及行为。
- 对象:实际存在的属于该类事物的具体个体,因此也称实例。因一个对象由一组属性和对这组属性操作的方法构成,所以对象是属性和操作的封装体。
2.1.1类的定义
类主要由变量和方法组成
- 变量:修饰符 变量类型 变量名 = [默认值];
- 方法:修饰符 返回值类型 方法名(形参列表){ }
2.1.2对象的创建
类名称 对象名称 = new 类名称( );
2.2构造方法
2.2.1构造方法概念
构造方法也称作构造器,用于给对象进行初始化操作,即为对象成员变量付出是指构造方法的名称必须与类型相同,并且不能定义返回值,不能出现return关键字,构造方法的调用必须通过new关键字调用。
定义格式:修饰符 类名(形参列表){ }
2.2.2构造方法的使用
默认情况下,当系统没有委内提供一个构造方法是只能使用默认的无参构造方法创建对象。
2.2.3构造方法的重载
三、关键字
3.1常用关键字
1:this:表示当前对象
2:super:表示父类的引用
3: static:静态的
4: final:最终的
5:instanceof:表示某个对象是否是本类或本类的子类的对象
6:extends:表示继承
7: abstract:抽象
8: package:包
3.2super与this对比
区别点 | this | super |
---|---|---|
引用 | this代表本类对象的使用 | super代表父类存储空间 |
调用方法 | this.属性,this.方法,this() | super.属性,super.方法(),super() |
调用构造方法 | 调用本类构造方法放在第一条语句 | 调用父类构造方法放在第一条语句 |
查找范围 | 先从本类找,找不到,则查找父类 | 直接查找父类 |
四、Object类
方法签名 | 方法描述 |
---|---|
String toString() | 返回该对象的字符串表示形式 |
boolean equals(Object obj) | 判断两个对象的地址是否相同 |
native int hashCode() | 返回该对象的哈希码值 |
final native Class<?> getClass() | 得到一个对象或者类的结构信息 |
final void wait() | 使当前线程进入等待 |
final native void notify() | 唤醒一个等待的线程 |
五、抽象类
格式:权限修饰符 abstract class 类名{}
权限修饰符 abstract 返回值类型 方法名(参数列表);
注:
- 抽象方法只有方法声明,没有方法体,它必须交给子类重写。子类重写抽象方法,也称作“实现”抽象方法。
- 子类如果也是抽象类,则不一定需要实现父类的抽象方法,而如果不是抽象类,则必须实现父类中所有的抽象方法。
- 抽象方法必须被子类重写,因此抽象方法的访问修饰符不能是private.
- 由于抽象方法没有具体的方法体,无法用一个抽象的对象调用它,因此抽象类不能被实例化。
- 抽象类可以有构造方法,它的构造方法的作用是便于子类创建对象时给抽象类的属性赋值。
六、内部类
6.1成员内部类
定义格式:
class 外部类{
修饰符 class 内部类{
}
}
外部类名.内部类名 变量名 = new 外部类名(实参列表).new 内部类名(实参列表);
6.2静态内部类
class 外部类{
修饰符 static class 内部类{
}
}
外部类名.静态内部类名 变量名 =new外部类名.静态内部类名(形参列表);
6.3局部内部类
class 外部类{
修饰符 返回值类型 方法名(参数列表){
class 内部类{ //其他代码
}
}
}
6.4匿名内部类
new接口() | 父类(){
//其他代码
}