第二章 Java语言基础
2.1 关键字
- 被赋予特殊含义的单词,关键字都是小写
2.2 标识符
- 在程序中自定义的一些名称。
- 由26个英文字母大小写,数字:0-9 符号:_$组成。
- 定义合法标识符规则:
1,数字不可以开头。
2,不可以使用关键字。 - Java中严格区分大小写。
- 注意:在起名字时,为了提高阅读性,要尽量有意义
2.3 注释
- 对于单行和多行注释,被注释的文字,将会被Java编译器忽略,不会被JVM解释执行
- 对于文档注释,是java特有的注释,其中注释内容可以被JDK提供的工具javadoc所解析,生成一套以网页文件形式体现的改程序的说明文档。
- 注释是一个程序员必须要具有的良好变成习惯。
- 初学者编程可以养成习惯:先写注释再写代码。
例:
/*
需求:练习一个hello world程序。
思路:
1,定义一个类,因为Java程序都定义在类中,java程序都是以类的形式存在的,类的形式其实就是一个字节码文件最终体现。
2,定义一个主函数。为了让该类可以独立运行。
3,因为演示hello world,在控制台上看到该字样,所以需要使用输出语句完成。
步骤:
1,用class关键字来完成类的定义,并起一个阅读性强的类名。
2,主函数:public static void main(String[] args)这是固定格式的。JVM认识。
3,使用输出语句:System.out.println("hello world");
*/
class Demo
{
//定义一个主函数,为了保证程序的独立运行。
public static void main(String[] args)
{
System.out.println("Hello World!");//这是输出语句,用于将括号中的数据打印到控制台上,ln可以在数据的结尾处换行。
}
}
将自己的思想通过注释先整理出来,再用代码去体现。
因为代码仅仅是思想的一种体现形式而已。
用于注解说明解释程序的文字就是注释
提高了代码阅读性
- 注释可以进行程序的调试
格式:
单行注释
//这是许多程序语言通用单行注释
多行注释
/这是许多
程序语言
通用多行注释/
文档注释
/** 文档注释。
Java语言独有 */
2.4 常量和变量
常量
-
常量表示不能改变的数值。
-
Java中常量分类:
1,整数常量。所有整数
2,小数常量。所有小数
3,布尔(boolean)型常量。较为特有,只有两个数值。true false。
4,字符常量。将一个数字字母或者符号用单引号(’ ')标识。
5,字符串常量。讲一个或者多个字符用双引号(" ")标识。
6,null常量。只有一个数值就是:null。 -
对于整数:有四种表现形式。
-
二进制:0,1,满2进1。byte 字节=8个二进制位(bit位),1KB=1024byte;1MB=1024KB;1GB=2014MB;1TB=1024GB。
负数的二进制表现形式:对应的正数二进制取反加1。负数的二进制最高位是1 -
八进制:0-7,满8进1。用0开头表示。八进制数,其实就是3个二进制位为1个八进制位。如023。
-
十进制:0-9,满10进1。
-
十六进制:0-9,A-F,满16进1。用0x开头表示。十六进制数,其实就是4个二进制位为1个十六进制位。如0x23。
-
一个整数在内存中是用4个字节来表示,如6在内存中表示为0000-0000 0000-0000 0000-0000 0000-0110,-6为6对应的二进制数取反加1,1111-1010
变量
- 变量的概念:
- 内存中的一个存储区域
- 该区域有自己的名称(变量名)和类型(数据类型)
- 该区域的数据可以在同一类型范围内不断变化
- 为什么要定义变量:
- 用来不断的存放同一类型的常量,并可以重复使用
- 使用变量注意:
- 变量的作用范围(一对{}之间有效)
- 初始化值
- 定义变量的格式:
- 数据类型 变量名=初始化值;
- 注:格式是固定的,记住格式,以不变应万变。
- 理解:变量就如同数学中的未知数。
数据类型
- Java语言是强类型语言,对于每一种数据都定义了明确的具体数据类型,在内存总分配了不同大小的内存空间。
- 整数默认:int 小数默认:double(双精度浮点数)
- byte 数据类型是8位、有符号的,以二进制补码表示的整数,范围-128(-27)~127(27-1),默认值是0;
- short 数据类型是 16 位、有符号的以二进制补码表示的整数,范围-32768(-215)~32767(215-1),默认值是0;
- int 数据类型是32位、有符号的以二进制补码表示的整数,范围-2,147,483,648(-2^31)~ 2,147,483,647(2^31 - 1),默认值是0,一般整形变量默认为int类型;
- long 数据类型是 64 位、有符号的以二进制补码表示的整数,范围-9,223,372,036,854,775,808(-2^63)~ 9,223,372,036,854,775,807(2^63 -1),默认值是0L("L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。);
- float 数据类型是单精度、32位、符合IEEE 754标准的浮点数,默认值为0.0f;
- double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数,默认值为0.0d;
- boolean数据类型表示一位的信息,只有true和false两个取值,默认值为false;
- char类型是一个单一的16位Unicode(国际统一编码表)字符,范围\u0000(即为0)~\uffff(即为65535),char数据类型可以储存任何字符,可以根据ASCII码(American Standard Code for Information Interchange,美国信息交换标准代码)转换成数值后运算,如’A’=65, ‘a’=97;
- 自动类型转换(也叫隐式类型转换)
- 整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。
- 转换从低级到高级。
如:int x = 3;
byte b = 5;
x = x + b; / /此时byte会自动提升为int,并与int相加得出结果 - 强制类型转换(也叫显式类型转换)
- 条件是转换的数据类型必须是兼容的。
- 格式:(type)value type是要强制类型转换后的数据类型
如:byte b = 3;
b = (byte)(b+4); //强制类型转换。 - 类型转换的原理
- 什么时候要用强制类型转换?
- 表达式的数据类型自动提升
- 所有的byte型、short型和char的值将被提升到int型;
- 如果一个操作数是long型,计算结果就是long型;
- 如果一个操作数是float型,计算结果就是float型;
- 如果一个操作数是double型,计算结果就是double型。
- 分析
- System.out.println(‘a’)与System.out.println(‘a’+1)的区别。
面试题:
为什么以下代码运行时报错?
byte b = 4;
//若给定条件b = 3+7; <font color=#FF4500 size=3>3+7是常量</font>,可以赋值给b,因此run ok。
byte b1 = 3;
byte b2 = 7;
b = b1 + b2;
//b1和b2是变量,b为byte类型,如b1+b2的值超过-128~127范围则不能赋予b,因此run会报错可能丢失精度。
System.out.println(b);
2.5 运算符
算术运算符
- 有四个:+ - * /
% 取余,模运算,如5%2读作“五模以二”,结果为1,结果正负只参考被模数,如5%-2=1,-5%2=-1。
+(连接符) 用于连接字符串,连接符两端都是字符串,如System.out.println(“5+5=”+5+5)输出为5+5=55,若改为System.out.println(“5+5=”+(5+5))输出为5+5=10。
++ 自增 a++; //a=a+1;
难点:
int i = 3;
i++; //i = i + 1;
System.out.println("i= "+i); //i++等价于i=i+1,结果为i=4。
int i = 3 ;
i = i++; //temp = i;
i = i + 1;
i = temp; //即先赋值,后运算。
System.out.println("i=" + i ); //结果为i=3。
int i = 3 ;
i = ++i; //i = i + 1;
temp=i;
i = temp; //即先运算,后赋值。
System.out.println("i=" + i ); //结果为i=4。
- 自减
这里除法/需特别注意,java是强类型语言,两个整数运算后仍是整数。
例:
int x = 6370;
x = x/1000*1000;
System.out.println(x); //这里输出结果是6000,因为6370/1000=6.37,而结果类型为int整型,所以实际结果等于6,6*1000=6000。
赋值运算符
- =
- +=
int a = 4;
a+=2; //a = a + 2; 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数
- -= 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数
- *= 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数
- /= 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数
- %= 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数
面试题:
1 short s = 3;
2 s+=4;
3 s = s + 4;
问:2&3有什么区别?
答:short在内存中占两个字节,整数默认类型为int,占4个字节,第3行s为变量,如果s取值较大+4,会超出short范围,则右边s+4不能赋予左边short类型的s。因此若用第三行编译会报错可能精度丢失。若用第2行不会报错,因为第2行+=是加和赋值操作,是一次运算,第3行是两次运算,先求和,再赋值,+=会有一个底层自动强转的过程,而第3行不会做自动强转。其实本题中s+=4;应该等价于s = (short) (s + 4);。
比较运算符
- 比较运算符的结果都是boolean型,也就是要么是true,要么是false
- 比较运算符“==”读作等等于,不能误写成“=”
逻辑运算符
- 用于连接两个boolean类型的表达式
- & 运算两边只有有一个是false,结果肯定是false,只有两边都为true,结果才是true
- | 运算两边只要有一个是true,结果肯定是true,只有两边都为false,结果才是false
- ^ 异或两边结果如果相同,结果是false,两边的结果不同,结果是true。一个数异或同一个数两次,结果还是这个数。利用该特性可以用于加密
- ! 逻辑非运算符。用来反转操作数的逻辑状态
面试题:
- && (短路) 只要左边为false,右边不进行运算直接得出false,类似电路中的短路(与&区别,&不管左边什么结果右边都运算),与&运算结果一样,但是运算过程有区别
- ||(短路)只要左边为true,右边不进行运算直接得出true,类似电路中的短路(与|区别,|不管左边什么结果右边都运算),与|运算结果一样,但是运算过程有区别
###位运算符
- 位运算是直接对二进制进行运算
- 位运算可以使运算高效
- a << b = a * 2b; 如3<<2 = 3 * 22 = 12。
- a >> b = a / 2b;
-
无符号右移:数据进行右移时,高位出现的空位,无论原高位是什么,空位都用0补
三元运算符
- 格式
- (条件表达式)? 表达式1 : 表达式2
- 如果条件为true,运算后的结果是表达式1
- 如果条件为false,运算后的结果是表达式2
- 三元运算符就是if else语句的简写格式,当if else运算后,有一个具体的结果时,可以简化为三元运算符
- 示例:
- 获取两个数中大数。
int x=3,y=4,z;
z = (x>y)?x:y; //z变量存储的就是两个数的大数
2.6 程序流程控制
判断结构
if 语句
- 注意:上述三种格式均为单条语句,if(条件表达式)后面紧跟"{",没有";"。
- 大括号"{}“里面的内容根据前面的内容命名,如class后面紧跟的”{}“中的内容叫做类代码块,
public static void main后面大括号”{}“中的内容叫做主函数代码块,如果”{}“前面什么都没有,那么”{}"中的内容称为局部代码块。局部代码块的功能:限定局部变量的生命周期(作用域)。
选择结构
switch语句
- 格式:
switch(表达式) //只有byte, short, int, char.四种类型可以选择
{
case 取值1: //注意是冒号":"
执行语句;
break; //如果符合,跳出
case 取值2:
执行语句;
break;
……
default: //缺省、默认,即其他情况
执行语句;
break;
}
- if和switch的区别:
- if:
1,对具体的值进行判断
2,对区间的判断
3,对运算结果是boolean类型的表达式进行判断 - switch(相比if而言并不常用):
1,对具体的值进行判断。对于几个固定值的判断,建议用switch语句,因为switch 语句会将具体答案都加载进内存。
2,值的个数通常是固定的
循环结构 (loop)
while循环
- 格式:
while (条件表达式)
{
执行语句;
}
Tips: ctrl + c终止控制台运行
do…while循环
- 格式:
do
{
执行语句;
}while(条件表达式);
- do…while语句的特点:无论条件是否满足,循环体至少执行一次。
for循环(重要!)
- 格式:
for (初始化表达式; 循环条件表达式(即boolean表达式); 循环后的操作表达式)
{
执行语句; //循环体
}
-
for循环执行的次数是在执行前就确定的。
-
执行顺序:1~8
-
for和while的特点:
1,for和while可以互换
2,格式上的不同,在使用上有点小区别。
如果需要通过变量来对循环进行控制,该变量只作为循环增量存在时,区别就体现出来了。 -
什么时候使用循环结构?
当对某些代码执行很多次时,使用循环结构完成。
当对一个条件进行一次判断时,可以使用if语句。
当对一个条件进行多次判断时,可以使用while语句。
注意:在使用循环时,一定要明确哪些语句需要参与循环,哪些不需要。
循环通常情况下,需要定义条件,需要控制次数。 -
嵌套语句结构
-
大圈套小圈思想:对于一种重复的情况中的每一次重复都对应另一种情况的多次重复。
-
例子:
for (int x = 0;x<3 ;x++ )
{
for (int y=0;y<4 ;y++ )
{
System.out.println("ok");
}
}
- 分析:外循环每循环1次,内循环循环4次,总共循环3*4=12次。
- Tips:
- ":双引号:如输出带双引号的hello world则应输入System.out.print( ““hello world””);
- \n:换行符
- \t:制表符
- \b:退格
- \r:按下回车键
- 在Windows系统中回车符其实是由两个符号组成的:\r\n
- 在Linux系统中回车符是:\n
其他流程控制语句
- break(跳出),continue(继续)
- break语句应用范围:选择结构和循环结构
- continue语句应用范围:循环结构
- 这两个语句离开应用范围,存在时没有意义的
- 这两个语句单独存在下面都不可以有语句,因为执行不到
- continue语句是结束本次循环继续下次循环
- 标号的出现,可以让这两个语句作用于制定的范围
2.7 函数
函数的定义
- 函数就是定义在类中的具有特定功能的一段独立小程序
- 函数也称为方法
- 函数的格式
修饰符 返回值类型 函数名(参数类型 形式参数1, 参数类型 形式参数2, ...)
{
执行语句;
return 返回值;
}
- 函数名写作规范:首字母小写,若有多个单词则除第一个词以外其他词首字母大写
- 返回值类型:函数运行后的结果的数据类型
- 参数类型:是形式参数的数据类型
- 形式参数:是一个变量,用于存储调用函数时传递给函数的实际参数
- 实际参数:传递给形式参数的具体数值
- return:用于结束函数
- 返回值:该函数运算后的结果,该结果会返回给调用者
函数的特点
- 定义函数可以将功能代码进行封装
- 便于对该功能进行复用
- 函数只有被调用才会被执行
- 函数的出现提高了代码的复用性
- 对于函数没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的return语句如果再最后一行可省略不写
- 注意:
1, 函数中只能调用函数,不可以在函数内部定义函数
2, 定义函数时,函数的结果应该返回给调用者,交由调用者处理
函数的应用
- 例子:需求:定义一个功能,完成两个整数的和的获取
- 思路:既然定义功能,就是可以用函数来体现
- 通过两个明确来完成。
- 明确一:这个功能的结果是什么?
是和。是功能的结果,所以该功能的返回值类型是int
其实就是在明确函数的返回值类型 - 明确二:这个功能实现过程中是否需要未知内容参与运算?
有,加数和被加数。这就是函数的参数列表(参数的个数,参数的类型)
其实就是在明确参数列表 - 注意:返回值类型和参数类型没有直接关系。
- 函数示例:
public static int add(int a,int b)
{
int sum = a+b;
return sum;
}
函数的重载(overload)
- 概念:在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不同即可。
- 特点:与返回值类型无关,只看参数列表
java是严谨性语言,如果函数出现调用的不确定性,会编译失败 - 好处:提高阅读性,优化程序设计
- 示例:
//返回两个整数的和
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;}
2.8 数组
前言
- 学习任何程序语言,具有容器功能的程序都应作为重点学习。
- 如果数据出现了对应关系,而且对应关系的一方是有序的数字编号。并作为角标使用,这时就必须要想到数组的使用
数组的定义
-
概念:同一种类型数据的集合。其实数组就是一个容器
-
好处:可以自动给数组中的元素从0开始编号,方便操作这些元素
-
格式1:
元素类型[] 数组名 = new 元素类型[元素个数或数组长度];
int[] arr = new int[5];
使用情况:需要一个容器,但是不明确容器中的具体数据
-
格式2:
元素类型[] 数组名 = new 元素类型[]{元素,元素,…};
int[] arr = new int[]{3,5,1,7};
int[] arr = {3,5,1,7};//也可以简写为此行
使用情况:需要一个容器,存储已知的具体数据
数组的内存分配及特点
-
寄存器
-
本地方法区
-
方法区
-
栈内存
内存分配:存储的都是局部变量,而且变量所属的作用域一旦结束,该变量就自动释放
特点:生命周期短,更新速度快 -
堆内存
内存分配:存储的是数组和对象(其实数组就是对象)。凡是new建立的都在堆中
特点:
1,每一个实体都有首地址值 (C++中的指针,即Java中的引用)
2,堆内存中的每一个变量都有默认初始化值,根据类型的不同而不同。整数是0,小数0.0f,boolean false,char ‘\u0000’
3,垃圾回收机制
数组常见操作
- 对数组操作最基本的动作就是存和取
- 核心思想:对角标的操作
- 遍历:arr.length 表示数组的长度
System.out.println("length:"+arr.length);
for (int x=0;x<arr.length ;x++ )
{
System.out.println("arr["+x+"] = "+arr[x]+";");//输出效果:arr[0] = 89;
}//数组的正向遍历
- 获取最值(最大值,最小值)
- 排序(选择排序,冒泡排序)
//选择排序
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++ )
{
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++ )
{
for (int y=0;y<arr.length-1-x ;y++ )
{
if (arr[y]>arr[y+1])
{
int temp = arr[y];
arr[y] = arr[y+1];
arr [y+1] = temp;
}
}
}
}
注意:以上代码面试使用,其实java中已经做好了排序功能,输入以下代码:
import java.util.*; 然后在主函数中输入Arrays.sort(arr); 即可自动对指定数组进行排序,此方法适合实际开发时使用
- 折半查找(二分查找)
public static int halfSearch(int[] arr,int key)
{
int max,min,mid;
min = 0;
max = arr.length-1;
mid = (max+min)/2;
while (arr[mid]!=key)
{
if (key>arr[mid])
{
min = mid + 1;
}
else if (key<arr[mid])
{
max = mid - 1;
}
if (max<min)
{
return -1;
}
mid = (max+min)/2;
}
return mid;
}
注意:以上代码面试使用,其实java中已经做好了二分查找功能,输入以下代码:
import java.util.*; 然后在程序中输入Arrays.binarySearch(arr,x); 即可自动对指定元素x进行二分查找。如果元素x在数组arr[]中存在,返回具体角标;如果不存在,返回的是 -插入点-1。此方法适合实际开发时使用
Integer.toBinaryString(x); //将十进制数x转化为二进制
Integer.toHexString(x);// 将十进制数x转化为十六进制
Integer.toOctalString(x);// 将十进制数x转化为八进制
数组中的数组
- 二维数组[][]
- 格式1:
int[][]arr = new int[3][2];
定义了名称为arr的二维数组
表示该二维数组中有3个一维数组
每一个一维数组中有2个元素
一维数组的名称分别为arr[0],arr[1],arr[2]
给第一个一维数组1脚标位赋值为78的写法是:arr[0][1] = 78;
- 格式2:
int[][]arr = new int[3][];
二维数组中有3个一维数组
每个一维数组都是默认初始化值null
可以对这个三个一维数组分别进行初始化
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];
int[][] arr = new int[3][];
System.out.println(arr);//直接打印二维数组 结果:[[I@61064425 @左边[[表示二维数组
System.out.println(arr[0]);//直接打印二维数组中的角标0的一维数组 结果:null
System.out.println(arr[0][0]);//直接打印二维数组中的角标0的一维数组中角标为0的元素 结果:NullPointerException
二维数组内存图解
也可以写成int[][] arr = {{3,1,7},{5,8,2,9},{4,1}};
编辑器:EditPlus
蓝色:关键字
红色:Java创建好的类
2.9 基本语法
- 编写Java程序时,应注意以下几点:
- 大小写敏感:Java是大小写敏感的,这就意味着标识符Hello与hello是不同的。
- 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。
- 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
- 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记Java是大小写敏感的),文件名的后缀为.java。(如果文件名和类名不相同则会导致编译错误)。
- 主方法入口:所有的Java 程序由public static void main(String []args)方法开始执行。