二进制 ob
八进制 0
十六进制 0x
原码 反码 补码
正数的原码 反码 补码 都相同
负数的反码 除符号位之外 按位取反
负数的补码 反码加一
在计算机中的运算都是补码运算
正数的补码按位取反(包括符号位)再加一---->负数
负数也同样
变量的作用就是用来接受、操作、保存、传递对应的数据
int a = 5; 5这个值通过操作传递给了a,a接受了5这一个值并保存5这个值在变量a中
其中赋值 =左边为变量,右边为具体的数据,就是将等号右边的东西传给左边
基本数据类型
byte 1字节
short 2字节
int 4字节
long 8字节
float 4字节
double 8字节
char 2字节
boolean 1字节
转义字符 用于特殊字符
类型之间的转换 小类型转大类型可以自动转换 大类型转小类型需要强转---手动转换,但强转可能会引发精度丢失的问题
在Java中的的浮点类型float和double不能进行精确的运算,虽然在大多情况是正常的,但偶尔也会出现问题
在Java中要保证运行结果的精度,可以使用BigDecimal类
变量
变量一定要先声明,在复制,在使用
成员变量可以不用赋值,因为系统会自动分配一个默认值
Java是强类型编程语言,要求数据的类型与变量的类型保持一致
对象
Java是面向对象的编程语言
对象:
属性表示对象本身的一些特点
方法表示对象本身的一些行为
类是抽象的,而对象是具体的
狗是一个类,具体到某一只狗(小白) 那么小白就是对象
引用数据类型变量
类类型 接口类型 数组类型
我们写的每一个类都是一种类型,这种类型就是引用类型
jdk中也会自带一些类,这些类型也是引用类型
基本数据类型只能接收基本数据类型数据,相对来说是比较简单的数据,没有属性,也没有方法
引用数据类型只能接受对象,一般来说,对象是比较复杂的数据,可以具有属性和方法
基本类型变量和引用类型的变量核心区别:是否可以指向对象
局部变量:定义在方法之中,局部变量没有默认值
成员变量:定义在方法之中
- byte类型,默认值为0
- short类型,默认值为0
- int类型,默认值为0
- long类型,默认值为0L
- float类型,默认值为0.0F
- double类型,默认值为0.0D
- boolean类型,默认值false
- char类型,默认值是'\u0000'
- 引用类型,默认值是null
操作符
赋值操作符
= 赋值
*= 左边变量与右边数据相乘并把结果赋值个左边变量
%= 求余数
/= 求商
+= 求和
-= 求差
int a = 5/2.0
在这里结果不为2.5 而是为2 这里是5/2.0=2.5这个结果赋值给了a 但a不是浮点数类型而是整型 就会浮点型转整型,系统就会默认去掉小数部分
a++ 先执行在自增一
++a 先自增一在执行
如果没有执行 那么a++与++a作用相同
a-- --a类似
比较操作符
> >= <= <
instanceof 判断对象是否属于指定类型 语句 stu instanceof Student
但这个对象要被创建出来
Student stu; 这个不是创建对象 只是定义了一个类型类Student的变量,名为stu
相等操作符
== 是否相等 != 是否不相等
算术操作符
+ - * / %
移位操作符
>> 算术右位移运算
注意,这个操作的本质就是除以2^n^,这个n就是我们右移的位数。
注意,除以2^n之后,只保留整数部分
注意,正数右移之后,最左边空出的位置,都要补0
注意,负数右移之后,最左边空出的位置,都要补1
例如,16 >> 3 结果是2 ,相当于 16 /2^3 = 2
<< 算术左位移运算
注意,这个操作的本质就是除以2^n^,这个n就是我们右移的位数。
注意,除以2^n之后,只保留整数部分
注意,不论正负数左移以后,最右边空出的位置都要补0
注意,当左移之后,得到的数字已经超出当前类型所能表示的最大值的时候,这个值最终会被限定到这个当前类型中,所以最终显示的值会和我们逻辑上算出的值有所不同。
例如:直接使用2进制表示数字
int a = 0b01000000000000000000000000000000;
int result = a<<2; //其实这个结果已经超出了int能表示的最大值
System.out.println(result); //结果是0
特殊情况:
int a = 0b00000000000000000000000000000001;
System.out.println(a<<32); //结果是1 相当于1<<0
System.out.println(a<<33); //结果是2 相当于1<<1
System.out.println(a<<34); //结果是4 相当于1<<2
原因:
如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模/取余。如果对int型移动33位,实际上只移动了33%32=1位。如果对int型移动32位,实际上只移动了32%32=0位
>>> 逻辑右移位运算,也叫做【不带】符号的右移运算
注意,这个操作的本质就是除以2^n^,这个n就是我们右移的位数
注意,除以2^n^之后,只保留整数部分
注意,正数和负数右移之后,最左边空出的位置,都要补0
例如:
12>>>1 结果是 6
-12>>>1 结果是 2147483642
注意:在操作的时候,java操作的都是计算机中的补码
正数的原码、反码、补码都是一样的
例如:数字1的原码0000 0001,反码0000 0001,补码0000 0001
负数的原码、反码、补码有所不同
例如:数字-1
原码:1000 0001
反码:1111 1110 除了符号位之外,其他按位取反
补码:1111 1111 反码基础上加1
位运算符
& 与运算 有0则0
| 或运算 有1则1
^ 异或运算 相同则0 不同则1
~ 取反运算
9取反=-10
0 1001
1 0110
-0 0001
---------
1 0101
1 1010
逻辑运算符
短路与(逻辑与) &&
&& 与 & 的区别 ,在一个长表达式中包含多个表达式 当进行短路与判断时
&会把每一个表达式都进行判断 而&&则是遇到一个表达式结果为false时候 后面其他的表达式不再进行判断
整个表达式就结束了
不论时&& 还是& 有false的时候 表达时结果就为false
短路或(逻辑或)||
||与|的区别与上诉类似,区别就在于或运算是有true的时候,整个表达式的结果就为true
条件运算符(三目运算符)
语法:
boolean表达式?表达式1(boolean表达式为true结果为表达时1):表达式2(boolean表达式为false结果为表达式2)
String +两边 一边是字符串 一边是数据 那+的意思就是拼接
String str = 1+1+"s"+2+5 = 2s25
String str = 1+1+'a'+"s"+2+5 = 99225
String str = 1+1+"S"+'a'+2+5 = 2Sa25
流程控制
if语句
if(表达式){
}else{
}
if(){
}elseif{
}else{
}
不论是那种方式 都会只执行其中一个花括号中的代码
当然可以再if语句中嵌套if语句
switch语句
switch语句与if语句类似
目前switch默认只支持byte,short, int ,char, String(jdk1.8)
int a = 1;
switch(a){
case 0:{
}
case 1:{
}
case 2:{
}
.......
default:{
}
}
switch(a){
case 0:{
break;
}
case 1:{
break;
}
case 2:{
break;
}
.......
default:{
}
}
这两种方式不同之处就在于break,这要涉及到穿透概念
当没有break的时候,如果有一个case满足了switch()中的内容,那么首先这个相对于的语句会执行
接着,这个case后面所有的执行语句都会执行,而跳过后面case的判断,不论后面case是否满足switch
在这两种方法中还有一个default语句,这是再其他case都不满足时候会执行的语句,也可以省略不写
for循环
for(初始变量值;判断表达式;变量执行语句){
执行语句
}
例如:
for(int i=0;i<10;i++){
System.out.println("hello world");
}
当然,初始变量值可以写在for循环之外,变量执行语句可以写在花括号中
int i = 0;
for(;i<10;){
System.out.println("hello world");
i++;
}
这是一个死循环代码,for的小括号中,只有俩个分号
for(;;){
System.out.println("hello world");
}
当for循环中只有一行执行语句时候,花括号可以不写,但不建议
while语句
while(判断表达式){
执行语句
}
do-while语句
do{
执行语句
}while(判断表达式);
while于do-while的区别在于,do-while语句至少会执行一次,大体上与for循环类型
嵌套循环
在一个循环中可以嵌套另一个循环
for(){
while(){
do{
}while();
}
}
break语句
break的意思是退出,结束当前的循环或switch代码
continue语句
continue的意思是结束本次循环,让循环直接进入一次运行
break与continue
例如
for(int i = 0;i<3;i++){
if(i=0){
break;
}
}
当i=0时,结束for循环,后面的i=1,1=2的语句不在执行
for(int i = 0;i<3;i++){
if(i=0){
continue;
}
}
当i=0时,不执行i=0的执行代码,直接跳过i=0,直接执行下一个i=1的执行代码
默认情况下,在嵌套循环中,break和continue只能默认对当前循环其作用。
label
label用于结束指定一个for循环
test1:for(int i=0;i<3;i++){//外层循环
test2:for(int j=0;j<5;j++){//内层循环
if(j==2){
break test1;
}
System.out.println("i="+i+",j="+j);
}
System.out.println("----------------------");
}
其中test1,test2,test3就是label标签
那么会直接结束test1的for循环(包括for循环中其他循环)
结束多层循环可以使用label标签,也可以使用return
Jvm内存的分配
虚拟机栈:
存储局部变量
栈采用的是先进后出的规则
栈所占的内存空间小
栈中的变量,变量的作用结束以后弹栈
堆:
存放对象实例,成员变量也属于对象
堆占据jvm内存中最大的一块
堆里面的内存需要通过Jvm中的垃圾回收机制去回收
方法区:
存储已被加载器加载的类型信息、常量、静态变量,即时编译器编译后的代码缓存等数据
本地方法栈:
本地方法栈与虚拟机栈作用类型,区别在于虚拟机栈为虚拟机执行Java方法服务,而本地方法栈为虚拟机使用到的本地方法服务
寄存器:
程序计数器占据很小的一块内存空间,它可以看作当前线程所执行的字节码的行号治时期,字节码解释器工作时就是通过该百年计数器的值来选取下一条需要执行的字节码指令,它时程序控制流的治时期,分支,循环,挑战,异常处理,线程恢复等功能都需要以来这个计算器来完成
简单而言控制程序流程
jvm内存分配的方式
指针碰撞
空闲列表
数组的概述
数组是一组数据的集合,数组中的每一个数据称为元素
在Java中,数组也是对象。数组中的元素可以是任意类型(基本类型或引用类类型),但同一个数组里只能存放类型相同的元素
数组是存储同一种数据类型多个元素的结合,也可以看成是一个容器
数组即可以存储基本数据类型,也可以存储引用数据类型
Java是强类型语言,所以数组中的元素必须是对应数组类型
数组类型
任意类型 + [] = 相应的数组类型
例如:
int [] ----->int[]
数组中可以存放一组数据,要求这一组数据的类型都是一样的(或者是兼容的,兼容就代表可以自动转换)
数组变量
在原有的数组类型中声明这个数组类型的变量
int[] a; int[] a;
这两种方式都是正确的变量声明方式 建议使用第一种
数组类型的变量,也是引用类型变量,简称引用,它是可以执行对象的
数组对象
使用new关键字,来创建数组对象,中括号中的数字代表数组的长度(容量)
int[] a = new int[4];
数组对象,在内存中,就是一块连续的内存空间,在这一个连续的空间中可以存放多个类型相同的数据
注意:在堆中划分对象空间内存,其对应的地址是存放在相对应的虚拟机栈空间中的变量上,可以通过访问栈空间中的变量中的地址访问堆空间中存放的对象
数组对象中只有一个属性length,表示数组的长度
数组对象中的方法,只有从父类型Object中继承过来的方法
除此之外,数组对象中就没有其他的属性和方法了
数组长度
数组对象的长度
数组长度,是指一个数组对象中,最多可以存放多少个同以类型的数据
数组长度,必须在创建数组对象的时候明确指定
数组长度,一旦确定,就无法在改变
数组长度,可以为0,但是不能为负数
数组下标
数组对象在jvm的堆空间中是一款连续的内存空间,并允许使用下标,设置或获取每一个空间的值·
数组的下标区间[0,数组长度-1]
可以通过数组下标对数组中对应位置进行赋值或者是去取值
数组的地址
[(一个[对应一维数组,有多少个[就是几维数组)I(这里代表数据类型,不同的类型数组对应不同的字母,对应的数据类型的英文字母第一个并大写)哈希码(16进制)
[Iafffff
默认值
一个数组对象在创建的时候,需要指明数组长度,并且数组中的每一个元素位置上,都已经有一个相对应的默认值,默认值与数组的类型相关
//byte、short、int、long类型数组中的默认值为 0
//例如,
int[] a = new int[4];//默认4个数据全是0
//float、double类型数组中的默认值为 0.0
//例如,
double[] d = new double[4];//默认4个数据全是0.0
//boolean类型数组中的默认值为 false
//例如,
boolean[] d = new boolean[4];//默认4个数据全是false
//char类型数组中的默认值为 '\u0000'
//例如,
char[] d = new char[4];//默认4个数据全是'\u0000'
//引用类型数组中的默认值为 null
//例如,
String[] d = new String[4];//默认4个数据全是null
数组的初始化
数组创建时会在jvm中开辟连续的内存空间,并为每个数组元素赋值
数组对象的初始化形式
动态初始化
只指定长度,没有给数组赋值,都是默认值
int[] arr = new int[4];
静态初始化
给出初始化的值,长度由系统决定
int[] arr = new int[]{1,2,3,4}
int[] arr = {1,2,3,4}
int arr;
arr = new int[]{1,2,3,4};
错误的初始化方式
int[] arr = new int[4]{1,2,3,4}
int[] arr;
arr = {1,2,3,4}
数组的拷贝
数组对象在创建之时就已经确定了长度,并且时不能进行修改,但是可以通过赋值数组的内容变通实现改变数组长度
深拷贝 创建一个新的数组来接收被拷贝的数组
浅拷贝 定义一个数组变量指向被拷贝的内存地址
拷贝的三种方式
int[] arr = {12,12};
int[] arrcopy =new int[arr.length*2];
System.arraycopy(arr, 0, arrcopy, 0,arr.length);
arr=Arrays.copyOf(arr,arr.length*2);
int[] arr01 =new int[arr.length*2];
for(int i = 0;i<arr01.length;++i) {
if(arr.length>i) {
arr01[i]=arr[i];
}else {
arr01[i]=0;
}
}
arr=arr01;
数组的遍历
将数组中的元素逐个访问并取出来操作
可以使用三种基本循环来实现,
也可以使用增强for循环来实现(不需要下标)
增强for循环:
int[] arr = {1,4,4,5};
for(int ar : arr) {
System.out.println(ar);
}
数组中常见的问题
ArrayIndexOutOfBoundsException:数组索引越界异常(访问了不存在的索引)
NullPointerException:空指针异常