变量和类型
变量 指的是 程序运行时 的 可变的量,相当于开辟一块内存空间来保存一些数据
类型 则是 对 变量的种类 进行了 划分,不同的类型 的 变量 具有不同特性
我们所讨论的"变量"主要 和 我们的"内存"这样的硬件设备密切相关
?
我们先来讲讲变量。
变量就像一个个大小不一的盒子(类型不同的变量),盒子的空间里面装着不同的宝藏,
并且盒子里的宝藏是可以进行替换(覆盖) 的,只要放得下。如果放不下,咱就不要它。(Java是一门强势语言,不存在截断的情况,超出类型的取值范围的值,强行存入,程序会报错,并且程序从该处结束运行)
也就是说 不同类型的变量的空间 存储的数据 都是不同的,且变量的值是可以改变的
?
而变量的存储空间从何而来?这里我们就要讲讲 内存
打个比方
内存 就像 一个长长的街道,街道上住着形形色色的人(各种各样的变量)
就好比 类型不同 值相同 且变量不同 的数据[两个年纪相同的人,但是,是两个人不是一个人,也不是一个家庭的成员 char a = 10;int b = 10;]
和 类型相同值不同 且变量不同 的数据(生在同一个家庭,有兄弟姐妹,他们独特的存在。 int a =10;int b =20;)
和 类型和值都相同 且变量不同 的数据(你可以认为就是一对双胞胎,虽然他们出生一个家庭,同时出生,长得一模一样,但确确实实是两个人,int a=0;int b =0;)
和 类型和值都不同 且变量不同 的数据(你可以认为是两个完全不搭边的人,float a=3.14;int b = 5;)
变量 就好比 一个人的唯一性,是不可重复或分裂,在程序中一个变量是不可以被重复定义的,在现实生活中,你总不能说人会分身吧。
而且变量的存储的数据 是可以被改变的,唯一不变的就是变量本身(int a;a就是变量本身),
人也是一样的,可以改变自己的,为了成为更好的自己,一直在努力的各位。唯一不变的就是 我们还是自己,不可能变成另一个人,取代别人的存在(这个别杠,少看点剧)
只要是个人都有自己的家(变量都有自己的存储空间),家是有门牌号的,而 门牌号 就相当于 变量存储空间的地址
内存就好比是这一条街道所有人的信息的汇总
?
切回实际
真正想要理解内存,需要理解 冯诺依曼 体系,因为现在的计算机都是以这个体系来建立我们逻辑关系的 小常识: 现代计算机之父 就是 约翰.冯.诺依曼。又是一个聪明绝顶之人’
冯诺依曼体系 由五个部分组成
1、输入设备,2、输出设备,3、外存储器,4、内存储器,5、运算器和控制器(两者组成的,也就是所谓的CPU)
冯诺依曼体系结构图
1,2这两个部分就不用我解释了(生活例子:键盘和屏幕),我们重点讲讲 外储存器 和 内存储器 有何区别?
举个列子
买手机,商家可能会问你 你是要 8G+258G 还是 4G+64G 等等。
我们可以看到两块内存(小的内存,大的外存),我们都是 小一点的内存越大,玩游戏越顺畅。后面大的那个内存,说明你可以存很多数据到手机里,如果你是258的,都不够用,我想说汝分享否?
有的人会说,为什么我苹果的内存(运行内存)没有 安卓的大,玩同一个游戏,为什么它比我卡?
因为 苹果手机的每一个部件都是为苹果手机专门制造设计的,所以系统之间的兼容性很强,所以在玩游戏的时候,所占内存较小
而安卓机,就是一个组装机,懂得都懂,一个手机可能有几个厂家的部件组装而成,所以兼容性不是很好,所以在玩游戏的时候,所占内存较大
说白了就是,苹果房子的每一块转都是无缝链接,每一块砖的大小形状都是相同的,所以墙面光滑如玉(原装就是强[贵])(打游戏,6的飞起)。
而安卓房子,就像是每一个砖之间是存在间隔(系统不兼容,导致内存有所浪费),再加上每一块砖的大小形状有着一些或很大的差别(又会占用一些内存的空间),导致墙面不光滑(卡的飞起,成为甩锅的对象)
当然国产机现在越做越好(贵)[好 == 贵].很好,我选小米
电脑内存图片示例(运行内存 RAM)
?
CPU(运算器和控制器)
CPU当中 运算器(逻辑运算)和 控制器(控制程序的运行【怎么运行,从哪里运行】 和 停止 【停止的条件,停止】,停止之后又该怎么做?)
这里我们不做深究,我们只是在 了解 内存的过程中 了解一下 冯洛伊曼体系 ,其重点是内存储器,也就是我们的内存。
总结:
变量 就是存储在 内存(内存储器【硬件】)当中,当变量的类型不一样,存储的数据也就不一样。它所占内存大小就不一样。
学了C的,都知道,变量在程序运行时,才在内存中申请空间,程序结束之后,要将空间还给 内存。
所以 变量的空间的创造和销毁(回收),都与我们的内存储器【硬件】有这密切的关系
这样就回到我们的最初的标题注释的内容,"变量"主要和我们的 "内存"这样的硬件设备密切相关
?
拓展
变量的命名:
小驼峰形式 intMax,第一词的首字符小写,后面词的首字符大写(见附图 驼峰)
在Java中 标识符由数字、字母、下划线、$,组成
表示开头不能是数字( int a2;right, int 2a;error)
注意 $ 和 下划线, 虽然可以这么写 int $a,int _a, 但不建议(别给别人挖坑,保持良好代码习惯)。
举个例子,有一个二货这么写 int ______a=0; ,你告诉我这有几个下划线?,所以别这么写
?
JavaSE(Java Platform, Standard Edition - Java平台标准版的简称) 中的 八大基本数据类型
1.整形变量( 4 byte)
基本语法格式
int 变量名 = 初始值;
代码示例
public class DataTypeAndOperator{
public static void main(String[] args){
int num = 10;
System.out.println(num);
System.out.printf("%d\n",num);
}
java一共有三种打印方式
}
效果图
?
整形变量的取值范围
提醒:
在 Java中,是没有无符号类型的(unsigned ),统一是 有符号的(signed ),就是 有符号数【正负数】,
也就意味着我们的数值转化为二进制时,最高位永远都是符号位
例子
int 为 4 byte,即 32 bit 位,即 32位 二进制数
(8 bit = 1 byte; 1024 byte = 1 kb; 1024 kb = 1mb; 1024 mb = 1gb; 1024 gb = 1 tb; 1024 tb = 1pb.)
最高位为符号位,那么剩下的31位,都是数值位,就是能表示出 2^31 个数字
最高位【符号位】为 0,表示为正,数值位全部取1,得到最大值 2^31-1,
因为0也算一个数字了,所以它能表达的最大值,就是 能表达数字的个数 减去一个1.(照理说是从1算起的,那么就是2^31),所以我们要减一(附图)
最高位【符号位】为 1,表示为负,数值位全部全1,得到最小值【-2^31,这个就是从-1算起,所以是-2^31】(图10)
附图
?
那么在 Java中 如何求 取值范围的最大值和最小值?
在此之前,我们需要 integer 是什么?
int是java提供的8种原始数据类型之一。Java为每个原始类型提供了封装类,Integer是java为int提供的封装类。
小知识点,
-
除了 int 和 char,的封装类分别是 Integer,Character 之外 其它 6 个原始数据类型 都是首字符大写(Byte、Short、Float、Double、Long、Boolean) ? -
八 个原始数据类型: byte(1)、 char(2)、short(2)、 int(4)、 float(4)、 double(8)、 long(8), 、boolean[布尔类型] (没有明确规定它的大小。在JVM中 1字节 或者 1 bit) int的默认值为0,而Integer的默认值为null -
即Integer可以区分出未 未赋值 和 值为0 的区别,int则无法表达出未赋值的情况,例如,要想表达出 没有参加考试 和 考试成绩为0 的区别,则只能使用 Integer -
另外,Integer提供了多个与整数相关的操作方法,例如,将一个字符串转换成整数,Integer中还定义了表示整数的最大值和最小值的常量。
程序例子:
int的默认值为0,而Integer的默认值为null,
public class DataTypeAndOperator{
public static void main(String[] args) {
int a;
System.out.println(a);
}
}
效果图
程序出错,不应该输出为 0吗? 因为在 Java中 一个局部变量,没有进行初始化赋值,那么就不能够使用它,如果运行,程序会报错。 这里体现出 Java的安全性 ps:在Java中是没有全局变量的,这点请记住
另外注意一点,在方法(main方法)中,定义的量叫做变量 在类的内部,方法的外部的变量,叫做属性(又称 成员变量), 比如说 我就在 DataTypeAndOperator 的花括号后面建立 int a 的变量 这时,a就是成员变量(属性),它的默认值就是 0。
现在我们来在Java中求 int 类型 所能存储最大值和最小值
public class DataTypeAndOperator{
public static void main(String[] args){
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
}
}
上下两者写法师等价的。
最大值+1,最小值-1,会导致数值溢出(相当于碗就这么点大,容量有限,你非要装,肯定是会溢出的),那么效果如何?
public class DataTypeAndOperator{
public static void main(String[] args){
System.out.println(Integer.MAX_VALUE+1);
System.out.println(Integer.MIN_VALUE-1);
}
}
从 效果图 和 圆形图 可以看出,正数 0~2^31-1,负数 -1 ~ -2^31.,-2 ^31 代替了 2^31的位置,从而形成了一个圆形范围(取值循环)
最大值加一,取得最小值;最小值减一,取得最大值
?
Java有一个地方狠拐。。
public class DataTypeAndOperator{
public static void main(String[] args) {
int 钱 = 10;
System.out.println(钱);
}
}
因为 Java 是Unicode字符集,它包含ASCII码字符集,拉丁文,中文 等等… 所以 在 Java 中 能以中文作为变量。 但是最好不要这么写,有点过了。。。
?
注意事项
- int 表示变量的类型是一个整形,另外 在 Java中 int 是没有无符号类型的(unsigned int),统一是 有符号的int(signed int)
- 变量名是变量的标识(int a,a就是变量名),后续都是通过这个名字来使用变量
- Java 中 = 表示赋值,意思是给变量设置一个初始值。(和数学不一样,数学里是等于的意思)
- 初始化操作时可选的,但是 建议 创建变量的时候都显式初始化。(尤其是局部变量,不初始化,程序会报错)
- 最后不要忘记分号,否则会编译失败
- // 表示注释,注释作为代码的解释说明部分,不参与编译运行。
?
2.长整形变量(长整形:long 8 byte)
基本语法格式
long 变量名 = 初始值;
?
注意 在Java中是没有long long类型的。
?
long 的取值范围
long : 8 byte == 64 bit
除去一个符号位,还剩63位,也就是说 取值范围为 -2^63 ~ 2^63-1
long类型的数据的最大值为 2^63-1,最小值为 -2^63
?
程序如下:
public class DataTypeAndOperator{
public static void main(String[] args) {
long a = 10l;
代码习惯!!!
long long b =10;
System.out.println(Long.MAX_VALUE);
System.out.println(Long.MIN_VALUE);
}
}
注意事项
注意事项: 1. 基本语法格式和创建 int 变量基本一致, 只是把类型修改成 long 2. 初始化设定的值为 10L , 表示一个长整型的数字. 小写的 l,不建议写。 3. 使用 10 初始化也可以, 10 的类型是 int, 10L 的类型是 long, 使用 10 L 更好一些. 4. Java 中 long 类型占 8 个字节. 表示的数据范围 -2^63 -> 2^63-1
?
3 双精度浮点型变量(8 byte)
基本语法
double 变量名 = 初始值;
代码示例
public class DataTypeAndOperator{
public static void main(String[] args) {
double d = 10.1;
System.out.println(d);
}
}
拓展代码1
public class DataTypeAndOperator{
public static void main(String[] args) {
int a =1;
int b =2;
System.out.println(a/b);
}
}
讲道理 结果应该是0.5, 但是在Java中整数除以整数,结果只能是整数。 所以 结果取 0.5 整数位 0
?
那么我么想得到 0.5,该怎么写?
代码如下
public class DataTypeAndOperator{
public static void main(String[] args) {
double a =1.0;
double b =2.0;
如果这样写呢?
System.out.println(a/b);
}
}
?
拓展代码2
public class DataTypeAndOperator{
public static void main(String[] args) {
double a =1.1;
double b =2.0;
System.out.println(a*a);
}
}
照理说 结果应该为 1.21 但是结果为 1.2100000000000002,后面多了一个 2,这是为什么呢? 因为在程序里,小数是没有精确的数字的 也就是说 小数本身是没有一个精确的数字的。它只能精确到几位
// float类型,只能精确到小数点后 6 位
// double类型,只能精确到小数点后 16 位
?
4 单精度浮点型变量(4 byte)
基本格式:
float 变量名 =初始值;
代码示例
public class DataTypeAndOperator{
public static void main(String[] args) {
float a =1.0f;
为什么不这样写?
因为小数是默认 占 8 字节,也就是默认 double类型
你需要知道 Java是一门强势语言,赋值一定要类型相同,否则代码进行编译时,是不会通过的,会报错。
所以在 java 当中,对 单精度浮点型,也就是对float类型的变量,进行赋值时,小数后面一定要加上 小写 f 或 大写 F
12.5f 或 12.5F 这样写,就表明了 小数 12.5 是一个单精度浮点型数据,而非双精度浮点型数据
System.out.println(a);
}
}
?
注意:
float 类型在 Java 中占四个字节, 同样遵守 IEEE 754 标准. 由于表示的数据精度范围较小, 一般在工程上用到浮点数都
优先考虑 double, 不太推荐使用 float
?
5 字符类型变量( 2 byte)
基本格式:
char 变量名 = 初始值;
代码示例
public class DataTypeAndOperator{
public static void main(String[] args) {
char a ='w';
char b = '强';
System.out.println(a);
System.out.println(b);
}
}
由效果图可知 char 类型能够存的下 汉字 一个汉字占 2 个字节,也就意味着 char 在 Java 当中,所占内存大小为 2 字节
?
代码2
public class DataTypeAndOperator{
public static void main(String[] args) {
char a =97;
System.out.println(a);
}
}
由图可知 在 Java 中,将 整数 赋给char类型的变量,Java会将 整形数据 转换成 ASCII码值,再将其打印,其结果是 ASCII码值 所对应的 字符
?
注意事项:
1. Java 中使用 单引号 + 单个字母 的形式表示字符字面值. 2. 计算机中的字符本质上是一个整数. 在 C 语言中使用 ASCII 表示字符 而 Java 中使用 Unicode 表示字符. 因此一个字符占用两个字节, 表示的字符种类更多, 包括中文.
?
6 字节类型变量(相当于 C语言里面的char,内存大小 1 byte)
基本语法格式:
byte 变量名 = 初始值
代码如下:
public class DataTypeAndOperator{
public static void main(String[] args) {
byte a =9;
另外 和 int 它们一样,赋值超过它的取值范围,程序会报错
1 byte = 8 bit
除去符号位,取值范围为 -2^7 ~ 2*7-1(-128~127)
byte b = 130;
System.out.println(b);
由图可知,130 超出去 byte 能存储的值,系统会认为该值的类型 是 其他类型,且所占字节比它大。
两者之间无法进行赋值
注意: 在Java中,所有数据,都是这样,拥有属于它们自己的取值范围, 一个类型的变量,只能存储该类型的取值范围以内的值
超出了,我就存不了。
就是说 多一分不行,少一分可以,因为我放得下
类型 所占字节大的,可以放下 比它 所占字节要小的类型的值
就是说 一个类型的取值范围比另一个类型的取值范围 要大时, 取值范围大的类型,可以存放 取值范围小的类型的所有取值
说白了 就是 大吃小,小吃不下大。
System.out.println(a);
}
}
附图1
附图2
附图3(用 long 和 int 做比较)
?
另外 提示一下, 在Java当中,是没有sizeof 这种操作符的。
就是说 在 Java 中, 类型所占字节的大小,你需要自己记住
?
注意事项:
1. 字节类型表示的也是整数. 只占一个字节, 表示范围较小 ( -128 -> +127 ) 2. 字节类型 和 字符类型 互不相干 (不要混淆)
?
7 短整型变量(2 byte)
基本语法格式
short 变量名 = 初始值;
代码示例
public class DataTypeAndOperator{
public static void main(String[] args) {
short a = 2;
2 字节 == 16 byte
除去了符号位
它的取值范围为 -2^15 ~ 2^15-1( -32768 ~ 32767)
System.out.println(a);
}
}
?
8 布尔类型变量
基本语法格式:
boolean 变量名 = 初始值;
代码示例:
public class JavaFirst {
public static void main(String[] args) {
boolean flag = true;
System.out.println(flag);
boolean flag3 = false;
System.out.println(flag3);
相信大家都是有一定的C语言基础的
在 C语言中,0为假, 非零为真
那么我这么写。
boolean flag2= 2;
这样写是不行的
在Java当中 boolean 类型,只有 2个取值
要么是 true,要么是 false
附图2
我可以这样写吗?
boolean flag5 = true +1;
boolean flag6 = false+1;
图 4
}
}
附图1
附图2
那么 boolean 的值 只能为 ture 和 false
?
附图3
附图4
还有一个原因,true 和 false 根本就不是 一个数,所以根本无法相加
?
注意事项:
1. boolean 类型的变量只有两种取值, true 表示真, false 表示假.
2. Java 的 boolean 类型和 int 不能相互转换, 不存在 1 表示 true, 0 表示 false 这样的用法.
3. boolean 类型有些 JVM 的实现是占 1 个字节, 有些是占 1 个比特位, 这个没有明确规定
假如
有一天 你碰到了一道题,有4个选项,让你找出那个是对的(问布尔类型的大小)
你看其他三项是不是明确错误的(就是 一个选项 是 1 byte,其它的 都是 几个字节,那就选 1字节的,懂吧)
至此Java的8大基本数据类型结束了。
?
下面我们来讲讲其他类型
字符串类型变量
字符串类型 是Java特有的类型,不属于 8大基本数据类型。
字符串 就是把 一些字符 放到一起。
基本语法格式:
String 变量名 = "初始值";
代码示例:
public class JavaFirst {
public static void main(String[] args) {
String str = "hello";
System.out.println(str);
}
}
?
知识点, String 是 字符串类型,又称 引用类型
在 Java 中 数据类型 主要分为 2部分:
数值类型(基本数据类型) : 整数(byte、short、int、long)、浮点数(float、double)、字符(char)、布尔(boolean)
引用类型: String、数组、类、接口、枚举
怎么判断 一个变量 是不是 引用类型,你就看这个变量存储的值,是不是一个地址
细品!! 提示一下 数组名是什么? 嗯~~~
?
拓展
public class JavaFirst {
public static void main(String[] args) {
1
System.out.println("hello"+"world");
从效果图可以看出 它们拼接成一个字符串
也就是说 在 Java 中,两个字符串相加,就能拼接成一个字符串。
即 + 号, 等于 拼接 命令
2
System.out.println("hello"+10+20);
由 结果得知, 字符串和其它数据类型int 10 和 int 20,使用 + 拼接,其结果就是拼接成一个字符串
语法格式:字符串 + 其他数据类型(将其后的面的数据,不进行处理,转换成字符串,进行拼接)
3
System.out.println(10+20+"hello");
由结果得知, 其他类型数据int 30 和 字符串,使用 + 拼接
虽然结果还是一个字符串, 但 其他类型的数据,在拼接之前,就已经 处理过了。
4
System.out.println(10+""+20+"hello");
由结果得知, 当 一个 非字符串类型int 10 与 "" ,使用 + 拼接时,会成为 一个字符串(就相当于 10 带上一个头套)
那么 这就是 第二种情况( 字符串"10" 和 其他类型数据(int 20) 拼接,其结果还是字符串["1020"])
和 第一种情况(字符串("1020")和 字符串("hello") 拼接), 其结果 就是 "1020hello"
a = 10; b = 20(取巧)
System.out.println("a = " + 10 + "; b = " + 20);
运用了 1 和 2 两种情况
字符串("a = ")和 其他类型数据 int 10 ,使用 + 号,进行拼接,使其成为一个字符串 “a = 10”
字符串("a = 10") 和 字符串 ("; b = "),使其成为一个字符串“a = 10; b = ”
字符串("a=10; b=") 和 其他数据类型 int 20,使用 + 号,进行拼接,使其成为一个字符串 "a = 10; b = 20"
}
}
图6
?
图7
图8
图 9
图 10
?
注意事项: 1. Java 使用 双引号 + 若干字符 的方式表示字符串字面值. 2. 和上面的类型不同, String 不是基本类型, 而是引用类型(后面重点解释). 3. 字符串中的一些特定的不太方便直接表示的字符需要进行转义.
?
转义字符
转义字符 | 释义 |
---|
1 。??\ ? | 在书写连续多个问号时使用,防止他们被解析成三字母词 | 2,?? \ ’ | 用于表示字符常量’ | \“ | 用于表示一个字符串内部的双引号 | 3. ?? \ \ | 用于表示一个反斜杠,防止它被解释为一个转义序列符。 | \a | 警告字符,蜂鸣 | \b | 退格符 | \f | 进制符 | \n | 换行 | \r | 回车 | \t | 水平制表符 | \v | 垂直制表符 | \ddd | ddd表示1~3个八进制的数字。 如: \130 X | \xdd | dd表示2个十六进制数字。 如: \x30 0 |
注意!! 标有123的,转义字符中间是没有空格,因为我不给空格 它显示不了 \ 的。
?
程序实例
public class JavaFirst{
public static void main(String[] args) {
String s1 = "bit";
System.out.println(s1);
String s2 = " \"bit\" ";
System.out.println(s2);
String s3 = "\\bit\\";
System.out.println(s3);
String s4 = "\\\\bit\\\\";
System.out.println(s4);
}
}
图11
图12
图13
图 14
图15
?
变量的作用域
就是该变量能生效的范围, 一般是变量定义所在的代码块(定义在大括号里
如果 该变量 出了(不在) 创建它的 大括号里,来到外道大括号外面,该变量就不能使用)
讲到这里 我需要提醒一下的是
在 Java中 变量 分为两种:
1.成员变量;普通成员变量,静态成员变量(在后面讲类和对象的时候,会重点讲解)
2.局部变量
?
我们今天所讲的 主要就是 局部变量的作用域
程序一
public class JavaFirst{
int b =0;
此时 b 就是成员变量,也就是说,在 类的里面,main方法的外面 定义的变量,称为成员变量
public static void main(String[] args) {
int a = 10;
}
public static void main2(String[] args) {
System.out.println(a);
}
}
图16
?
程序二
public class JavaFirst{
public static void main(String[] args) {
{
int a =10;
}
System.out.println(a);
}
}
图 17
这样也不行,因为 局部变量 a 的作用域,只在创建它的大括号里能用,出了大括号就不能用
?
接着上一个例子,那如果我这样写呢?
public class JavaFirst{
public static void main(String[] args) {
int a =0;
{
a = 99;
}
System.out.println(a);
}
}
图18
由图可知,是可以输出a 的值,且a的值为 99,这是因为 a == 99,和输出语句,都在 局部变量 a 的作用域内(在创建局部变量a,所在的大括号里)
?
如何判断变量的作用域?
去找 离该变量最近的大括号,该大括号所包含的范围,就是 变量的作用域
?
变量的命名规则
硬性指标:
1. 一个变量名只能包含数字, 字母, 下划线
2. 数字不能开头.
3. 变量名对大小写很敏感. 即 num 和 Num 是两个不同的变量.
注意: 虽然语法上也允许使用中文/美元符($)命名变量, 但是 强烈 不推荐这样做.</font>.
软性指标:
1. 变量命名要具有描述性, 见名知意(英文).
2. 变量名不宜使用拼音(但是不绝对,最好别用就对了).
3. 变量名的词性推荐使用名词(英文).
4. 变量命名推荐 小驼峰命名法, 当一个变量名由多个单词构成的时候, 除了第一个单词之外, 其他单词首字母都大
写.
程序1
public class JavaFirst{
public static void main(String[] args) {
int 3a = 0;
int a3 = 0;
}
}
图19
由图可知 符合 变量的命名规则 硬性指标 第二条 不能以数字开头
?
程序2
public class JavaFirst{
public static void main(String[] args) {
int Num = 1;
int num = 2;
System.out.println(Num);
System.out.println(num);
}
}
图20
由结果得知 符合 变量命名规则 硬性指标 第三条 变量名对大小写很敏感. 即 num 和 Num 是两个不同的变量.
?
常量
每种类型的变量 也对应着 一种相同类型 的 常量.
常量 指的是运行时类型不能发生改变.
常量主要有以下两种体现形式:
1.字面值常量
10 | int 字面值常量(十进制) |
---|
010 | int 字面值常量(八进制) 由数字 0 开头. 010 也就是十进制的 8 | 0x10 | int 字面值常量(十六进制) 由数字 0x 开头. 0x10 也就是十进制的 16 | 10L | long 字面值常量. 也可以写作 10l (小写的l) | 1.0 | double 字面值常量. 也可以写作 1.0d 或者 1.0D | 1.5e2 | double 字面值常量. 科学计数法表示. 相当于 1.5 * 10^2 | 1.0f | float 字面值常量, 也可以写作 1.0F | true | boolen 字面值常量, 同样的还有 false | ‘a’ | char 字面值常量, 单引号中只能有一个字符 | “abc” | String 字面值常量, 双引号中可以有多个字符. |
?
2. final 关键字修饰的常量
public class JavaFirst{
public static void main(String[] args) {
int a = 10;
a = 99;
System.out.println(a);
final int b = 10;
b = 20;
System.out.println(b);
}
}
图21
由图可知, b 现在就相当于是 整形常量,值是无法改变的(另外体现出:常量的值,只能初始化一次,不像变量可以重复赋值)。
? 另外: 我建议常量标识符 用大写好一点,小写也行。你可以认为这是一种默认代码习惯 即:final int B = 10; System.out.println(B);// 10
小知识点:
常量 在程序编译时,就已经确定了其值是什么
代码示例
public class JavaFirst{
public static void main(String[] args) {
int a =10;
final int b =20;
意味着 常量 的 值 确定的速度非常快
有多快,比变量快(变量已经哭晕在厕所)
}
}
?
类型转换
java 作为一个强类型编程语言, 当不同类型之间的变量相互赋值的时候, 会有教严格的校验
int 和 long/double 相互赋值
public class JavaFirst{
public static void main(String[] args) {
int a =10;
long b =20;
a=b;
b=a;
(图22)
你程序还没运行,就提示你有错误,你想出错都难(注意 a = b 下面的红色波浪线就是在提醒你的写法出错了)
}
}
图22
?
那么 你说,我就想 把 b 的值 存入 a 里面,好的,没问题,这就需要强制类型转换
public class JavaFirst{
public static void main(String[] args) {
int a =10;
long b = 20;
a = (int)b;
System.out.println(a);
}
}
图23
结果得知,是可行的。 但是注意一点,任何强制类型转换都是有风险的,你再牛逼也有翻车时候
?
结论:
不同 数字类型 的 变量 之间赋值, 表示 范围更小的类型 能隐式转换成 范围较大的类型, 反之则不行.
?
int 和 boolean 相互赋值
public class JavaFirst{
public static void main(String[] args) {
int a = 10;
boolean b = true;
b = a;
a = b;
}
}
图24
结论: int 和 boolean 是毫不相干的两种类型, 不能相互赋值
?
int字面值常量 给 byte 赋值
public class JavaFirst{
public static void main(String[] args) {
byte a = 100;
byte b = 256;
}
}
图25
结论: 使用字面值常量赋值的时候, Java 会自动进行一些检查校验, 判定赋值是否合理
?
拓展
程序一
public class JavaFirst{
public static void main(String[] args) {
byte a = 10;
byte b = 20;
byte c = a+b;
这样写是错的。
}
}
图26
?
程序二
public class JavaFirst{
public static void main(String[] args) {
byte a =10;
byte b =20;
byte c = 10+20;
System.out.println(c);
这样写没错,为什么?
}
}
图29
?
程序三
public class JavaFirst{
public static void main(String[] args) {
int a = 0;
double b = 10.5;
a = (int)b;
System.out.println(a);
}
}
图28
?
结论:
使用 (类型) 的方式可以将 double 类型强制转成 int. 但是 1. 强制类型转换可能会导致精度丢失. 如刚才的例子中, 赋值之后, 10.5 就变成 10 了, 小数点后面的部分被忽略. 2. 强制类型转换不是一定能成功, 互不相干的类型之间无法强转
总得来说,只要是强制类型转换,都存在一定风险,正如我上面所说的 你再牛逼也会翻车。
?
类型转换小结
1. 不同 数字类型 的 变量之间赋值, 表示 范围更小的类型 能隐式转换成 范围较大的类型
(这里不是整形提升,就是单纯的 大吃小:数字类型 所占字节小的变量,它的所有取值,都可以 存储到 比它所占字节更大 的 数字类型 变量 当中).
2. 如果需要把范围大的类型赋值给范围小的, 需要强制类型转换, 但是可能精度丢失.
3. 将一个字面值常量进行赋值的时候, Java 会自动针对数字范围进行检查.
?
理解数值提升
程序实例
public class JavaFirst{
public static void main(String[] args) {
int a = 10;
long b = 20;
int c = a+b;
这样为什么会错呢?
因为CPU中,做类型提升时,小的类型会向大的类型进行类型提升(大的类型 所占字节 要大于4字节,否则,提升为整形)
也就是说 a 与 b,在进行加法运算时,发生类形提升,两者变为了 long 类型的数据
其结果当然也是 long 类型,所以无法将其运算结果赋给 int 类型的 变量 c
需要强制类型转换才能存进去, int c = (int)(a+b);
}
}
图27
?
讲到这里,有必要说一下 整形提升的意义何在?
? 为了效率高!.
?
类型提升小结:
1. 不同类型的数据混合运算, 范围小的会提升成范围大的.
2.由于计算机的 CPU 通常是按照 4 个字节为单位从内存中读写数据. 为了硬件上实现方便, 诸如 byte 和 short 这种低于
4 个字节的类型, 会先提升成 int, 再参与计算
?
int 和 String 之间的相互转换
int 转换 字符串
public class JavaFirst{
public static void main(String[] args) {
int a = 10;
String ret = String.valueOf(a);
System.out.println(ret);
}
}
图30
图31
?
字符串转换int
public class JavaFirst{
public static void main(String[] args) {
String ret = "123";
int i = Integer.valueOf(ret);
System.out.println(i);
}
}
图32
图33
?
运算符
算术运算符
基本四则运算符 + - * / %
+?? -?? ?* ?规则比较简单, 注意的是除法
程序一
public class JavaFirst{
public static void main(String[] args) {
int a = 1;
int b = 2;
System.out.println(a / b);
}
}
结果为 0,为什么呢?不应该是 0.5吗? 因为 两个整数相除,其结果也是整数, 所以 取结果的整数为 0,作为最后结果。
?
0 不能作为除数(重点)
public class JavaFirst{
public static void main(String[] args) {
int a =1;
int b =0;
System.out.println(a/b);
}
}
图35
该错误被称为 异常错误(术语) 只要程序抛出 异常错误,程序在异常错误的位置,结束程序的运行
?
% 取余(求模/取模,说白了就是取余数)
public class JavaFirst{
public static void main(String[] args) {
System.out.println(10%3);
System.out.println(11.5 % 2);
}
}
图36
图37
?
来看一道题
我赌你们有些人绝对会算错下面取余的题
public class JavaFirst{
public static void main(String[] args) {
System.out.println(-10%3);
System.out.println(10%-3);
System.out.println(-10%-3);
}
}
?
图38
?
增量赋值运算符(复合运算符) +=?? -=?? *=?? /=?? %=
public class JavaFirst{
public static void main(String[] args) {
int a = 10;
a+=1;
System.out.println(a);
short s = 10;
s= s+1;
s = (short)(s+1);
s += 1;
}
}
图39
图40
图41
?
自增/自减运算符 ++ –
后置加加
public class JavaFirst{
public static void main(String[] args) {
int a =10;
int b = a++;
System.out.println(a);
System.out.println(b);
}
}
图 42
?
前置加加
public class JavaFirst{
public static void main(String[] args) {
int a =10;
int b = ++a;
System.out.println(a);
System.out.println(b);
}
}
图43
?
后置 减减
public class JavaFirst{
public static void main(String[] args) {
int a =10;
int b =a--;
System.out.println(a);
System.out.println(b);
}
}
图 44
?
前置减减
public class JavaFirst{
public static void main(String[] args) {
int a =10;
int b =--a;
System.out.println(a);
System.out.println(b);
}
}
图45
?
结论:
1. 如果不取自增运算的表达式的返回值, 则前置自增和后置自增没有区别.
2. 如果取表达式的返回值, 则前置自增的返回值是自增之后的值, 后置自增的返回值是自增之前的值.
?
关系运算符(判断数据)
关系运算符主要有六个:
== != < > <= >=
public class JavaFirst{
public static void main(String[] args) {
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);
}
}
图46
?
拓展
在Java中,判断条件是否成立,是根据布尔类型的
public class JavaFirst{
public static void main(String[] args) {
if(true)
{
;
}
if(false)
{
;
}
}
}
?
逻辑运算符
逻辑运算符主要有三个:
&& || !
注意: 逻辑运算符的操作数(操作数往往是关系运算符的结果)和返回值都是 boolean 类型的数据(true 和 false)
?
逻辑与 &&
规则: 两个操作数都为 true, 结果为 true, 否则结果为 false
表达式1 && 表达式2,都为 true, 结果为 true, 否则结果为 false 而且 逻辑与 支持 短路 什么意思呢? 如果 表达式1 为 假,后面的表达式2就不执行了,因为没必要 逻辑或: 双true出true,有false出false 有一个false,整个表达式的结果就为 false,所以 表达式2 看与不看(执不执行)都没多大的关系
?
程序实例
public class JavaFirst{
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b && b < c);
}
}
图 47
?
逻辑或 ||
规则: 两个操作数都为 false, 结果为 false, 否则结果为 true
也存在 短路现象 表达式1 || 表达式2 有 true 出 true,双 false 出 false 只要表达式1 为真(true),整个表达式就为true,表达式2 就不用执行了,因为不影响结果
程序一
public class JavaFirst{
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b || b < c);
}
}
图48
?
逻辑非 !
规则: 操作数为 true, 结果为 false; 操作数为 false, 结果为 true(这是个单目运算符, 只有一个操作数).
public class JavaFirst {
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println(!(a<b));
}
}
图49
图50
?
讲到这里,我们看到了逻辑运算符存在着“短路”的情况,现在我们来了解一下 “短路求值”
&& 和 || 遵守短路求值的规则
System.out.println(10 > 20 && 10 / 0 == 0); // 打印 false
System.out.println(10 < 20 || 10 / 0 == 0); // 打印 true
这里值详解 逻辑与,逻辑或 大家可以自己尝试着思考
public class JavaFirst{
public static void main(String[] args) {
System.out.println(10>20 && 10/0 == 0);
}
}
图51
?
那上面的代码这样写呢?
public class JavaFirst{
public static void main(String[] args) {
System.out.println(10<20 && 10/0 == 0);
}
}
图 52
?
结论
1. 对于 && , 如果左侧表达式值为 false,则表达式的整体的值一定是 false, 无需计算右侧表达式
2. 对于 ||, 如果左侧表达式值为 true, 则表达式的整体的值一定是 true, 无需计算右侧表达式
?
位运算符
Java 中对数据的操作的最小单位不是字节, 而是二进制位(bit).
位运算符主要有四个:
& | ~ ^
位操作表示 按二进制位运算. 计算机中都是使用二进制来表示数据的(01构成的序列), 按位运算就是在按照二进制位的每一位依次进行计算.
?
按位与 &
直接举例子
0000 1010
0000 1000 上下对应着看,如果两个二进制位都是 1, 则结果为 1, 否则结果为 0
0000 1000
结论
一个数的二进制数 与 另一个数的二进制数,相对应的二进制位上的数字,都是1,则结果为1,否则为0
假设两个数字 5 和 6,这里我们不写太多,就写 4个bit位,因为它们的数值都不是很大,就不浪费空间了
5 0101
6 0110
0100 其结果对应的十进制数为 4
?
按位或 |
如果两个二进制位都是 0, 则结果为 0, 否则结果为 1
依然是假设两个数字 5 和 6
5 0101
6 0110
0111 其结果对应的十进制数为 7
结论
一个数的二进制数 与 另一个数的二进制数,相对应的二进制位上的数字,都是0,则结果为0,否则为1
注意: 当 & 和 | 的操作数为整数(int, short, long, byte) 的时候, 表示按位运算, 当操作数为 boolean 的时候, 表示逻辑 运算.
?
注意!!!
&(按位与) 和 |(按位或) (不推荐使用,因为在Java当中使用的太少了,所以大家只需要了解一下就可以了)
& 和 | 如果操作数为 boolean 的时候, 也表示逻辑运算. 但是和 && 以及 || 相比, 它们不支持短路求值
System.out.println(10 > 20 & 10 / 0 == 0); // 程序抛出异常
System.out.println(10 < 20 | 10 / 0 == 0); // 程序抛出异常
不会有人这么奇怪的代码的,大家也别写!!!
?
按位异或 ^
如果两个数字的二进制位相同, 则结果为 0, 相异则结果为 1
依然是假设两个数字 5 和 6
5 0101
6 0110
0011 其结果对应的十进制数为 3
?
按位取反 ~
如果该位为 0 则转为 1, 如果该位为 1 则转为 0
我这里写一个 32 位 二进制数
-1的补码
1111 1111 1111 1111 1111 1111 1111 1111
进行按位取反
0000 0000 0000 0000 0000 0000 0000 0000
由结果得知:按位取反,是 数值位 和 连符号位一起取反,这一点需要注意
?
注意:
1. 0x 前缀的数字为 十六进制 数字. 十六进制可以看成是二进制的简化表示方式. 一个十六进制数字对应 4 个二进制位.
2. 十六进制的f 表示 10 进制的 15, 也就是二进制的 1111
3. printf 能够格式化输出内容, %x 表示按照十六进制输出.
4. \n 表示换行符
小要求:需掌握 进制 之间转换
这个不讲,真要讲的话,我的习惯可能写的非常细,再加上将每个进制转换都讲清楚的话,感觉要写一篇 接近 万字的博客
你们自行了解,我就不再增长本文章的长度了
?
移位运算
移位运算符有三个:
<< >> >>>
都是按照二进制位来运算
另外 整数在内存中存的是补码,详细看这篇文章0operator(操作符)- 重置版,C语言和Java 这方面是一样的
?
左移 <<
最左侧的二进制位不要了,最右边补一个零
例子
依然是 5 ,只不过这次是 32位,方便你们理解
0000 0000 0000 0000 0000 0000 0000 0101 (5)
5 << 1,5的二进制位 左移1位
0000 0000 0000 0000 0000 0000 0000 101 (最左侧的零其实已经挤掉了,由于整个二进制数向左移动一位,导致最右边空出一位)
最右边空出一位,补0
0000 0000 0000 0000 0000 0000 0000 1010 转换成10进制数 为 10
?
右移 >>:
最右侧位不要了, 最左侧补符号位
这里我就举6
0(最高位/符号位) 000 0000 0000 0000 0000 0000 0000 0110 (6)
6 >> 1 6的二进制位 右移1位
000 0000 0000 0000 0000 0000 0000 0011(最右侧的零其实已经挤掉了,由于整个二进制数向右移动一位,导致最左边空出一位)
补位, 按照原先的6的二进制数的最高位(符号位进行补位),1为负,0为正
是 0(正)就补0,是1(负)就补1
因为 6 的原先的二进制数的最高位是 0(正),所以我们要补个零
0000 0000 0000 0000 0000 0000 0000 0011 转换成10进制数 为 3
?
在假设一个 负数 -1
1111 1111 这里我们只写8位
-1 >> 1
111 1111 (最右侧的一其实已经挤掉了,由于整个二进制数向右移动一位,导致最左边空出一位)
补位, 按照原先的 -1 的二进制数的最高位(符号位进行补位),1为负,0为正
是 0(正)就补0,是1(负)就补1
因为 -1 的原先的二进制数的最高位是 1(负),所以我们要补个1
1111 1111 你会发现结果跟原来的二进制码相比,没有任何变化
?
无符号右移 >>>
最右侧位不要了, 最左侧补 0
这回特别点,0x ff ff ff ff
11111111 11111111 11111111 11111111
ff ff ff ff
0xffffffff >>> 1 :意思是0xffffffff 无符号右移一位
1111111 11111111 11111111 11111111
最左侧补 0(无符号右移,不管你符号位是0还是1,统一补0)
0111 1111 11111111 11111111 11111111
0x 7 f f f f f f f
另外请记住 在Java中是没有 无符号左移的,没有意义
左移都是补零,(因为二进制数最右边是没有符号位的,所以统一补0)
?
注意:
1. 左移 1 位, 相当于原数字 * 2. 左移 N 位, 相当于原数字 * 2 的N次方.
2. 右移 1 位, 相当于原数字 / 2. 右移 N 位, 相当于原数字 / 2 的N次方.
3. 由于计算机计算移位效率高于计算乘除, 当某个代码正好乘除 2 的N次方的时候可以用移位运算代替.
4. 移动负数位或者移位位数过大都没有意义(二进数数只有32位,你要移动35位,没意义)
?
条件运算符
条件运算符只有一个:
表达式1 ? 表达式2 : 表达式3
又称 三目运算符
意思是 表达式1 为真,返回表达式2,为假,返回表达式3
意味着 表达式1必须为 布尔表达式
举个例子 求两个数的最大值
public class JavaFirst{
public static void main(String[] args) {
int a = 10;
int b = 20;
int max = a > b ? a : b;
System.out.println(max);
}
}
图53
?
运算符的优先级
程序一
public class JavaFirst{
public static void main(String[] args) {
System.out.println(1 + 2 * 3);
}
}
图 54
?
接着程序一, 如果你想算出 9,用小括号将 1 和 2 括起来
因为小括号的优先最高,将其括起来,编译器先计算 小括号里的内容
程序如下
public class JavaFirst{
public static void main(String[] args) {
System.out.println((1 + 2) * 3);
}
}
图 55
?
运算符之间是有优先级的. 具体的规则我们不必记忆. 只需要根据自己的逻辑加括号就可以
小结
1. % 操作再 Java 中也能针对 double 来计算.
2. 需要区分清楚 前置自增 和 后置自增之间的区别.
3. 由于 Java 是强类型语言, 因此对于类型检查较严格, 因此像 && 之类的运算操作数必须是 boolean.
4. 要区分清楚 & 和 | 什么时候是表示按位运算, 什么时候表示逻辑运算.
整体来看, Java 的运算符的基本规则和 C 语言基本一致
本文在这里结束了。
|