JAVA基础语法
1.JAVA概念
1.1JAVA和C的区别
- 跨平台
- 面向对象
- 健壮 安全性(无需自己生成内存、无指针)
- 分布式 高效(初始JAVA未经优化)
- 多线程 结构中立(独立于操作系统)
- open sourse
1.2JAVA的跨平台性
- JAVA运行在虚拟机上,而不是运行在物理机,因此可移植性强。代价就是JVM是不跨平台的。
1.3JDK和JRE
- JRE(Java Runtime Environment)
- JDK
配1.4置环境变量
- path环境变量,相对路径写法,新建一个目录路径的定义,告诉操作系统javac可执行程序的位置
- classpath,告诉JVM加载字节码文件的位置
2.关于IDEA
- Project是工程的工作空间,Module是具体的一个个工程。
- JAVA源代码必须放在JAVA源目录中(source root)
- git更新,更新module
3.标识符
注意,不能是数字开头
3.1约定俗成的命名规则
3.1.1包的命名
- 单级包全部小写
- 多级包域名反转(保证了包名的唯一性)是虚拟的域名反转
例: com.cskaoyan.name
3.1.2类和接口的命名
- 一个单词 首字母大写,其他字母小写
- 多个单词 大驼峰式
3.1.3变量和方法的命名
- 一个单词 全部小写
- 多个单词 小驼峰式
3.1.4常量的命名
- 一个单词 全部大写
- 多个单词 全部大写,单词间下划线分隔
4.注释
- 单行 //
- 多行 /* */
- 文档 /** */
5.常量
5.1 进制
- 二进制 0b11
- 八进制 0b11
- 十进制 11
- 十六进制 0x11
6.变量
变量就是一片小的存储空间
6.1.数据类型
一定范围内的数据集合,和对数据集合的合法操作
- 基本数据类型
- 整数型 byte,short,int(默认),long
- 小数型 float,double(默认)
- 字符型
- 布尔型
- 引用数据类型
6.2.注意事项
-
作用域
变量有一定的生命周期,只在它所在的作用域中才有意义,作用域即变量所在的{}- 一旦超出了变量定义的作用域,就访问不到了
- 在包含关系的作用域中不能出现重名的情况
-
初始值
变量在使用之前,必须赋初始值 -
数据类型转化
- 隐式类型转化
- 不同数据类型运算时,JVM会先将数据转化成同一类型,具体是把范围小的数据类型转换成范围大的
- boolean类型不能直接转化为其他类型
- byte,short,char类型之间不会直接转化,而是以int类型的身份进行计算
- 强制类型转化
格式:目标类型 变量名=(目标类型)被转换的数据
数据精度可能会丢失
因此,声明float类型时,需要在数值后面加上f
float f = 0.5F; long l = 99999999999L;//最好不要用小写l byte b = 1 + 2;//编译器进行了优化,因为是直接的常量计算,编译器会预先计算好结果,并检查是否在相应的数据类型所能取值的范围内t
- 隐式类型转化
7.运算符
7.1 算数运算符
- +
+ 数值加法
+ 正号
+ 字符串拼接 - - * /
- %
- ++ --(以++为例说明)
建议不要在表达式中使用自加自减,容易出现bug- 单独运算时,++的位置在何处都不会有影响
- 参与其他运算
- c++ 先参与运算再自增
- ++c 先自增再参与运算
7.2 赋值运算符
- += 复合运算包含强制类型转换
7.3 关系运算符
结果是布尔类型,是或否
==, !=, <, >, <=, >=
7.4 逻辑运算符
&, |, !, ^(异或), &&, ||, ?:
&与&&,|与||的差别:&和|不太聪明,必须要执行完两侧运算才能进行逻辑运算,而&&不需要,比如第一个为false的话,另一个就不运算了
7.5 位运算符
- 移位 移位移的补码
- 左移
空位补零,高位丢弃 - 右移
- 带符号右移 >> 相当于除以二
- 无符号右移 >>> 只有正数才是除以二
- 左移
- 与,或,异或
- ~:所有位取反
变量交换的方式
1.定义中间变量
2.计算技巧int a,b; a = a + b; b = a - b; a = a - b;
3.异或运算
int a,b; a = a ^ b; b = a ^ b; a = a ^ b;
4.神头鬼脸
int a,b; a = (a + b) - (b = a);
8.流程控制
作用域
变量有一定的生命周期,只在它所在的作用域中才有意义,作用域即变量所在的{},一旦超出了变量定义的作用域,就访问不到了。在包含关系的作用域中不能出现重名的情况
8.1 顺序结构
8.2 选择结构
- if
- if else
- if else if else
- switch
switch(choice){
case 1:
...;
break;
case 2:
...;
break;
default://other value
...;
break;
}
删除break语句在语法上没有错误,但是在当前case分支中的语句执行完后,而是继续执行相邻case分支中的语句
当然,并不是说这样不好,相反,有时候我们利用这种结构会减少所需要使用的代码量
case的标签可以是:
类型为char,byte,short,int的常量表达式
枚举常量
字符串字面量(Java7开始)
8.3 循环结构
循环控制变量贯穿始终
循环结构的四种基本语句
- 初始化语句
- 条件判断语句
- 循环体语句
- 循环控制语句
-
while
先检测循环的条件 -
do statement while(condition)
先执行语句再检测循环条件 -
for
不成文的规矩:对同一个变量进行初始化、检测和更新
建议不要使用浮点数判断相等条件,因为浮点数是近似值,有可能永远不满足条件 -
带标签的break
和C++的goto类似,只能跳出语句块,而不能跳进语句块。当然,不建议使用。
read_data:
...
while(condition){
...;
if(condition2)
break read_data;
}
-
continue
跳过本轮循环,进入到下一轮循环 -
return
方法的结束语句,具体内容在方法中展开
9.大数
如果基本的整数和浮点数不能满足需求,java.math中有两个很有用的类:BigInteger(任意精度整型运算)和BigDecimal(任意精度浮点数运算)。
如果需要进行算术运算,需要调用大数对象的方法。
具体的方法可以去Oracle官方网站查找API文档
BigInteger c = a.add(b);//c=a+b
BigInteger d = c.multiply(b.add(BigInteger.valueOf(2)));//d=c*(b+2)
10.数组
10.1 声明数组
- 动态初始化
int[] a = new int[100];//声明并初始化一个容量大小为100个整型变量的数组
//a = 数组的首地址(相当于C++的&a[0])称之为引用变量
a = [I@4554617c//[是一维数组,@无实际意义,后面的字符串是数组首地址
- 静态初始化
初始化时,创建数组后就给就给数组初始化,之后再用给定的值覆盖原来的值
int[] a = {2,3,4};
smallPrimes = new int[] {2,3,4};//标准写法
//等价于
int[] anonymous = {2,3,4};//简化写法,只在数组定义时能用
Java中允许有长度为0的数组,但是和null并不等价
new elementType[0]; 或者 new elementTypr[] {};
10.2 访问数组元素
根据数组下表访问数组,和C++一样
10.3 for each循环
for(variable : collection) statement;
联想:Python中的for file in files:
variable变量用于暂存数组collection中的变量值
10.4 数组拷贝
Arrays的copyOf方法
10.5 命令行参数
public static void main(String[] args)
表明main方法将接收一个字符串数组,也就是命令行指定的参数,和C++不同,程序名没有存储在args数组中,命令行参数的第一个字符串即为args[0]。
10.6 多维数组
double[][] balances;//声明
balances = new double[NYEARS][NRATES];初始化
int [][] magicSquare =
{
{1,2},
{3,4},
{5,6}
};
for each循环不能自动处理二维数组中的每一个变量,需要使用两次:第一次是访问每一个数组,第二次是访问第一次访问数组中的每一个数组元素
Arrays.deepToString(a)
可输出二维数组的数据元素列表
Java实际上没有二维数组,因此可以根据自己需要,使用不规则数组
10.7 常见错误
- 数组索引越界
访问数组中不存在的元素而引发的操作 - 空指针错误
访问了内存中不存在的东西而引发的错误(null代表不存在的内存地址)
11.方法
11.1 概念
-
有返回值的方法
形式参数和实际参数
不管参数是什么类型,实参和形参的传递方式只有一种:实际参数的值复制给形式参数,在方法体内参与运算后将结果返回到方法的返回值;因此实参的值有两份,调用方法中一份,被调用方法中有一份。参数类型是基本数据类型:值传递
参数类型是引用数据类型(如数组):引用传递 -
无返回值的方法
11.2 方法重载
一个类定义多个同名方法是没有问题的,方法重载需要遵守一定的规则:
- 参数个数不同
- 参数类型不同
- 参数顺序不同(是参数类型的顺序)
Java区分方法的原理:
方法签名:方法名+形式参数列表 不会考虑方法返回值
方法重载便利了方法的调用,但不能忽视方法的定义
11.3 注意事项
- 方法需要调用才能使用
- 方法不能嵌套定义
- 参数用逗号隔开
- 注意返回值
11.4 递归
11.4.1 递归方法
概念:方法定义中调用方法的本身,后调用的方法先执行完
- 注意事项:
+ 不能缺少递归出口
+ 递归调用次数不能太多,否则可能造成栈溢出
11.4.2 递归算法
11.4.2.1 汉诺塔
搬运N个圆盘:分解成1个圆盘和N-1个圆盘的搬运
理解递归算法的关键是得到递推关系并将递推关系表达出来
11.4.2.2 不死神兔
/*
有一对兔子,从第三个月开始每个月生一对兔子,生出来的兔子也在第三个月生兔子,假设兔子不死,20个月一共有多少兔子
观察连续三个月的兔子数量,可以得到递推关系式M(n) = M(n - 1) + M(n - 2)
*/
public static int getMountOfRabbit(int month){
if (month == 1 || month == 2) {
return 1;
}
return getMountOfRabbit(month - 1) + getMountOfRabbit(month - 2);
}
11.4.2.3
可能(当子问题重叠)出现重复计算的问题
/*
不死神兔加速减空间方法
*/
public static int getMountOfRabbitAccelerate(int month){
if (month == 1 || month == 2) {
return 1;
}
int a = 1;
int b = 1;
while (month-- >= 3) {
b = a + b;
a = b - a;
}
return b;
}
12.JVM虚拟机内存模型
- 栈
存放局部变量 必须赋初值- 栈空间内存管理
- 栈空间分配的基本单位
- 栈空间中,存储局部变量等数据
- 局部变量定义在方法当中,所以栈内存给方法分配内存
- 运行中的方法,才回去访问它的局部变量,只有运行中的方法,才会占用一块内存空间
- 所以,栈空间,会给每一个正在运行中的方法分配一个专属的内存空间 —— 栈帧(stack frame)
- 栈空间内存分配的生命周期(栈帧的生命周期)
- 栈帧何时分配?
方法开始运行即被调用时 - 栈帧何时回收?
方法运行结束时
- 栈帧何时分配?
- 操作系统分配给虚拟机的内存空间是有上限的
- 栈空间分配的基本单位
- 栈空间内存管理
- 堆
存放new出来的变量 天生有初值 - 方法区
- 本地方法栈
- 程序计数器