扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
变量指程序运行时可变的量,相当开辟了一块内存空间来保存一些数据,类型则是对变量的种类进行划分,使不同的类型变量具有不同的特性
而变量与我们内存的硬件设施密切相关
JAVA是强类型语言
硬性指标 :
注意: 虽然语法上也允许使用中文/美元符($)命名变量, 但是 强烈 不推荐这样做.
软性指标 :
final int a = 10;
a = 20; // 编译出错. 提示 无法为最终变量a分配值 常量不能在程序运行过程中发生修改
字面常量 ——程序中直接写出来的值
几种常数赋值方式
public class Candy3 {public static void main(String[] args) {int a=0x123;
int b=0b1001;
int c=010;
System.out.println(a);//291
System.out.println(b);//9
System.out.println(c);//8
}
}
基本类型基本语法格式
int a=10;//初始化时并赋值
int a;
内存大小
int 大小为4个字节(byte),与操作系统的和JVM的版本无关,像C语言可能就会受到编译器的影响,是为了实现跨平台
整型的范围
数据溢出问题
为什么会溢出
因为2^32-1的数据的大小不够用,还不够表述出马云的个人资产,所以引出了long类型
长整型 longlong a=10L;
long a=10l;
long a=1000_000_000;//可以为数字字面量加下划线,这些下划线只是让人更易读,Java编译器会自动去除这些下划线
为什么要加L呢?
整型的字面量,默认是整型(int),浮点数的字面量,默认是double,所以要加一个L(l)表示它是long类型,否则会发生隐式转换
内存的大小
long类型的大小是8字节
long的数据范围
-263至263-1
短整型 shortshort a=20;
内存大小
2个字节 数值范围是 -215至-215-1
基本没啥用
比特型 bytebyte a=1;
内存大小
一个字节 ,数值访问 -128到127
主要用于文件和网络的传输
浮点数 float和doublefloat f=1.2f;
float f=1.2F;
double d=1.2;
在JAVA中直接写出来的字母常量的浮点数都是double类型的,所以在flaot需要特别的声明一下
内存大小
float的大小为4个字节,double的字节是8个字节 在内存中采用指数的形式来模拟
浮点数存储规则
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^S S表示符号位,当s=0,V为正数;当s=1,V为负数。
M表示有效数字,大于等于1,小于2。
2^E E表示指数位。
举例来说:
十进制的5.0,写成二进制是 101.0 ,相当于 1.01×2^2 。
那么,按照上面V的格式,可以得出s=0,M=1.01,E=2。
十进制的-5.0,写成二进制是 -101.0 ,相当于 -1.01×2^2 。那么,s=1,M=1.01,E=2。
IEEE 754规定:
IEEE 754对有效数字M和指数E,还有一些特别规定。
前面说过, 1≤M<2 ,也就是说,M必须写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的 xxxxxx部分。比如保存1.01的时 候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位 浮点数为例,留给M只有23位, 将第一位的1舍去以后,等于可以保存24位有效数字。
至于指数E,情况就比较复杂。
首先,E为一个无符号整数(unsigned int)
这意味着,如果E为8位,它的取值范围为0255;如果E为11位,它的取值范围为02047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数 是127;对于11位的E,这个中间 数是1023。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即 10001001。
然后,指数E从内存中取出还可以再分成三种情况:
E不全为0或不全为1
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将 有效数字M前加上第一位的1。
比如:0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为1.0*2^(-1),其阶码为-1+127=126,表示为 01111110,而尾数1.0去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进 制表示形式为:
E全为0
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);
关于3*0.1==0.3答案是不相同的
在上面,我们知道我们的浮点数在计算机以指数形式存储,其原理还是得用我们的二进制来表示
如何解决
三种特殊的double如果的基本整数和浮点数的精度不能满足需求,可以使用java.math包下两个很有用的类
BigInteger 实现任意精度的整数运算
- BigInteger a=new BigInteger(“123”); //第一种,参数是字符串
- BigInteger a=BigInteger.valueOf(123); //第二种,参数可以是int、long
BigDecimal 实现任意精度的浮点数运算
BigDecimal 常用的构造方法如下。
BigDecimal(double val):实例化时将双精度型转换为 BigDecimal 类型。
BigDecimal(String val):实例化时将字符串形式转换为 BigDecimal 类型。
BigDecimal add(BigDecimal augend) // 加法操作 BigDecimal subtract(BigDecimal subtrahend) // 减法操作 BigDecimal multiply(BigDecimal multiplieand) // 乘法操作 BigDecimal divide(BigDecimal divisor,int scale,int roundingMode ) // 除法操作
char a='a';
char b='A';
char c='哈';
内存大小
占两个字节,在C中是一个字节,而且它可以存储中文
这是C做不到的C言中使用 ASCII 表示字符, 而 Java 中使用 Unicode 表示字符. 因此一 个字符占用两个字节, 表示的字符种类更多, 包括中文
在Java中,char类型表示的是UTF-16的一个代码单元,而不是Uncoide的字符 字符集和char的关系
布尔类型 booleanboolean b=true;
boolean b=false;
注意点
boolean只有两个值,真就是true,假就是false
Java 的 boolean 类型和 int 不能相互转换 , 不存在 1 表示 true, 0 表示 false 这样的用法
如何将boolean变成0或者1
boolean类型在我们的官方文档写的是 It’s virtual machine dependent.// 由虚拟机自己实现
- 我们都知道,Java语言中有个boolean类型。每个boolean类型的变量中存储的是一个true或者是false的逻辑值。那么存储这个逻辑值,需要多大的空间呢?从理论上来讲,存储这个逻辑值只需要1个位(bit)就可以了,所以很多教科书上谈到这个问题的时候,也说boolean类型的数据在内存中只占1个位。
- 但是稍微有点计算机常识的人都知道:计算机完成寻址操作的时候,是以字节为最小单位进行的。也就是说每次要读取内存中数据的时候,最小只能精确到1个字节,不能单独读取某个位上的信息。如果boolean类型的变量的值只占1个位,计算机每次读取到1个字节的信息,里面会包含8个boolean变量的值。计算机就不得不通过某种算法去确定这8个值中,哪一个才是我们要找的值。这样做显然非常不合理,因为要完成这个“8选1”的操作又会增加运算工作量。那么Java虚拟机到底是怎样存储boolean值呢?
- 在《虚拟机规范》中,对boolean类型的存储有专门的解释,文中说到:“虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,(因此)每个boolean元素占8位”。
- 变成int类型,是因为我们很多的CPU都是32位,这样的存取效率是最高的
对于这种转换但是无信息丢失的情况我们的隐式类型转换是会自动发生的
int a=10;
long b=20;//发生了隐式类型提升
long c=a+b;//发生了隐式类型提升
强制类型转换对于转换可能存储精度损失的情况我们必须采用强制类型转换
小类型 变量=(小类型) 大类型数值
int a = 0;
double b = 10.5;
a = (int)b;
int a = 10;
byte a=20;
byte b=256;//发生编译错误,因为byte的值位-128到127 所以需要强制类型转换
boolean b = false;
b = (boolean)a; // 编译出错, 提示不兼容的类型
关于一个byte和byte的现象
byte a=20;
byte b=30;
byte c=a+b;//会发生编译报错
可以写成
final byte a=20;
final byte b=20;
byte c=a+b;
可以在赋值中使用二元运算符,是一种很方便的简写形式
int x=1;
x+=2;
x=x+2;
int x=1;
x+=3.5;//相当于(int)(x+3.5)
自增/自减运算符 ++ –int a = 10;
int b = ++a;
System.out.println(b);
int c = a++;
System.out.println(c);
结论:
关系运算符主要有六个:
== !=< ><= >=
int a = 10;
int b = 20;
System.out.println(a == b);
System.out.println(a != b);
System.out.println(a< b);
System.out.println(a >b);
System.out.println(a<= b);
System.out.println(a >= b);
注意: 关系运算符的表达式返回值都是 boolean 类型
逻辑运算符逻辑运算符主要有三个:
&& || !
注意: 逻辑运算符的操作数(操作数往往是关系运算符的结果)和返回值都是 boolean,如果操作数不是boolean,那么编译不通过
逻辑与 &&
规则: 两个操作数都为 true, 结果为 true, 否则结果为 false.
int a = 10;
int b = 20;
int c = 30;
System.out.println(a< b && b< c);
逻辑或 ||
规则: 两个操作数都为 false, 结果为 false, 否则结果为 true
int a = 10;
int b = 20;
int c = 30;
System.out.println(a< b || b< c)
逻辑非 !
规则: 操作数为 true, 结果为 false; 操作数为 false, 结果为 true(这是个单目运算符, 只有一个操作数).
int a = 10;
int b = 20;
System.out.println(!a< b);
&&与||都是短路运算符&& 和 || 遵守短路求值的规则.
System.out.println(10 >20 && 10 / 0 == 0); // 打印 false
System.out.println(10< 20 || 10 / 0 == 0); // 打印 true
我们都知道, 计算 10 / 0 会导致程序抛出异常. 但是上面的代码却能正常运行, 说明 10 / 0 并没有真正被求值.
结论:
& 和 |
& 和 | 如果操作数为 boolean 的时候, 也表示逻辑运算. 但是和 && 以及 || 相比, 它们不支持短路求值.
System.out.println(10 >20 & 10 / 0 == 0); // 程序抛出异常
System.out.println(10< 20 | 10 / 0 == 0); // 程序抛出异常
Java支持的三位运算符
condition ? expression1 : expression2
int max=a>b?a:b; //返回a 和 b中较大的那个值
位运算符java 中对数据的操作的最小单位不是字节, 而是二进制位.
位运算符主要有四个:
& | ~ ^
位操作表示 按二进制位运算. 计算机中都是使用二进制来表示数据的(01构成的序列), 按位运算就是在按照二进制位的每一位依次进行计算
移位运算符有三个:
<< >>>>>
都是按照二进制位来运算.
int a = 0x10;
System.out.printf("%x\n", a<< 1);
// 运行结果(注意, 是按十六进制打印的)
20
int a = 0x10;
System.out.printf("%x\n", a >>1);
// 运行结果(注意, 是按十六进制打印的)
8
int b = 0xffff0000;
System.out.printf("%x\n", b >>1);
// 运行结果(注意, 是按十六进制打印的)
ffff8000
int a = 0xffffffff;
System.out.printf("%x\n", a >>>1);
// 运行结果(注意, 是按十六进制打印的)
7fffffff
关于移位大小的规定
先看一段代码
System.out.println(1 + 2 * 3);
结果为 7, 说明先计算了 2*3 , 再计算 1+
另外一个例子
System.out.println(10< 20 && 20< 30);
此时明显是先计算的 10< 20 和 20< 30, 再计算 &&. 否则 20 && 20 这样的操作是语法上有误的(&& 的操作数只能是boolean).运算符之间是有优先级的. 具体的规则我们不必记忆. 在可能存在歧义的代码中加上括号即可.
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流