文章目录
大纲
1.Java语言及JVM
知识点:
1)什么是Java语言:
- Java是跨平台的纯面向对象的语言
2)JVM概念:
- JVM是运行在操作系统之上,是一个可以运行java代码的虚拟计算机;
- 对于不同的平台,有不同的虚拟机,其屏蔽了底层运行平台的差别,实现了“一次编译,导出运行”。
什么是JDK、JRE、JVM,及其之间的关系:
- JDK(Java Development Kit,Java开发工具包):
- 包含JRE以及一些开发工具
- 面向开发人员使用(开发用的)
- JDK:javac.exe:编译工具, java.exe:运行工具
- JRE(Java Runtime Environment,Java运行时环境):
- 包含JVM以及一些核心的运行类库,面向运行人员使用(运行用的)
- 核心类库,简单理解就是已经写好的java代码(eg.写代码时System等代码的使用)
- JVM(Java Virtual Machine, Java 虚拟机):
- 包含字节码等核心内容(核心所在,跨平台的关键)
- 运行程序的载体【平台】
java编译运行原理
- Java 引入了字节码的概念,JVM只能认识字节码,并将它们解释到系统的 API 调用,JVM把字节码解释成具体平台上的机器指令。
- 对于不同的平台,有不同的虚拟机,其屏蔽了底层运行平台的差别,实现了“一次编译,导出运行”。
编译运行流程:
2.数据类型
基础数据类型,四类八种:
1)整数类型:(使用最多的是int)
- byte 1个字节;范围 : -128~127 2^7=128 + 一位符号位
- short 2个字节
- int 4个字节
- long 8个字节
-
2)小数类型:
- float(单精度) 4个字节
- double(双精度) 8个字节
3)布尔类型:
-
boolean 1个字节 true false
-
回答:理论上来说,八分之一个字节就能表示他的大小,但是计算机当中最小的存储单元是字节,所以它应该占1个字节。
boolean类型数据注意事项:
- 只允许取值true和false,无null
- 不可以 0 或非 0 的整数替代false和true,这点和C语言不同
- boolean类型不可以转换为其它的数据类型
- Java虚拟机中没有任何供boolean值专用的字节码指令,java语言表达所操作的boolean值,在编译之后都使用java虚拟机中的int数据类型来代替:true用1表示,false用0表示《java虚拟机规范 8版》
4)字符类型:
- char 2个字节 0~65535 = 2^(2*8)-1
// a = 97
// A = 65
// 0 = 48
char c1 = ‘a’;
char c2 = 65;
char c3 = 48;
占用空间/取值范围:
- 计算机中最小的存储[单元] - 字节-byte
- 计算机中最小的存储[单位] - 位-Bit-比特
- 1个字节 = 8个位 (Bit) 比特位
问题:byte存储空间为8,最小值为 1111 1111 不应该代表 -127么?
Java程序默认的运算是十进制, 但是在底层运算的过程中, 都是以二进制(补码)的形式在运算.
byte b = (byte) 130; //问 b的值是?
/*
130存储形式:0000 0000 0000 0000 0000 0000 1000 0010
对应byte8位补码的存储为:1000 0010 其反码为 1000 0001 其源码为 1111 1110
对应十进制为 -126
*/
默认值:
- 整数(四种类型): 0
- 小数(两种类型): 0.0
- 布尔: false
- 字符: 0 或写为:’\u0000’(表现为空)
- 引用数据类型: null
注意事项:
1)所有整数默认都是int类型 、所有小数默认都是double
2)定义float类型变量应该加F的标识
float num = 12.3;
//一开始就会报错,需要加F标识:
float num2 = 12.3F;
//因为12.3常量默认是8个字节的double类型,直接赋值会报错(因为涉及强制转换,应转换为float类型);
3)定义Long类型变量应该加L的标识,建议使用大写.
long num = 12345678;
//常量值默认是用int类型存储的,当数值过大时会产生溢出,正确做法如下:
long num = 123456789999L;
4)为什么float占4个字节,long占8个字节,float却比long要大呢?
- 因为整数和小数,底层的二进制存储结构不同.
5)byte, short, char, int 在一起运算的时候, 都会先提升为int (因为所有整数默认都是int类型),
- 其余类型的运算, 都是小的提升为大的.
3.运算符
知识点:
-
运算符的分类?
-
算数运算符有哪些?
算数运算符(自增自减运算符) 赋值运算符 扩展赋值运算符:+= 、-=、*=、/= 、%= 关系运算符[比较运算符] 逻辑运算符 三元运算符[三目运算符]
注意事项:
- 1)整数相除结果只能是整数
- 2)如果想计算出小数, 必须要有浮点类型数据参数运算
- 3)字符与字符串参与加法运算
- 4)自增与自减操作【案例】
int x = 4;
// 4 + 6 + 60
int y = (x++)+(++x)+(x*10);
System.out.println("x="+x); // x=6
System.out.println("y="+y); // y=70
System.out.println("---------------");
-
5)=和==要区分明白
=:赋值的
==:比较的 -
6)与、或、 非 以及 短路与、短路或、异或
&& : 从最终结果来看,跟&的效果是一样的,也是与false则false,但是&&具有短路效果,运行效果会提升(但要注意短路产生的影响)
|| : 遇true则true,也具备短路效果,当左边为true,右边就不执行了。
^(异或) :
- 现象: 相同为false,不同为true(处对象)
- 特点:一个数,被另外一个数,异或两次,该数本身不变。
因为在每一位上:
- 1)0位:不管0遇到谁(0或1),异或后其值都会与该值相同(0或1),此时再与该值(0或1)异或,对应位的值相同,结果都为0;
- 2)1位:不管1遇到谁(0或1),异或后其值都会与该值相反(1或0),此时再与该值(0或1)异或,对应位的值相反,结果都为1;
面试题:实现两个变量的数值交换, 不允许定义三方变量
public static void main(String[] args) {
int a = 10;
int b = 20;
a = a ^ b; // 10 ^ 20
b = a ^ b; // 10 ^ 20 ^ 20 --> 10
a = a ^ b; // 10 ^ 20 ^ 10 --> 20
System.out.println(a);
System.out.println(b);
}
- 7)三元运算符
格式: (比较表达式) ? 值1 :值 2
注意事项:
-
三元运算符的结果,必须被使用(如赋给变量、输出……)
hold?fish:palm;
-
8)位运算符
>> 右移 二进制进行右移 最高位是0,则空缺位用0补齐,最高位是1,则空缺位用1补齐
>>> 无符号右移 最高位用0补齐
<< 高位舍弃,空缺位用0补齐
赋值运算中的类型转换
- 隐式/显式转换:将大的数据类型,给小的数据类型赋值,不能直接赋值,需要强转符号
- 底层强制转换 += 、 -= ......
- 常量优化机制
// 案例一:隐式/显式转换 会报错
short s=1;
s=s+1; // s是short类型,1是int类型,short和int相加的时候,会先将short提升为int
// 两个int相加的结果,还是int,把int结果赋值给short类型的变量,需要强转。
System.out.println("---------------");
// 案例二:底层强制转换 不会 报错
short s=1;
s+=1; //原因:底层自动做了强制类型转换 其等价于 —>
// s = (short)(s+1);
----------------------
// 案例三:
byte b1=3,b2=4,b;
b=b1+b2;
1. 因为所有整数默认都是int类型,b1和b2两个byte类型在做运算之前,会先各自提升为int类型,然后再做运算
两个变量都提升为int类型了,两个int相加,结果还是int,将int数据赋值给byte,不能直接赋值,应该加入强转。
2. 因为b1和b2是两个变量,变量内部所记录的值是不可控的,有可能相加之后的结果就超出了byte的取值范围
----------------------
常量优化机制
----------------------
b=3+4;
因为3和4是两个常量,Java有常量优化机制,在编译的时候就会将3和4进行相加,然后看相加的结果是否在byte的取值范围。
4.流程控制
知识点
流程控制语句的分类:
- 顺序结构
- 选择结构:
- if
- switch
- 循环结构:
- for
- while
- do … while
if语句
三种格式:
格式1:
if(比较表达式){ //注意 0、1等常量值不能代表 布尔值
语句体;
}
//if语句的语句体,如果是一条语句,大括号可以省略不写
if()
语句体;
格式2:
if(比较表达式){
语句体1;
}else{
语句体2;
}
格式3:
if(比较表达式1) {
语句体1;
}else if(比较表达式2) {
语句体2;
}else if(比较表达式3) {
语句体3;
}
...
else {
语句体n+1;
}
switch语句
switch(将要匹配的值) {
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
…
default:
语句体n+1;
break;
}
注意事项:
- 1)case后面的值只能是常量, 不能是变量
- 2)case后面的值不允许重复定义!
问题:
-
1)break语句可以省略吗?
- 可以省略,但是不建议,因为会出现case穿透的现象
-
2)default语句可以省略吗?
- 可以省略,但是不建议,因为需要default对范围外的错误值,给出提示.
-
3)表达式(将要匹配的值)可以接受的值为?
-
基本数据类型:byte short char (int) -> 只要是能够提升为int类型的
-
引用数据类型:枚举、字符串(jdk1.5之后可以接收枚举,jdk1.7之后可以接收String字符串)
-
-
4)swich语言什么时候会停止运行:
- 当遇到break时;
- 当不会遇到break时,会按照逻辑一直穿透,直到运行遇到到大括号时;
-
5)default语句位置没有固定要求,且可以省略;
全部没有break的case穿透:
public static void main(String[] args) {
int x = 0;
int y = 0;
Scanner sc = new Scanner(System.in);
System.out.println("请输入x值(默认为0):");
x = sc.nextInt();
switch (x) {
default:
y++;
case 3:
y++;
case 4:
y++;
case 5:
y++;
}
System.out.println("y值为:" + y);
// x = 0 -> y = 4;
//x = 3 -> y = 3;
//x = 5 -> y = 1;
}
循环语句
1.for循环
for(初始化语句; 循环判断语句; 循环后的步进语句){
循环体;
}
2.while循环
初始化语句;
while(判断条件语句){
循环体;
循环后的步进语句;
}
3.do while循环
初始化语句;
do {
循环体语句;
控制条件语句;
}while(判断条件语句);
三种循环的区别?
-
(for循环while)和do…while的区别 :
for循环和while循环,都是在判断条件满足的情况下,才会进入循环执行循环体.
do…while循环, 无论条件是否满足, 都至少执行一次循环体.
-
for和while的区别:
for循环内部定义的变量, 在循环结束后, 将会从内存中释放掉
如果想要在循环结束后, 继续使用控制循环的那个变量, 就可以使用while循环
for each*
break 与 continue
break语句:
- 1: 用于结束循环, 或者是switch语句
- 2: break语句只能应用在循环和switch语句当中
- 3:如果循环嵌套循环,break只能结束自己所在的那一层循环,如果想要结束指定的循环,可以加入标号
public static void main(String[] args) {
lo:while(true){
for(int i = 1; i <= 10; i++){
if(i == 3){
break lo;
}
System.out.println("HelloWorld");
}
System.out.println("------------");
}
}
continue:
- 1: 终止本次循环, 继续下一次循环 (跳过后继续)
- 2: 只能在循环当中使用
5.数组
使用过程
1)声明数组
int[] a;
int a[];
Java语言中声明数组时不能指定其长度(数组中元素的数), 例如: int a[5]; //非法
2)分配空间
a = new int[5];
3)赋值
a[0] = 5;
4)操作
数组初始化
数组的初始化:给变量开辟内存空间,并为数组中每个元素赋予初始值
动态初始化 与 静态初始化 的区别
-
动态初始化:只给出长度,由系统给出初始化值 int[] arr = new int[2];
-
静态初始化:直接通过大括号,给出初始值,由系统决定数组长度 int[] arr = {11, 22, 33};
1)动态初始化
数据类型[] 数组名 = new 数据类型[数组的长度];
int[] arr = new int[3];
// 在内存中开辟了3个连续大小的内存空间, 这三个空间可以存储3个int类型整数
2)静态初始化
完整格式:
- 数据类型[ ] 数组名 = new 数据类型[ ]{元素1, 元素2, 元素3…};
简化格式
- 数据类型[ ] 数组名 = {元素1, 元素2, 元素3…};
int[] arr = {11, 22, 33};
注意:
- 不能动静结合
- int[] arr2 = new int[3]{11,22,33}; // 编译错误, 语法错误
其他
1)打印数组变量
打印数组变量的结果:System.out.println(arr);
* [D@4d687dcd
*
* @ : 分隔符
* [ : 代表的是数组类型, 几个中括号就代表的是几维数组
* D : 代表的是double类型
*
* 4d687dcd : 十六进制地址值
*
* 十六进制: 1 2 3 4 5 6 7 8 9 a b c d e f
问题: 描述下列代码的每一步代表什么
char[] arr = new char[2];
// 这是创建了一个char类型数组, 变量名叫arr, 数组中可以存储2个char类型字符.
2)数组操作的两个常见小问题
-
1: ArrayIndexOutOfBoundsException : 数组索引越界异常
原因: 访问了不存在的索引
-
2: NullPointerException : 空指针异常
原因 : 将一个引用数据类型赋值为null之后, 就跟堆内存的引用切断了,这时候再想访问堆内存中的数据, 就会出现空指针异常.
6.方法
定义
修饰符 返回值类型 方法名(参数类型 参数名1, 参数类型 参数名2...){
方法体;
return 返回值;
}
修饰符 : 如 public权限修饰符 static状态修饰符
返回值类型 : 跟返回值有关.(若不需要返回值 则使用 void)
方法名 : 合法的标识符即可(自己起的名字)
参数类型 参数名1 (参数列表) : 方法运行所需要参数
方法体 : 方法真正执行的代码逻辑.
return :
- 用于结束方法
- 用于将返回值携带给调用者
- 如果方法的返回值类型是void, return语句可以省略不写
方法调用之方法调用图解
方法的重载overload
什么是重载:同一类中,方法名相同,参数列表不同,与返回值无关。
参数列表不同包括:
- 个数不同;
- 类型不同;
- 顺序不同(没有意义,但不会报错)
注意事项:
- 在调用方法的时候,java虚拟机会根据方法名及参数列表的不同来区分方法。
问题1:参数类型为int的方法能否接受byte的数据? (可以,因为含有隐式转换)
public static void main(String[] args) {
byte b1 = 10;
byte b2 = 20;
check(b1,b2);
}
public static boolean check(int a, int b){
System.out.println("int...");
return a == b;
}
问题2:有两个方法,参数列表为byte 和 int类型,如果直接调用方法传入两个整数常量, 会匹配到int, 如果非要匹配byte可以加入强制转换.
public static void main(String[] args) {
check((byte)10,(byte)20);
}
public static boolean check(int a, int b){
System.out.println("int...");
return a == b;
}
public static boolean check(byte a, byte b){
System.out.println("byte...");
return a == b;
}
问题3: Java当中到底是值传递, 还是址传递?
基本数据类型, 传递的是值, 引用数据类型的时候传递的是地址值.
方法的重写*
7.各类关键字*
权限修饰符
状态修饰符