变量和常量

在使用计算机编写程序的时候,我们怎么来表示生活中的各种类如年龄,性别,身份证号码等数据呢?
在Java中,我们使用变量和常量的概念表示
此外,生活中的数据分为可变和不可变的,比如年龄会随着时间而增长,而圆周率,普朗克常数这些数据是不会变化的
那我们可以用变量来表示前者,用常量来表示后者
变量
变量的作用域
一般来说,变量定义时所在的花括号范围即为变量的作用域


因为第二个花括号包含于第一个花括号里面,而a在第一个花括号里定义
因此第二个花括号也属于a的作用域
而如果在第二个花括号内定义,而在第一个花括号内使用,便会出现错误
因为此时a的作用域只有第二个花括号的范围

变量的命名规则
我们在命名变量的时候,只能使用数字,字母还有下划线,且不能使用数字开头
并且命名的时候,要做到见名知意,因为这能让我们阅读代码时更加高效
我们可不想一个月之后阅读自己代码的时候,花许多时间在思考a,b,c,asdfa变量都是干什么的
(当然,不只是方便自己)
为做到见名知意,我们可以采取以下原则
- 具有描述性
- 小驼峰命名法,也就是第一个单词首字母不大写,接下来的单词首字母都大写
如年龄最大值,可命名为maxAge
常量
字面值常量
| 字面值常量 | 含义 |
|---|---|
| 10 | 十进制数字 |
| 010 | 八进制数字 |
| 0x10 | 十六进制数字 |
| 10L / 10l | long类型数值 |
| 1.0 | double类型数值 |
| 1.5e2 | 同上, 相当于1.5 * 10 ^ 2 |
| 1.0f | float类型数值 |
| true | boolean类型字面值 |
| false | boolean类型字面值 |
| 'a' | 字符类型字面值 |
| "hello" | 字符串类型字面值 |
定义

(一旦定义,便不可修改)
Java中有八大基础数据类型和三大引用数据类型
八大数据类型

int
表示整数
一个int占4个字节
System.out.println(Integer.SIZE); //查看Integer类有多少个字段(比特位)
范围为: -2^31 ~ 2^31-1
System.out.println(Integer.MAX_VALUE);
long
表示范围更大的整数
一个long占8个字节
定义
long a = 100L;
long a = 100l;
范围为: -2^63 ~ -2^63-1
float
表示小数(浮点数)
一个float占4个字节
定义
float num = 1.1f;float num = 1.1F;
double
表示范围更大的小数
一个double为8个字节
注意点1
System.out.println(1 / 2);
打印结果为0
关于 / 运算符,若我们想要得到double类型的结果,至少需要有一个操作数为double
注意点2
double num = 1.1;System.out.println(num * num)
执行结果为:

之所以会出现精度误差,是因为在内存中使用有限的空间去存储无限的小数
char
表示各种字符(字符,数字或特殊符号)
一个char占2个字节
定义
char a = 'a'
byte
在网络传输,通信中起到重要的作用
取值范围为-128到127
一个byte占1个字节
short
表示范围更小的整数
一个short占2个字节
范围为: -32768 -> 32767
boolean
用来表示真假
一个boolean类型占多少空间在不同JVM中可能不同,并没有明确规定
注意事项
Java中的boolean类型不能与int相互转换
如,循环体中的真假判断部分不能为整型

应当改为

类型转换
- 范围小的类型能直接转换为范围大的类型(隐式转换)
- 范围大的类型转换为范围小的类型需要进行强制类型转换(精度可能会丢失)
- 互不相干的类型之间无法转换(如数值类型和boolean类型,但int类型和String类型有特殊的方式进行转换)
案例1 int, double, long类型之间的转换

这里我们可以看出,double类型的范围是最大的,因为能直接兼容int类型和long类型

而当我们进行强制转换时,就不会提示错误了
案例2 int和boolean类型之间的转换


这里我们可以看到,即时加了进行强制转换也无法成功
因为int和boolean是毫不相关的两种类型
(不像C语言中的0表示false, 非0表示true)
案例3 int和char类型之间的转换


我们可以看到,int和char类型之间的转换跟案例1基本没什么不同
只是转换的时候会照着ASCII码表进行
案例4 int和String的互相转换
int转换为String

String转换为int

数值提升
- 不同数据类型混合运算时,范围小的会提升为大的
- 运算时最小单位为4个字节,若不足4个字节(如short,char)会提升至4个字节再运算 (这是为了实现硬件方面运算的便捷)
案例1


案例2

出现错误,提示 “从int转换到byte可能会有损失”

三大引用类型
数组

创建
动态初始化
系统会根据后面初始化的元素去确定有多少个元素并分配内存空间
int[] arr = new int[]{1, 2, 3, 4};
静态初始化
即告诉系统数组里有多少个元素
int[] arr = {1, 2, 3, 4}
使用
获取数组长度
System.out.println(arr.length)
访问数组元素
通过[]进行访问,访问时下标不能超过arr.length - 1(因为下标从0开始记)
System.out.println(arr[0]);
修改数组元素
arr[0] = 10
数组的遍历

数组与方法
作为方法的参数

注意
因为数组是引用类型,所以作为方法参数传入时,在方法内修改数组的值时,原数组也会被修改
详见:
作为方法的返回值


引用类型是什么?
也就是只存放所有元素的首地址,使用的时候再根据地址去访问其他元素
这里打印出来的就是所有元素的首地址

我们上面的八种类型属于内置类型,在内存中是这样子的
int num = 10;

而引用类型在内存中是这样的
int[] arr = {1, 2, 3};

因此,如果引用类型作为方法的参数进行传递,那么在方法内进行修改的话,原数据也会受到影响,而内置类型便不会受到影响
内置类型作为方法参数



引用类型作为方法参数


这里传入的仅是一个地址,既不用把所有数据拷贝下来,又能修改原数组的内容
null
若我们将一个引用类型的数据置为null,便表示没有指向任何空间
int[] arr = null
如果试图访问其中的元素,就会出现NullPointerException这个异常
类
类指的是一类对象的统称
比如我们建房子的时候,设计图是类,建出来的房子是对象
我们可以根据设计图建出很多房子
也就可以根据类实例化出很多对象
类的声明

成员变量
构造方法
方法
this关键字
static关键字
类的实例化
匿名对象
toString
内存分布
封装
private
getter和setter
代码块
普通代码块
构造代码块
静态代码块
String类
创建
这四种方法都可以


内存分布
顺便讲一下字符串常量池,还有以上创建方法的不同之处
转义字符
在创建字符串的时候,我们要用 "" 将内容包裹起来,但如果我们想给里面的字符也加上""就会出现问题

也就是字符串提前结束了
因此,我们可以加个反斜杠,相当于需要告诉计算机
“嘿,这是字符串的一部分,不是要结束的意思”

\"也就被称为转义字符
| 转义字符 | 含义 |
|---|---|
| \n | 换行 |
| \' | ' |
| \" | " |
| \\ | \ |
| \t | tab键 |
字符串拼接

打印结果为:

那如果字符串的内容都为数字,拼接之后的结果会不会是两个数字相加呢?


可以看出,拼接这个动作,只是单纯把字符连接起来
字符串比较相等


我们采用比较运算符来进行比较的时候发现没什么问题
但从上面我们可以知道,采用这种创建方式的话
这两个字符串在内存中指向的是同一块地址,那如果指向的是不同的地址呢?
是否结果就会不同了呢?
想要验证这个想法,就需要让两个字符串指向的内存地址不同

果然,当指向的内存地址不同时,就算字符串内容相同,结果也是false
其实,比较运算符对于引用类型的数据来说,比较的并不是内容,而是它们所指向的地址
比如我们可以想象成,== 比较的是两个盒子,如果盒子相同结果就为true,它并不关心里面的东西是否一样
但是这并不是我们想要的,我们关心的只是字符串的内容相不相同,并不关心是不是指向同一块内存地址
因此,我们不能使用比较运算符去比较字符串是否相等
在String类中提供了一个equals方法用来比较两个字符串的内容

equals注意事项
当我们在比较字符串常量和字符串对象的时候,如下

两者谁前谁后看似没有区别,但是当字符串对象引用为null时,第二种方式就会抛出异常,而第一种方式并不会

其实我们从上面类和对象的知识就可以了解到,当一个对象引用为null的时候,如果试图调用类里面的方法,就会抛出 NullPointerException 异常
("Hello" 或者 "" 这种字面值常量,本质上其实也是一个String对象,也都可以调用String对象的方法)
字符和字符串
字节和字符串
字符串常见操作
这里面所有的方法都是public的
比较
| 方法名称 | 作用 |
|---|---|
boolean equals(Object anObject) | 比较字符串内容是否相等 |
boolean equalsIgnoreCase(String anotherString) | 同上,但不区分大小写 |
int compareTo(String anohterString) | 比较两个字符串大小关系 |
查找
| 方法名称 | 作用 |
|---|---|
boolean contains(CharSequence s) | 判断一个子字符串是否存在 |
int indexOf(String str) | 从头开始查找制定字符串的位置,查到了就返回位置的开始索引,如果查不到就返回 -1 |
int indexOf(String str, int fromIndex) | 从指定位置开始查找子字符串的位置 |
int lastIndeOf(String str) | 由后向前查找子字符串的位置 |
int lastIndexOf(String str, int fromIndex) | 从指定位置由后向前查找 |
boolean startsWith(String prefix) | 判断是否以指定字符串开头 |
boolean startsWith(String prefix, int toffset) | 从指定位置开始判断是否以指定字符串开头 |
boolean endsWith(String suffix) | 判断是否以指定字符串结尾 |
替换
| 方法名称 | 作用 |
|---|---|
String replaceAll(String regex, String replacement) | 替换所有指定内容 |
String replaceFirst(String regex, String replacement) | 替换第一个指定内容 |
拆分
| 方法名称 | 作用 |
|---|---|
String[] split(String regex) | 将字符串全部拆分 |
String[] split(String regex, int limit) | 同上,且该数组长度就是limit极限 |
截取
| 方法名称 | 作用 |
|---|---|
String substring(int beginIndex) | 从指定索引截取到结尾 |
String substring(int beginIndex, int endIndex) | 截取部分内容 |
其他
| 方法名称 | 作用 |
|---|---|
String trim() | 去掉字符串中的左右空格,保留中间空格 |
String toUpeperCase() | 字符串转成大写 |
String toLowerCase() | 字符串转成小写 |
native String intern() | 字符串入池操作 |
String concat(String str) | 字符串连接,等同于“+”,不入池 |
int length() | 获取字符串长度 |
boolean isEmpty() | 判断是否为空字符串(只是长度为0,不是null) |


