Java第二周 总结
运算符
算数运算符
+ - * / %
int a = 10;
int b = 3;
System.out.println(a-b);
System.out.println(a+b);
System.out.println(a*b);
//注意 结果类型是参与运算的类型中精度最高的类型
//a和b的类型为整型 a/b=3 再加上1.0, 1.0是double类型 所以转为double类型 则值为4.0
System.out.println(a/b+1.0);
System.out.println(a%b);
// a%b的值为0.300000000000004 因此千万不要使用小数进行比较相等的判断
System.out.println(0.1+0.2);
++和--:
++ : 自身加1,等同于 i=i+1 -- : 自身减1,等同于 i=i-1
++i 和 i++ :
i++ : 先赋值再加1 ++i : 先加1后赋值(-- 同理)
双目 :指的是只有两个操作数 例如 1 + 2
// ++ :自增+1,把对应空间的值 先拿出来加1再放回去
int s = 100;
//i++ : 先赋值 后加1
//++i : 先加1 后赋值
s = s + s++;
//s= 100 + 100(先赋值,已经定为100) = 200
System.out.println(s);
int w = 10;
w = w++ * w;
//w= 10(先赋值后加1) * 11(调用了已经+了1的w) = 110
System.out.println(w);
int m = 10;
int e = 2 + m++;
//e = 2 + 10 = 12
//m = 11
System.out.println(m);
//e = 12
System.out.println(e);
int p = 2;
p = 2 + p++ + ++p + p++ + ++p;
//p = 2 + 2(先定值为2,此时p为3) +4(此时p为3先加1为4,此时p为4) +4(先定值为4,此时p为5) +6(此时p为5先加1为6)= 2 +2 +4 +4 +6 =18
int x = 10;
x = 10 + x++ + ++x + (10*x++) + ++x;
/*x=10 + 10(先定值为10再加1,此时x为11)+ 12(此时x为11先加1,再定值此时x为12)+ (10*12(先定值x为12再加1,此时x为13))
*+ 14(先x加1为14,在定值)
*/
优先级 : 单目>双目>三目
单目 :指的是只有一个操作数 例如 ++和--
双目 :指的是只有两个操作数 例如 1 + 2
注意 : 不要使用小数比较相等 小数的储存值只是存储相近的值因此用来进行相等比较容易出错,不是BUG
关系运算符
返回值是boolean类型 只有false和true
> , >= , < , <= , == ,~=(不等于)
== : 比较基本类型的比较值的大小 , 如果是比较引用类型则是比较内存地址内值的大小 ( == 是比较相等 而 = 是赋值 )
int a = 10;
int b = 11;
System.out.println(a == b);//1
System.out.println(a >= b);//0
System.out.println(a > b);//0
System.out.println(a <= b);//1
System.out.println(a < b);//1
System.out.println(a != b);//1
位运算符
- & : 位与 , 两边都是true则结果为true
- | : 位或 , 两边只要有一个true则结果为true
- ! : 位非 , 取反 , !true为false
- ^ : 位异或 , 两边不一样则结果为true , 反之为false
- ~ : 按位非 , 0的二进制为 0000 0000 , ~0之后 为 1111 1111 这是补码,补码-1变为反码 1111 1110 , 原码为 1000 0001 就是-1
- >> : 右移运算符(考虑符号位) , 再怎么移动 符号位也不受影响 例如 8 >> 2 = 2 8为 0000 1000 右移两位 0000 0010
先转化为二进制 再右移两位 想最左边奖赏两个0(符号位后) 最右边则删除两位
正数 左边补0 , 负数 左边补1
右移几位就等于除以2的几次方 例如 x右移n位 x/2的n次方 - << : 左移运算符 , 与>>右移同理,除变乘
- >>> : 右移运算符(不考虑符号位),只补0,不补1,正数不受影响 与 >> 一样 , 负数全变正数 例如 -1 >>> 1 = 0111 1111
- 逻辑比较
&& : 且,短路与 , 和 & 一样 , 如果第一个是false则第二个不执行 , 但是 & 第二个也执行
|| : 或 , 短路或 , 如果第一个是true则第二个不执行 , 但 | 会执行第二个 - &的两边可以都是数字 ,如果是数字就是要进行与运算
8 & 9 : 把8 和 9先转换为二进制,然后按位与,如果都是1则取1,否则就是0;结果不会超过两个数中最小的一个数System.out.println(~10);// -11 System.out.println(-12 >> 2);// -3 System.out.println(-2 << 2);// -8 System.out.println(1 >>> 2);// 0 // 0000 0011 // 0000 0101 // 0000 0001 System.out.println(3 & 5);// 1 System.out.println(true & true);// true System.out.println(true && true);// true System.out.println(true || false);// true System.out.println(true ^ true);// false System.out.println(!true);// false System.out.println(!(1 < 2));// false int a = 10; int b = 11; boolean flag = (a == b && a++ >= b); System.out.println(flag);// false System.out.println(a);// 10
赋值运算符
= : 把右边的值赋值给左边
+ = : 右边和左边相加,结果赋值给左边 int i = 10; i += 20 ; 等价于 i = i += 20 ; 不需要强制转化类型
-= *= /= %= 同理
byte b1 = 2;
//需要强制转换
b1 = (byte)(b1 + 1);
//不需要强制转换
b1 += 2;
b1++;
int a = 10;
a += 10;//20
System.out.println(a);
a -= 5;//15
System.out.println(a);
a *= 5;//75
System.out.println(a);
a /= 15;//5
System.out.println(a);
a %= 2;//1
System.out.println(a);
字符串连接符
+ : 既是数值加减 , 也是字符串连接符 , 作用就是把多个字符串拼接成一个字符串
int a = 10;
int b = 12;
//1012
System.out.println("a+b="+a+b);
//a+b=22
System.out.println("a+b="+(a+b));
//10+12=22
System.out.println(a+"+"+b+"="+(a+b));
三目运算符
三目运算符有角三元运算符
语法 : boolean表达式?真语句 : 假语句; 先进行表达式判断 若表达式为真,则执行冒号前边的语句执行 否则执行冒号后边的
int i = 0;
//需求 : 如果为真 给变量i 赋值1 , 否则赋值11
i = 2<3 ? 1 : 11;
System.out.println(i);//1
int a = 5;
int b = 4;
int c = a++ - --b * ++a / b-- >> 2 % a--;
System.out.println(c);//-1
流程控制
顺序结构
从上往下,从左到右执行
分支结构
通过某个判断条件 , 选择不同的分支
if...else...
- 第一种结构 : 单分支 , 有不执行情况
if(boolean表达式){
java语句;
}int i = 1; //有不执行情况 if(i == 1){ System.out.println(1); }
-
第二种结构 : 双分支 ,肯定会执行
if(boolean表达式){
符合条件的java语句;
}else{
不符合条件的java语句;
}//没有不执行情况 if(i == 1){ System.out.println(1); }else{ System.out.println("不是1"); ]
-
第三种结构 : 多分支 ,else结尾肯定会执行 否则有不执行情况 多分支只会执行一个分支
if(boolean表达式){
符合条件的java语句;
}else if{
符合条件的java语句;
}else if(boolean表达式){
符合条件的java语句;
}... else{
不符合条件的java语句;
}//多分支 一条语句执行,则整个流程控制结束 String username = "admin"; String password = "root"; if(username != "admin"){ System.out.println(用户不存在); ]else if(password != "root"){ System.out.println("密码不正确"); }else{ System.out.println("登陆成功"); }//登陆成功
-
简写
如果分支只有一条语句则{}可以省略if(1 < 2) System.out.println("真的"); else System.out.println("假的");
switch
基本使用
1.7之前 , 只能传入整型( byte short char int ) 自动类型转换 1.7开始 还可以传入字符串
语法 : switch(数值){
case 值 : java语句; break; //可以不写
case 值 : java语句; break;
case 值 : java语句; break;
default : java语句; //可以不写 默认执行程序
}
char c = 'D';
if(c == 'A'){
}else if(c == 'B'){
}else if(c == 'C'){
}else{
}
switch(c){
case 'A':
System.out.println("优秀");
break;
case 'B':
System.out.println("良好");
break;
case 'C':
System.out.println("一般");
break;
default:
System.out.println("差");
break;
}
Case穿透
break结束switch分支执行 , 如果没有break就会发生case穿透现象
找到符合的case之后 , 剩下的所有case代码都不判断 直接执行
先执行case 再执行default
switch(c){
case 'A':
System.out.println("优秀");
default:
System.out.println("差");
case 'B':
System.out.println("良好");
case 'C':
System.out.println("一般");
}
循环结构
for循环
for循环 : 又被称为计数循环 , 就是在某个次数范围内重复执行某段相同代码
语法 :
for( 表达式1 ; 表达式2 ; 表达式3){
循环体 , 要重复做的事的java代码;
}
表达式1 : 是初始化表达式 , 最先执行 但只执行一次
表达式2 : 必须是boolean类型的表达式
表达式3 : 步长
执行过程 :
程序执行到for循环的时候 , 先执行 表达式1(只执行一次)
然后执行 表达式2 , 如果返回的值是false 则循环结束
如果 表达式2 返回的值是true 则执行循环体
执行完循环体之后再执行 表达式3 ,然后执行 表达式2 如果返回alse 则循环结束,如果返回true则执行循环体 , 再执行 表达式3 ......(套娃)
一直到 表达式2 返回值为false为止 , 终止循环 , 否则一直执行
循环三要素 : 初始值 终止条件 步长
//条件什么的可以都不写,但是;分号 必须有,死循环没有用
for( ; ; ){
System.out.println(111);
}
/****************************/
for (int i = 0; i < 10; i++){
System.out.println(i);
}
// 初始值的变量i,只能再循环中使用
//System.out.println(i);
int i = 0;
for ( ; i < 10; i+=2){
System.out.println(i);
}
System.out.println(i);
嵌套循环
//外循环执行一次,内循环执行一圈
for(int i = 0; i < 5; i++){
for(int j = 0; j < 5; j++){
System.out.print(j+" ")
}
//打印语句带有 ln 的是打印顺便换行
System.out.println();
}
嵌套循环简单事例 使用嵌套循环打印出 九九乘法表
//外循环表示行
//内循环表示列
for(int i = 1; i < 10; i++){
for(int j = 1; j < i; j++){
System.out.print(j+"*"+i+"="+(i*j)+" ");
}
System.out.println();
}
while循环
while循环 又被称真假循环 , 当某个条件为真时 , 就执行
语法 :
while(boolean表达式){
java代码;
}
for和while 执行次数 都是 0~N次
//某个次数范围内,for更有优势,更加适合
for(int i = 20; i < 10; i++){
System.out.println(i);
}
int i = 20;
while(i < 10){
System.out.println(i);
i++;
}
//某个条件为真的情况下,while更有优势,更加简洁
//死循环
while(true){
}
for( ; true; ){
}
do...while
do..while 循环 : 保证代码至少执行一次 , 先执行再判断
语法 :
do{
java代码;
}while(boolean表达式);
执行次数 1~N次
int i = 20;
/*
* while(i < 10){
* System.out.println(i);
* i++;
* }
*/
do{
System.out.println(i);
i++;
}while(i <10);
break&continue
break 语句
1 用于switch语句中 , 结束分支语句 , 避免case穿透现象
2 用于循环体中 , 结束循环执行 , 默认结束最近的一层循环
continue 语句 : 跳过本次循环 , 继续下一次
return 语句 : 结束方法
//需求:找40~100内 第一个被7整除的数
for(int i = 40; ui <= 100; i++){
if(i % 7 ==0){
System.out.println(i);
//终止循环
break;
}
}
//需求:找40~100内 所有不能被7整除的数
for(int i = 40; i <= 100; i++){
if(i % 7 == 0){
//跳过本次 直接执行i++
continue;
}
System.out.println(i);
}
//对外层循环设置名字
outerFor:for(int i = 0; i < 10; i++){
for(int j = 0; j < 5; j++){
if(i == 3 && j == 4){
//终止指定名字的循环即可
break outFor;
}
System.out.println(i+":"+j)
}
}
方法
概述和作用
一堆代码的集合,可以重复使用
方法目的 : 代码重复使用
相同的功能 , 相同的代码 , 不用重复写多遍 , 只写一遍然后重复调用这一段代码集合即可
使用方法的优点 :
1 使程序变得更加简洁和清晰
2 更加有利于程序的维护
3 提高开发效率
4 提高代码重用性/复用性(重复使用)
方法声明
方法声明 : [ 修饰符列表 ] 返回值类型 方法名 (参数列表) { 方法体 }
[ ] : 可以有 也可以没有 可以有多个
1 方法修饰符列表是可选的 :
权限控制 四选一 public private protected 默认(不写)
static (声明静态) , abstract synchrinized fina
2 返回值类型 : 11 中数据类型的任意一种 或者是没有返回值类型 void
3 方法名 : 方法名字 , 合法即可(之前的取名字方法)
4 参数列表 : 可以有 也可以没有 也可以有多个,多个之间使用逗号隔开
形参 : 形容参数在方法声明的时候 , 规定应该传入的数据类型
实参 : 实际参数 , 调入方法的时候实际传入的实际的数据
5 方法体 : 要做的事 代码的集合
5.1 如果有返回值类型 , 那么方法体重最后一条语句 , 必须要写 return 数据 形参
如果 返回值的类型为 int , 则需要在方法体中写 return int值 ; 另外 return 还有终止方法运行的作用
5.2 如果没有返回值类型 , 那么方法体中 , 可以没有return语句
如果要加return语句也行 , 那么return语句之后不能有数据return ; 此时return只有终止方法的作用
//有返回值类型
public static int sumInt(int a,int b){
return a+b;
}
//没有返回值
public static void sumInt1 (int a,int b){
System.out.println(a+b);
}
方法分类
方法 :
静态方法 : 类体中 使用static修饰的方法 , 是静态方法 , 类相关
成员方法 : 类体中 ,没有使用static修饰的方法 , 是成员方法 , 对象相关
构造方法 : 用于创建对象
//静态方法
public static void m1(){
}
//成员方法
puiblic void m2(){
}
//构造方法,没有返回值类型,void也没有,方法名和类名一直
public Method_02(){
}
方法调用
调用:
方法不调用不执行 , 调用才能执行 , 并且把结果返回到调用处
所以方法声明时 , 不需要考虑声明的先后顺序 因为执行顺序是看调用的顺序而来的 而不是声明的时候的顺序
1 静态方法 : 类名 . 静态方法(参数值) ; 在当前类中 类名可以省略
2 成员方法 : 对象 . 成员方法(参数值)
3 构成方法 : new
方法的声明只管功能作用的实现 , 保证使用 , 与该方法被谁调用和使用的地方则与声明无关(相当于数学里的公式和公理,定理)
public class Method_02{
public static void main(String[] args){
sumInt(1,22);
Method_02.sumInt(1,1);
//接收返回值,变量的值的类型必须和返回值的类型一致; 如果没有返回值,则是不能接收的
int result = sumInt(1,1);
System.out.println(result);
}
}
返回值
有返回值类型
public static int m1(){
}
必须得有 return 语句
public static int m1(){
return 0;
// return之后,不能有代码,因为return终止方法运行,返回参数;导致下面的代码没有运行
System.out.println();
}
public static int m2(){
//这样是不行的,编译时检查语法结构,而if单分支头部执行情况, 所以必须在if的外边加一个return
//或者在else中也添加retuen
//尽管我们知道一定会执行if中的return,外面也要加,因为编译器不会判定该方法有return操作
if(true){
return 2;
}
}
没有返回值类型
public static void m3(){
//因为没有返回值类型,所以return可以不加,如果要写,只能终止方法运行
//并且ruturn语句之后,不能跟数据 return;
return 2;
}
public static void main(String[] args){
m4(6);
}
public static void m4(int i){
//参数列表中的变量,也是局部变量,调用处的实参值会赋值给该变量
for( ;i <= 10; i++){
if(i == 5){
//如果没有返回值,单独写retuen意义不大(没有任何作用),但是可以结合流程控制来发挥return的作用
return;
}
System.out.println(i);
}
System.println("Hello 执行完成");
}
方法重载
方法唯一性 : 方法名 和 参数列表
方法重载 : overlord
方法名相同 , 参数列表不同(个数不同和类型不同)
在同一个;类中 , 方法名是允许相同的 , 可以根据不同的参数列表找到某一个方法 , 叫方法重载(其实就是方法声明的时候形参类型的不同的方法的集合)
public static void main(String[] args){
//相同功能,方法名不同,不容易记忆,也不美观
sumDoubkle(1,2.2);
sumInt(2,2);
sumLong(2323,222);
//功能相同,名字也相同,根据参数列表区分,容易记忆,代码美观
sum(2,3);
sum(2,3.4);
sum(2L,3);
}
public static void sumInt(int a,int b){
System.out.println(a + b);
}
public static void sumDouble(double a,double b){
System.out.println(a + b);
}
public static void sumLong(long a,long b){
System.out.println(a + b);
}
public static void sum(int a,int b){
System.out.println(a + b);
}
public static void sum(double a,double b){
System.out.println(a + b);
}
public static void sum(long a,long b){
System.out.println(a + b);
}
public static void main(String[] args){
//方法重载的优点,相同功能,只需要记住一个名字,通过参数区分不同的方法即可
System.out.println(1);
System.out.println(1.2);
System.out.println(false);
System.out.println("多撒即可到那边三");
}
内存分析
1 程序 : 一堆命令的集合 , 是可执行文件 , 并且是一个静态概念 , 一般保存在硬盘中
2 进程 : 就是正在执行的程序 , 是一个动态概念 , 会按照程序设计 一步一步的在内存中执行
运行中的程序 , 就是指载入到内存的可执行文件 , 这个时候操作系统会开启一个进程来运行内存中的这个文件对象
如果要关闭某个程序 , 可以结束该进程
java中的内存划分
java Runtime Data Area java 运行时数据区 , 也可以叫JVM内存
内存被划分为5个区域 : 程序计数器 方法区/静态区 栈内存 堆内存 本地方法
- 程序计数器 :
是一块比较小的内存区域 , 可以看成是当前执行的字节码位置 , 分支 , 循环 , 跳转 , 异常等都需要依赖于程序计数器
可以理解为保存执行的代码行号 , 每个方法都会有一个计数器 , 要么自己就会找不到返回值要返回的地方
- 方法区/静态区 :
保存我们的程序文件(.class) , 载入内存后的那个文件 , java中就是class文件
包括方法执行之前 , 还有代码段 , 内部的运行常量池
- 栈内存 :
虚拟机栈 / VM栈 / 栈内存
方法是在栈内存中执行的 , 包括局内变量也是在栈内存中
栈内存 : 就是一个以栈数据结构为模型的一段内存空间
栈 : 是一个数据结构 , 先进后出 , 比如 弹夹 网页的恢复 返回上一步 / 撤销
栈的构成因素 :
栈空间 : 就是指以栈数据结构为模型的一段内存空间 ( 弹夹 )
栈帧 : 栈内存中的每一个栈元素 , 叫栈帧 ( 子弹 )
栈底元素 : 是指第一个放入栈空间的栈帧 ( 第一个放入弹夹的子弹 , 在最下面 )
栈顶元素 : 是指最后一个放入栈空间的栈帧 ( 最后一个放入弹夹的子弹 , 在最上面 )
栈操作 :
压栈 : 就是指把栈帧放入栈空间的过程 ( 把子弹放入弹夹的过程 )
弹栈 : 就是指栈帧在栈空间内移出的过程 ( 把子弹从弹夹中被顶上入枪膛的过程 )
- 堆内存 :
用来存放 根据静态区中的 class 文件对象 , 所创建的用来保存 class 定义的数据的对象的空间
用来保存对象 ( 类创建的对象 new )
每个对象的空间分为三块
1 数据部分 : 成员变量
2 头部 : hashCode值
3 类型 : 是哪个类型实例化而来的 , 保存类文件在静态区的地址
栈操作 :
压栈 : 就是指把栈帧放入栈空间的过程 ( 把子弹放入弹夹的过程 )
弹栈 : 就是指栈帧在栈空间内移出的过程 ( 把子弹从弹夹中被顶上入枪膛的过程 )
- 本地栈 : 比如 hasCode() 方法 , 前面有个native(本地)的声明 , 当我们调用本地方法的时候 对于我们来说和调用其他方法一样
但是对于JVM来说 , 还是有区别的 , 因为需要一个个专门的区域来存放 (native是C中的关键字)
本地方法栈 和 VM栈 结构一样
VM栈 是用来为执行我们的 JAVA方法 服务的 , 而本地方法栈是为了使用 JVM使用native方法服务的
java执行流程
1 编码
文本编辑器 , 按照java规则 , 进行编码创造 .java 文件
2 编译
通过 javac 命令 , 使用 java 编译器 , 对 .java 文件进行编译 , 生成 .class 文件
3 运行
通过 java 命令 , 运行 .class 程序
3.1 开启 java 虚拟机 , 把对应的 .class 文件载入内存中(静态区)
3.2 JVM 自动调用该 class 中的 main 方法
3.3 main 方法执行,JVM会在栈内存中开辟main方法栈帧(只要是方法调用 , 都会在栈内存开辟 栈帧 执行方法) , 然后把 main 中的代码复制进去 , 准备执行
3.4 如果 main方法中 ,没有其他方法的调用 , 则安心执行 main 方法 , 执行完就终止 , JVM就关闭
3.5 如果main方法中 , 有其他方法的调用 , 如果是其他类 则需要把对应的类的 .class文件 , 也载入到静态区
3.6 如果main方法中 , 调用当前类的方法 , 则不需要重载载入当前类
3.7 当main方法中调用其他方法的时候 , 会再去栈内存中开辟对应的方法 栈帧 , 把对应方法的代码复制进去 , 准备执行
当该方法执行完成之后 , 方法弹栈 , 并返回到 main方法中的调用处 , 继续向下执行 一直到main方法执行结束 , 弹栈 , JVM关闭
程序的加载 :
1 静态加载 : 程序开始执行 , 一次性把所有的相关文件 , 全部载入文件
2 动态加载 : 程序开始执行 , 现在入当前文件 , 动用到其他文件的时候 , 再单独去加载
java中采用的动态加载
方法的调用 就是压栈操作 , 而方法调用结束 , 则是弹栈操作
public static void main(String[] args){
m1();
System.out.println("m1被执行了");
}
public static void m1(){
m2();
System.out.println("m1被执行了");
}
public static void m2(){
m3();
System.out.println("m2被执行了");
}
public static void m3(){
System.out.println("m3被执行了");
}