关键字,保留字
被java赋予特殊含义,用做专门用途的字符串(单词)
标识符
变量
变量的定义
定义格式: 数据类型 变量名 = 变量值
声明: int age;
赋值: age = 12;
声明并赋值: int age = 12;
注意点:
变量需要先声明后使用
变量不会有默认值,所以需要赋值后使用
在其定义的作用域内有效
变量的数据类型
整型:byte(1字节 = 8bit)/short(2字节)/int(4字节)/long(8字节)
byte(-128 ~ 127)
- 整型的常量,默认类型是:int型
- 声明long型变量,必须以"l"或"L"结尾
浮点型:float(4字节) \ double(8字节)
- 浮点型的常量,默认类型为:double
- float:单精度,尾数精确到7位有效数字,double是float精度的两倍
字符型:char (1字符=2字节)
定义char变量,通常使用一对 ‘’ ,内部有且仅有一个字符char c = 'a'
表示方式:声明字符,转义字符,使用Unicode值
char c = '\n'
char c = '\u0043'
布尔型:boolean
自动类型转换
当容量小的与容量大的运算时,会自动提升为容量大的
byte b = 2;
int i = 129;
int i1 = b + i;
long i2 = b + i;
float i3 = b + i;
当byte ,short ,char 运算是会自动转为int
char c1 = 'a';//97
int i3 = 10;
int i4 = c1 + i3;
short s2 = 10;
//char c2 = c1 + s2;//编译报错
强制类型转换
int i = (int) d;
基本数据类型变量间运算规则
自动类型转换(只涉及7种基本数据类型)
String
特点:
String是一个final类,代表不可变字符序列,只要 被 “” 的就是一个对象
字符串是常量,它们的值在创建之后不能更改
String对象的字符内容是存储在一个字符数组value[]中的。
String 原码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage.*/
private final byte[] value;
/** Cache the hash code for the string */
private int hash; // Default to 0
1.String实现了Serializable接口:表示字符串是支持序列化的。
实现了Comparable接口:表示String可以比较大小
2.通过字面量的方式(区别于new给一个字符串赋值,此时的字符串值声明在字符串常量池中)。
3.字符串常量池中是不会存储相同内容(使用String类的equals()比较,返回true)的字符串的。
String 在jdk8 及以前内部定义了 final char value[] 用于存储字符串数据。jdk9 时改为 final byte value[]
字符串的构造方法
1. 通过字面量定义的方式:声明的变量在常量池中
String s1 = "javaEE";
String s2 = "javaEE";
2. 通过new + 带参构造器的方式:先在堆内存中创建一份对象,再去查看堆内存中是否有该对象
String s3 = new String("javaEE"); //本质上是this.value = original.value;
String s4 = new String("javaEE");
3. 通过new + 空参构造器的方式:创建一个空的对象
String s5 = new String(); //本质上是this.value = new char[0];
4. //this.value = Arrays.copyOf(value, value.length);
String str = new String(char[] a);
5. String str = new String(char[] a,int startIndex,int count);
6. String str = new String(byte[] byte);
字符串拼接方式赋值的对比
总结:
1.常量与常量 的拼接结果在常量池。且常量池中不会存在相同内容的常量。
2.只要 其中一个是变量,结果就在堆中。
3.如果拼接的结果调用intern()方法,返回值就在常量池中
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s5 == s6);//false
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false
String s8 = s6.intern();//返回值得到的s8使用的常量值中已经存在的“javaEEhadoop”
System.out.println(s3 == s8);//true
String s1 = "javaEEhadoop";
String s2 = "javaEE";
String s3 = s2 + "hadoop";
System.out.println(s1 == s3);//false
final String s4 = "javaEE";//s4:常量
String s5 = s4 + "hadoop";
System.out.println(s1 == s5);//true
字符串的不可变性
对字符串重新赋值时,需要重写指定内存区域赋值
String s1 = "abc";//字面量的定义方式
String s2 = "abc";//指向的是常量池中同一块内存空间
s1 = "hello";
对现有的字符串进行连接操作时,也需要重新指定内存区域赋值
String s3 = "abc";
s3 += "def";
System.out.println(s3);//abcdef
System.out.println(s2);
当调用String的replace()方法修改指定字符或字符串时
String s4 = "abc";
String s5 = s4.replace('a', 'm');
System.out.println(s4);//abc
System.out.println(s5);//mbc
String 常用方法
boolean isEmpty();//return value.length == 0
boolean equals(Object obj)
boolean equalsIgnoreCase(String anotherString)
boolean endsWith(String suffix)
boolean startsWith(String prefix)
boolean startsWith(String prefix, int toffset)
boolean contains(CharSequence s)
boolean matches(String regex):告知此字符串是否匹配给定的正则表达式。
int length()
char charAt(int index)
char[] toCharArray()
byte[] getBytes()
String toLowerCase();
String toUpperCase()
String concat(String str)//将指定字符串拼接到结尾。等价于 “+”
int compareTo(String anotherString)
String substring(int beginIndex)
String substring(int beginIndex,int endIndex)
int indexOf(String str)
int indexOf(String str,int fromIndex)
int lastIndexOf(String str)
int lastIndexOf(String str,int fromIndex)
String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所 oldChar 得到的。
String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所匹配字面值目标序列的子字符串。
String replaceAll(String regex, String replacement):使用给定的 replacement 替换此字符串所匹配给定的正则表达式的子字符串。
String replaceFirst(String regex, String replacement):使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。
String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。
使用示例
- isEmpty
String s = "";
String s1 = " ";
String s2 = null;
System.out.println(s.isEmpty());//true
System.out.println(s1.isEmpty());//false
System.out.println(s2.isEmpty());//NullPointerException
扩展
如何判断字符串是否为空(null)或者是空字符串("")的方法
if(s == null || s.equals("")){}
if(s == null || s.length() == 0){}//效率最高
if(s == null || s.isEmpty()){}//1.6以上
//commons lang/commons lang3
StringUtils.isEmpty(null) //true
StringUtils.isEmpty("")//true
StringUtils.isEmpty(" ")//false
StringUtils.isBlank(null) // true
StringUtils.isBlank("") // true
StringUtils.isBlank(" ") // true
//Optional对null值处理
//有的时候我们获取的值虽然是String但所接受到的泛型不是String可能会出现如下情况
(inInfo.get("limit") == null || StringUtils.isBlank(inInfo.get("limit").toString()) //这里可能会NullPointerException
//还有一种处理null的方式如下: 如果是null 处理成 ""
String id = (String) Optional.ofNullable(inInfo.get("limit")).orElse("");
运算符
1.算术运算符: + - + - * / % (前)++ (后)++ (前)-- (后)-- +
2.赋值运算符:= += -= *= /= %=
3.比较运算符(关系运算符): == != > < >= <= instanceof
4.逻辑运算符:& && | || ! ^
5.位运算符:<< >> >>> & | ^ ~
6.三元运算符:(条件表达式)? 表达式1 : 表达式2
赋值运算符,运算的结果不会改变变量本身的数据类型
short s = 10;
//s = s + 1;//报错
s += 1
比较运算符的结果是 布尔类型
逻辑运算符
交换两个变量的值
int num1 = 10;
int num2 = 20;
//相加操作可能超出存储范围,只适用于数值类型
num1 = num1 + num2;
num2 = num1 - num2;
num1 = num1 - num2;
//只适用于数值类型
num1 = num1 ^ num2;
num2 = num1 ^ num2;
num1 = num1 ^ num2;
流程控制
分支、循环
1.if-else条件判断结构
2.switch-case选择结构
2.1 for循环结构
2.2 while循环结构
2.3 do-while循环结构
1.if-else条件判断结构
结构一:
if(条件表达式){
执行表达式
}
结构二:二选一
if(条件表达式){
执行表达式1
}else{
执行表达式2
}
结构三:n选一
if(条件表达式){
执行表达式1
}else if(条件表达式){
执行表达式2
}else if(条件表达式){
执行表达式3
}
...
else{
执行表达式n
}
1.2.说明:
1. else 结构是可选的。
2. 针对于条件表达式:
> 如果多个条件表达式之间是“互斥”关系(或没有交集的关系),
哪个判断和执行语句声明在上面还是下面,无所谓。
> 如果多个条件表达式之间有交集的关系,需要根据实际情况,
考虑清楚应该将哪个结构声明在上面。
> 如果多个条件表达式之间有包含的关系,通常情况下,
需要将范围小的声明在范围大的上面。否则,范围小的就没机会执行了。
3. if-else结构是可以相互嵌套的。
4. 如果if-else结构中的执行语句只有一行时,对应的一对{}可以省略的。
但是,不建议大家省略。
2.switch-case选择结构
switch(表达式){
case 常量1:
执行语句1;
//break;
case 常量2:
执行语句2;
//break;
...
default:
执行语句n;
//break;
}
2.说明:
① 根据switch表达式中的值,依次匹配各个case中的常量。一旦匹配成功,则进入相应case结构中,调用其执行语句。
当调用完执行语句以后,则仍然继续向下执行其他case结构中的执行语句,直到遇到break关键字或此switch-case结构
末尾结束为止。
② break,可以使用在switch-case结构中,表示一旦执行到此关键字,就跳出switch-case结构
③ switch结构中的表达式,只能是如下的6种数据类型之一:
byte 、short、char、int、枚举类型(JDK5.0新增)、String类型(JDK7.0新增)
④ case 之后只能声明常量。不能声明范围。
⑤ break关键字是可选的。
⑥ default:相当于if-else结构中的else.
default结构是可选的,而且位置是灵活的。
3.如果switch-case结构中的多个case的执行语句相同,则可以考虑进行合并。
4.break在switch-case中是可选的
5.凡是可以使用switch-case的结构,都可以转换为if-else。反之,不成立
2.1 for循环结构
for(①;②;④){
③
}
执行过程:① - ② - ③ - ④ - ② - ③ - ④ - ... - ②
2.2 while循环结构
①
while(②){
③;
④;
}
执行过程:① - ② - ③ - ④ - ② - ③ - ④ - ... - ②
说明:
写while循环千万小心不要丢了迭代条件。一旦丢了,就可能导致死循环!
当步进表达式不参与循环体变量时③,④位置可以交换
当步进表达式涉及循环体变量时需要注意不要交换位置
for和while循环总结:
- 开发中,基本上我们都会从for、while中进行选择,实现循环结构。
- for循环和while循环是可以相互转换的!
区别:for循环和while循环的初始化条件部分的作用范围不同。 - 我们写程序,要避免出现死循环。