02、第二个阶段,Java 基础入门
1)基本数据类型
-
8 种基本数据类型(boolean、char、byte、short、int、long、float、double)
- 整形中 byte、short、int、long 的取值范围
boolean:
- boolean数据类型表示一位的信息;
- 只有两个取值:true 和 false;
- 这种类型只作为一种标志来记录 true/false 情况;
- 默认值是 false;
- 例子:boolean one = true。
char:
- char类型是一个单一的 16 位 Unicode 字符;
- 最小值是 \u0000(即为0);
- 最大值是 \uffff(即为65,535);
- char 数据类型可以储存任何字符;
- 例子:char letter = 'A';。
byte:
- byte 数据类型是8位、有符号的,以二进制补码表示的整数;
- 最小值是 -128(-2^7);
- 最大值是 127(2^7-1);
- 默认值是 0;
- byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
- 例子:byte a = 100,byte b = -50。
short:
- short 数据类型是 16 位、有符号的以二进制补码表示的整数
- 最小值是 -32768(-2^15);
- 最大值是 32767(2^15 - 1);
- Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
- 默认值是 0;
- 例子:short s = 1000,short r = -20000。
int:
- int 数据类型是32位、有符号的以二进制补码表示的整数;
- 最小值是 -2,147,483,648(-2^31);
- 最大值是 2,147,483,647(2^31 - 1);
- 一般地整型变量默认为 int 类型;
- 默认值是 0 ;
- 例子:int a = 100000, int b = -200000。
float:
- float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
- float 在储存大型浮点数组的时候可节省内存空间;
- 默认值是 0.0f;
- 浮点数不能用来表示精确的值,如货币;
- 例子:float f1 = 234.5f。
double:
- double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数;
- 浮点数的默认类型为double类型;
- double类型同样不能表示精确的值,如货币;
- 默认值是 0.0d;
- 例子:double d1 = 123.4。
-
单精度和双精度
- float 数据类型是单精度、32位 double 数据类型是双精度、64 位
-
- 存储和转换的过程中浮点数容易引起一些较小的舍入误差
- 第一种方案就是使用
Math.abs()
方法来计算两个浮点数之间的差异,如果这个差异在阈值范围之内,我们就认为两个浮点数是相等。 -
final double THRESHOLD = .0001; double d1 = .0; for (int i = 1; i <= 11; i++) { d1 += .1; } double d2 = .1 * 11; if(Math.abs(d1-d2) < THRESHOLD) { System.out.println("d1 和 d2 相等"); } else { System.out.println("d1 和 d2 不等"); }
-
第二种解决方案就是使用 BigDecimal 类,可以指定要舍入的模式和精度,这样就可以解决舍入的误差。
-
BigDecimal d1 = new BigDecimal("0.0"); BigDecimal pointOne = new BigDecimal("0.1"); for (int i = 1; i <= 11; i++) { d1 = d1.add(pointOne); } BigDecimal d2 = new BigDecimal("0.1"); BigDecimal eleven = new BigDecimal("11"); d2 = d2.multiply(eleven); System.out.println("d1 = " + d1); System.out.println("d2 = " + d2); System.out.println(d1.compareTo(d2));
-
-
01、包装类型可以为 null,而基本类型不可以
- 数据库的查询结果可能是 null,如果使用基本类型的话,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值),就会抛出
NullPointerException
的异常。
- 数据库的查询结果可能是 null,如果使用基本类型的话,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值),就会抛出
-
02、包装类型可用于泛型,而基本类型不可以
- 泛型不能使用基本类型,因为使用基本类型时会编译出错。
-
List<int> list = new ArrayList<>(); // 提示 Syntax error, insert "Dimensions" to complete ReferenceType List<Integer> list = new ArrayList<>();
-
03、基本类型比包装类型更高效
-
基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用。
-
-
04、两个包装类型的值可以相同,但却不相等
-
Integer chenmo = new Integer(10); Integer wanger = new Integer(10); System.out.println(chenmo == wanger); // false System.out.println(chenmo.equals(wanger )); // true
两个包装类型在使用“==”进行判断的时候,判断的是其指向的地址是否相等。chenmo 和 wanger 两个变量使用了 new 关键字,导致它们在“==”的时候输出了 false。
而
chenmo.equals(wanger)
的输出结果为 true,是因为 equals 方法内部比较的是两个 int 值是否相等。源码如下。 -
private final int value; public int intValue() { return value; } public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
瞧,虽然 chenmo 和 wanger 的值都是 10,但他们并不相等。换句话说就是:将“==”操作符应用于包装类型比较的时候,其结果很可能会和预期的不符。
-
-
05、自动装箱和自动拆箱
- 当需要进行自动装箱时,如果数字在 -128 至 127 之间时,会直接使用缓存中的对象,而不是重新创建一个对象。
-
2)操作符
-
算术运算符
-
逻辑运算符
-
比较运算符
3)流程控制语句
-
条件分支(if/else/else if、三元运算符、switch)
-
if(布尔表达式) { //如果布尔表达式为true将执行的语句 } if(布尔表达式){ //如果布尔表达式的值为true }else{ //如果布尔表达式的值为false } if(布尔表达式 1){ //如果布尔表达式 1的值为true执行代码 }else if(布尔表达式 2){ //如果布尔表达式 2的值为true执行代码 }else if(布尔表达式 3){ //如果布尔表达式 3的值为true执行代码 }else { //如果以上布尔表达式都不为true执行代码 } switch(expression){ case value : //语句 break; //可选 case value : //语句 break; //可选 //你可以有任意数量的case语句 default : //可选 //语句 }
-
循环或者遍历(for、while、do-while)
-
while( 布尔表达式 ) { //循环内容 } do { //代码语句 }while(布尔表达式); for(初始化; 布尔表达式; 更新) { //代码语句 }
//增强for循环
for(声明语句 : 表达式) { //代码句子 } -
break 和 continue
-
break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。
-
break 跳出最里层的循环,并且继续执行该循环下面的语句。
-
continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
在 for 循环中,continue 语句使程序立即跳转到更新语句。
在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。
4)包
-
创建包
-
-
导入包
-
包全名
-
5)main 方法详解
-
public 关键字
- 访问控制修饰符 对所有类可见。使用对象:类、接口、变量、方法
- 非访问修饰符
-
static 修饰符
-
静态变量:
static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。
-
静态方法:
static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。
对类变量和方法的访问可以直接使用 classname.variablename 和 classname.methodname 的方式访问。
-
-
void 关键字
- 无返回值
-
main 方法
-
- 主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行。
-
字符串数组参数(
String[] args
)
6)数组
-
什么是数组?
- 按照 Javadoc 给出的解释,数组是一个对象,它包含了一组固定数量的元素,并且这些元素的类型是相同的。数组会按照索引的方式将元素放在指定的位置上,意味着我们可以通过索引来访问到这些元素。在 Java 中,索引是从 0 开始的。
-
访问数组
-
- 一维数组:Arrays.toString() 多维数组:deepToString()
anArray[0] = 10; System.out.println(anArray[0]);
- 一维数组:Arrays.toString() 多维数组:deepToString()
-
遍历数组
- 第一种,使用 for 循环:
-
int anOtherArray[] = new int[] {1, 2, 3, 4, 5}; for (int i = 0; i < anOtherArray.length; i++) { System.out.println(anOtherArray[i]); }
- 第二种,使用 for-each 循环:
-
for (int element : anOtherArray) { System.out.println(element); }
-
- 可变参数用于将任意数量的参数传递给方法:
-
void varargsMethod(String... varargs) {}
-
-
int[] anArray = new int[] {5, 2, 1, 4, 8}; Arrays.sort(anArray);
-
-
数组转成 Stream
-
String[] anArray = new String[] {"沉默王二", "一枚有趣的程序员", "好好珍重他"}; Stream<String> aStream = Arrays.stream(anArray);
-
-
数组转成 List
-
List<Integer> aList = Arrays.asList(anArray);
如果需要添加元素或者删除元素的话,最好把它转成
java.util.ArrayList
。 -
new ArrayList<>(Arrays.asList(anArray));
-
-
-
//1、loop int[] anArray = new int[] {5, 2, 1, 4, 8}; for (int i = 0; i < anArray.length; i++) { if (anArray[i] == 4) { System.out.println("找到了 " + i); break; } } //2、排序后 int[] anArray = new int[] {1, 2, 3, 4, 5}; int index = Arrays.binarySearch(anArray, 4);
//3、list
Arrays.asList(arr).contains(targetValue)
-
7)注释
-
单行注释
-
// 这是单行注释的示例 /* 这个也是单行注释的示例 */
-
-
多行注释
-
/* 这是第一个Java程序 *它将打印Hello World * 这是一个多行注释的示例 */
-
-
文档注释
8)字符串
-
双引号字符串和 new 字符串对象
-
1 采用双引号(字面量)方式创建字符串的比较
String s1 = "abc"; String s2 = "abc"; System.out.println(s1==s2);// true
- 1
- 2
- 3
(1)采用双引号的方式创建字符串时,JVM首先在字符串常量池中查找有没有"abc"这个字符串对象;
(2)如果有,则不创建任何对象,直接将池中"abc"这个对象的地址返回,分别赋给s1和s2。
(3)如果没有,则先在字符串常量池中创建"abc"这个对象,然后将池中"abc"这个对象的地址分别赋给s1和s2;
(4)由于s1、s2都指向字符串池中的"abc"对象,所以结果为true。
2 采用new方式创建字符串的比较
String s3 = new String("abc"); String s4 = new String("abc"); System.out.println(s3==s4);// false
- 1
- 2
- 3
(1)采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"abc"这个字符串对象;
(2)如果有,则不在池中创建"abc"这个对象,直接在堆中(常量池之外)创建一个"abc"字符串对象,并将其地址赋给s3,随后再创建另一个“abc”字符串对象,并将其地址赋给s4;
(3)如果没有,则先在字符串池中创建一个"abc"字符串对象,然后再在堆中(常量池之外)创建一个"abc"字符串对象,将其地址赋给s3,随后在堆中再创建另一个“abc”字符串对象,并将其地址赋给s4;
(4)由于s3 、s4是指向两个不同的字符串对象,所以结果是false。
3 栈 堆 常量池
1 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
2 堆:存放所有new出来的对象,JDK1.8以后常量池也存放在堆内存中。
3 常量池:存放字符串常量和基本类型常量(public static final)。
-
-
String、StringBuilder 和 StringBuffer 之间的区别
-
字符串拼接的几种方式
-
1. plus方式
当左右两个量其中有一个为String类型时,用plus方式可将两个量转成字符串并拼接。
-
String a="";
-
int b=0xb;
-
String c=a+b;
2. concat方式
当两个量都为String类型且值不为null时,可以用concat方式。
-
String a="a";
-
String b="b";
-
String c= a.concat(b);
理论上,此时拼接效率应该最高,因为已经假定两个量都为字符串,做底层优化不需要额外判断或转换,而其他方式无论如何优化,都要先走到这一步。
3. append方式
当需要拼接至少三个量的时候,可以考虑使用StringBuffer#append()以避免临时字符串的产生
-
StringBuffer buf=new StringBuffer()
-
buf.append("a");
-
if(someCondition){
-
buf.append("b");
-
}
-
buf.append("c");
-
String d=buf.toString();
当a,b,c拼接起来会很长时,可以给在构造器中传入一个合适的预估容量以减少因扩展缓冲空间而带来的性能开销。
StringBuffer buf=new StringBuffer(a.length()+b.length()+c.length());
JDK对外提供的一些涉及可append CharSequence的参数或返回值类型往往是StringBuffer类型,毕竟安全第一,而StringBuffer大多数情况(包括append操作)线程安全。
若不会出现多线程同时对一实例并发进行append操作,建议使用非线程安全的StringBuilder以获得更好性能
4. 其他
若需拼接至少三个量,只用一个连续拼接的语句就可完成时,从使代码简洁角度考虑,用plus方式。
-
String a="a";
-
String b="b";
-
String c="c";
-
String d=a+b+c;
此时,第4句经JDK编译后其字节码(或)会自动优化为等效于下列代码编译后的字节码。
String d=new StringBuilder().append(a).append(b).append(c).toString();
若采用模板+参数来替换占位符的方式或需同时对要拼接日期/数字进行格式化,可以用String.format()来实现
-
-
-
字符串常量池
- 提供给字符串的一块缓存区域
-
关于 intern
- intern方法可以看成返回常量池中该字符串对象的引用。如果没有该字符串对象就把这个对象(或引用)加到常量池。
-
-
-
当比较两个字符串对象的内容是否相等时,请使用
.equals()
方法。.equals()
方法在比较的时候需要判 null -
当比较两个字符串对象是否相等时,请使用“==”操作符。
-
-
-
-
public class Test { public static void main(String[] args) { String cmower = "沉默王二,一枚有趣的程序员"; if (cmower.contains(",")) { String [] parts = cmower.split(","); System.out.println("第一部分:" + parts[0] +" 第二部分:" + parts[1]); } else { throw new IllegalArgumentException("当前字符串没有包含逗号"); } } } /* 大约有 12 种英文特殊符号,如果直接拿这些特殊符号替换上面代码中的分隔符(中文逗号),这段程序在运行的时候就会出现以下提到的错误。 反斜杠 \(ArrayIndexOutOfBoundsException) 插入符号 ^(同上) 美元符号 $(同上) 逗点 .(同上) 竖线 |(正常,没有出错) 问号 ?(PatternSyntaxException) 星号 *(同上) 加号 +(同上) 左小括号或者右小括号 ()(同上) 左方括号或者右方括号 [](同上) 左大括号或者右大括号 {}(同上) */ //反斜杠转义 String cmower = "沉默王二.一枚有趣的程序员"; if (cmower.contains(".")) { String [] parts = cmower.split("\\."); System.out.println("第一部分:" + parts[0] +" 第二部分:" + parts[1]); }
-
反斜杠