13、常用类:
包装(Wrapper)类:
包装类的分类:
- 针对八种基本数据类型相应的引用类型——包装类;
- 有了类的特点,就可以调用类中的方法。
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
上表中非黄色的不是Number的子类。
包装类和基本数据类型的转换:
- jdk5 前的手动装箱和拆箱方式
- 装箱:基本类型 -> 包装类型;
- 拆箱:包装类型 -> 基本类型。
- jdk5后实现了自动装箱和拆箱方式;
- 自动装箱底层调用的式valueOf方法,比如Integer.valueOf()。
package com.jiangxian.wrapper_.integer_;
/**
* @author JiangXian~
* @version 1.0
*/
public class Integer01 {
public static void main(String[] args) {
// jdk5以前式手动的:
int n1 = 100;
// jdk5以前的两种手动装箱方式:int -> Integer
Integer integer = new Integer(n1);
Integer integer01 = Integer.valueOf(n1);
// 手动拆箱:
int i = integer.intValue();
// jdk5后自动装箱:
int n2 = 200;
// 自动装箱:
Integer integer2 = n2; // 底层使用的仍然式是Integer.valueOf(n2);
// 自动拆箱:
int i2 = integer2; // 底层仍然使用的是 integer2.intValue();
}
}
其余包装类是一样的,不再啰嗦举例了。
Object obj1 = true?new Integer(1):new Double(2.0); // obj1 = new Integer(1)
System.out.println(obj1);// 输出的是1.0
// 为什么?
// 三元运算符是一个整体,由于有double类型的,所以将obj设置为了Double类型。
三元运算符是一个整体!
包装类方法:
包装类和String类型的相互转换:
package com.jiangxian.wrapper_;
/**
* @author JiangXian~
* @version 1.0
*/
public class WrapperVSString {
public static void main(String[] args) {
// 包装类 ——》String
// 还是以Integer为例子,其余是一样的:
Integer i = 100; // 自动装箱
// 方式1:
String str1 = i + "";
// 方式2:
String str2 = i.toString();
// 方式3:
String str3 = String.valueOf(i);
//String ——》包装类(Integer)
String str4 = "12345";
// 方法一:
Integer integer1 = Integer.parseInt(str4)/*返回的是一个int类型,但是会自动装箱*/;
// 方法二:构造器
Integer integer2 = new Integer(str4);
}
}
所有包装类与String的转换都是一样的,所以就展示Integer这个包装类。
Integer类的常用方法:
- Integer.MIN_VALUE——返回最小值;
- Integer.MAX_VALUE——返回最大值;
Character类的常用方法:
- Character.isDigit(‘字符’);——判断是不是数字;
- Character.isLetter(‘字符’);——判断是不是字母;
- Character.isUpperCase(‘字符’);——判断是不是大写;
- Character.isLowerCase(‘字符’);——判断是不是小写;
- Character.isWihitespace(‘字符’);——判断是不是空格;
- Character.toUpperCase(‘字符’);——转换成大写;
- Character.toLowerCase(‘字符’);——转换成小写。
Integer创建机制:
面试题:
1:看看下面代码,输出结果是什么?为什么?
package com.jiangxian;
public class WrapperExercise02 {
public static void main(String[] args) {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j); // False,因为我们创建了两个不同的空间
Integer m = 1;
Integer n = 1;
System.out.println(m == n); // 调用的时自动装箱,Integer.valueOf(1),得看源码
// 源码如下:
/*
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
我们发现里面有个判断,与IntegerCache.low和IntegerCache.high有关,
源码中有这样的描述:This method will always cache values in the range -128 to 127
所以我们得知IntegerCache.low = -128,IntegerCache.high = 127
*/
// 我们发现,在-128~127这个范围,不会创建一个新的对象而是直接从缓存数组返回,所以此处为true。
Integer x = 128;
Integer y = 128;
System.out.println(x == y);
// 此处,超过了127,所以自动装箱会new一个Integer,故为false。
}
}
2、看看下面的代码,输出声明结果?
package com.jiangxian;
public class WrapperExercise01 {
public static void main(String[] args) {
Integer i11 = 127;
int i12 = 127;
System.out.println(i11 == i12);
Integer i21 = 128;
int i22 = 128;
System.out.println(i21 == i22);
// 由上文,我们可以看出,只要有基本数据类型;
// 判断的就是值是否相等。
}
}
==只要有基本数据类型, 号 判断的就是值是否相等。
String类:
String类的理解和创建对象:
-
String 对象用于保存字符串,也就是一组字符序列;
-
字符串常量对象是用双引号括起来的字符序列。例如:“你好”、“Hello”等;
-
字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节;
-
String 类常用的构造器有很多(其余看手册):
-
String s1 = new String();
-
String s2 = new String(String original);
-
String s3 = new String(char[] a);
-
String s4 = new String(char[] a, startIndex, int count);
-
String s5 = new String(byte[] b);
-
String 实现了Serializable接口,说明 String 对象可以串行化(即可以在网络传输,可以存储在文件中);
-
String 实现了Comparable接口,说明 String 对象可以进行比较大小;
-
String 还是一个final类(不能被其他类继承);
-
String 中有一个属性 private final char value[];用于存放字符串内容——一定要注意,value是一个final类型的,赋值后不可修改(不是说的数组内容不可以修改,而是指的是地址不能修改,为什么呢?因为value指向的是一个空间,修改空间内部的值不会对地址有影响)。
-
常量池中的常量拥有自己的地址。
package com.jiangxian.string_;
public class String01 {
public static void main(String[] args) {
final char[] value = {'a','b','c'};
value[0] = 'A';
char[] a = {'a'};
// value = a; 改变地址会报错
}
}
创建String 对象的两种方式:
- 方式一:直接赋值——String s = “JiangXian”;
- 先从常量池查看是否有“JiangXian”数据空间,若有,将 s 直接指向该数据空间;
- 若没有,在数据空间中创建“JiangXian”数据空间,再将 s 指向该空间;
- s 最终指向的是常量池的地址空间。
- 方式二:调用构造器——String s = new String(“JiangXian”);
- 先在堆中创建空间(创建String对象),里面维护了 value 属性,value 指向常量池的“JiangXian”空间;
- 若常量池中没有“JiangXian”,那么便在常量池中创建,然后通过 value 指向常量池中的“JiangXian”
- 最终指向的是堆中的地址空间。
String的特性:
-
String 是一个 final 类,不可以被继承;
-
String 代表不可变的字符序列——不可变性;
-
字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。
String s1 = "Hello"; s1 = "haha";
上述这个代码我们来分析一下,首先我们创建了一个字符串常量对象“Hello”,这个对象是存储在常量池中的,然后我们将s1 重新赋值为“haha”。
- 要注意的是,我们并不是将原来的字符串常量对象“Hello”的内容改变了,我们没有对这个对象进行任何改变!字符串一旦被定义就是不可便的。
- 我们是先在常量池中创建了另一个为“haha”的字符串常量对象,然后将原来 s1 指向“Hello”断开,再让 s1 指向 “haha”即可。
- 所以我们创建了两个字符串常量对象,而不是创建了一个字符串常量并对其内容进行修改。
字符串常量拼接:
String a = "hello" + "abc";
这段代码仅仅创建了一个字符串常量对象“helloabc”而不是三个对象“hello”,”abc”,”helloabc”。
分析:
- 编译器会帮我们进行一个优化,判断创建的常量池对象,是否有引用指向(是否有变量指向它);
- 在底层上就会被优化为:String a = “helloabc”;
字符串变量拼接:
String a = "hello"; //创建了一个字符串常量对象。
String b = "abc"; //创建了一个字符串常量对象。
String c = a + b; // 这个语句是怎么运行的呢?
底层执行步骤:
- 先创建一个StringBuilder对象,命名为sb;
- 调用 sb.append(a);
- 调用 sb.append(b);
- 最后 String c = sb.toString;
所以最后 c 指向的是堆中的一个String 对象,内部的 value 属性指向常量池中新创建的“helloabc”。
所以一共创建了三个字符串常量对象。
拼接小结:
- 常量相加,看常量池,底层会进行优化;
- 变量相加,是在堆中。
package com.jiangxian.string_;
public class StringExercise08 {
public static void main(String[] args) {
String a = "hello"; //创建了一个字符串常量对象。
String b = "abc"; //创建了一个字符串常量对象。
String c = a + b; // 这个语句是怎么运行的呢?
System.out.println(c == c.intern()); // 这里为true让我有些困惑
String hello = new String("hello");
System.out.println(hello == hello.intern());
}
}
对String是不变的字符串的加深理解:
package com.jiangxian.string_;
public class StringExercis10 {
String str = new String("jiangxian");
final char[] ch = {'j','a','v','a'};
public void change(String str, char ch[]){
str = "java"; // 一个局部变量
/*
1、java中只有值传递,对基本数据类型传递的是值,对引用类型传递的是对象的引用(内存地址的副本);
2、那么我得到困惑点就来了,为什么String是非基本数据类型,且是引用数据类型,为什么我们对它的修改没有作用呢?
3、那是因为在java中,String是一个不可变的:
任何对String的修改操作都会导致创建一个新的String对象。
4、属性的str 指向了一个 "jiangxian"对象的引用;
5、当其作为参数传递给change方法时,传递的是属性的str的引用,即指向“jiangxian”对象的内存地址;
6、局部变量str只是创建了一个新的对象"java",其对于原来的属性的str没有任何影响。
7、因此当change方法结束后,原来的属性的str仍然指向"jiangxian"
*/
ch[0] = 'h';
/*
那这边为什么能修改呢?
因为其修改的是内存地址中存放的值。
*/
}
public static void main(String[] args) {
StringExercis10 s = new StringExercis10();
s.change(s.str,s.ch);
System.out.print(s.str + " and ");
System.out.println(s.ch);
}
}
为了方便理解,我又写了一段代码,希望对各位的理解有所帮助:
package com.jiangxian.string_;
public class test {
public char[] c1= {'j','a','v','a'};
public void change(char[] c){
char[] c2 = {'h','l','l','o'};
c = c2;
}
public static void main(String[] args) {
test test = new test();
test.change(test.c1);
System.out.println(test.c1);
}
}
String类的常见方法:
说明:
String 类是保存字符串常量的。每次更新都需要重新开辟空间,效率极低,因此java设计者还提供了StringBuilder 和 StringBuffer 来增强String 的功能,并提高效率。
常见方法概述:
- equals——区分大小写,判断内容是否相等;
- equalsIgnoreCase——忽略大小写的判断内容是否相等;
- length——获取字符的个数,字符串的长度;
- indexOf——获取字符在字符串中第一次出现的索引,索引从0开始,若找不到,返回-1;
- lastIndexOf——获取字符在字符串中最后出现的索引,索引从0开始,若找不到,返回-1;
- substring——截取指定范围的字串;
- trim——去前后空格;
- charAt——获取某索引位置的字符,注意,想要获取某索引位置的字符不能使用Str[index]格式。
- toUpperCase——转换为大写形式;
- toLowerCase——转换为小写形式;
- concat——拼接字符串;
- replace——替换字符串中的字符;
- split——分割字符串,对于某些分割字符,我们需要转移字符;
- compareTo——比较两个字符串的大小;
- toCharArray——转换成字符数组;
- format——格式化字符串,%s 字符串,%c 字符, %d 整型, %.2f 浮点型
package com.jiangxian.string_;
/**
* @author JiangXian~
* @version 1.0
*/
public class StringMethod {
public static void main(String[] args) {
// 1.equals: 比较内容是否相等,区分大小写。
String str1 = "JiangXian";
System.out.println("hello".equals(str1));
// 2.equalsIgnoreCase: 忽略大小写的判断是否相等。
String username = "johN";
System.out.println("john".equalsIgnoreCase(username));
// 3.length: 获取字符的个数,即字符串的长度。
System.out.println("Jiangxian".length());
// 4.indexOf: 获取字符串对象中第一次出现的索引,索引从0开始,若找不到,返回0.
System.out.println(str1.indexOf('X'));
String s1 = "wer@terwe@g";
System.out.println("第一个 we 的 index为:" + s1.indexOf("we")); // 若找的是一个字符串,返回的是符合该字符串的第一个字符所在位置的索引
// 5.lastIndexOf: 获取字符在字符串中最后一次出现的索引,索引从0开始,若找不到,返回0.
System.out.println("最后一个 we 的 index 为:" + s1.lastIndexOf("we"));
// 6.substring: 截取指定范围的字串。
String name = "Hello,JiangXian";
System.out.println(name.substring(6)); // 从索引6开始(包括),截取后面所有的内容
System.out.println(name.substring(0,5));// 从0开始,截取到5前,即左闭右开[0,5)。
// 7.trim: 去掉前后的空格。
System.out.println(" m ".trim());
// 8.charAt: 获取字符串中指定位置的字符。
System.out.println("Hello".charAt(2));
// 9.toUpperCase: 转换成大写。
System.out.println("hello".toUpperCase());
// 10.toLowerCase: 转换成小写。
System.out.println("HELLO".toLowerCase());
// 11.concat: 拼接字符串
String s2 = "宝玉";
s2 = s2.concat("林黛玉").concat("薛宝钗");
System.out.println(s2);
// 12.replace: 替换字符串中的字符。
s2 = "宝玉 and 黛玉 黛玉 黛玉";
String s12 = s2.replace("黛玉","宝钗");
System.out.println("s2: " + s2);
System.out.println("s12: " + s12);
// 13.split: 分割字符串,对于某些分割字符,我们需要转义字符。
String s3 = "E:\\self_study\\NoteBook\\Java";
String[] splits = s3.split("\\\\");
System.out.println("====分割后的字符串====");
for(String split:splits){
System.out.println(split);
}
// 14.toCharArray: 转换成字符数组。
String s = "hello";
char[] c = s.toCharArray();
for(char cc:c){
System.out.println(cc);
}
// 15.compareTo: 比较两个字符串的大小,
// 若前者大,则返回正数,
// 后者大,则返回负数,
// 若相等,返回0
/*
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
*/
String a = "jac";
String b = "jack";
String d = "jcck";
System.out.println(a.compareTo(b));
System.out.println(b.compareTo(d));
// 16. format: 格式化,
// %.2f——会自动进行四舍五入处理。
String info = String.format("我的姓名%s 年龄是%d 成绩是%.2f 性别是%c。希望大家喜欢我!",
"JiangXian", 21, 99.199, 'M');
System.out.println("info: " + info);
String formatStr = "我的姓名%s 年龄是%d 成绩是%.2f 性别是%c。希望大家喜欢我!";
String info2 = String.format(formatStr, "JiangXian", 21, 99.199, 'M');
System.out.println("info2: " + info2);
}
}
StringBuffer类:
基本介绍:
- java.lang.StringBuffer 代表可变的字符序列,可以对字符串内容进行增删;
- 很多方法与 String 相同,但 StringBuffer是可变长度;
- StringBuffer 是一个容器。
- StringBuffer 是 final 类,是最终类,不能被继承;
- 实现了 Serializable 接口,可以串行化,可以保存文件,或网络传输;
- 继承了抽象类 AbstractStringBuilder;
- AbstractStringBuilder 属性 char[] value,存放的字符序列。
package com.jiangxian.stringbuffer_;
/**
* @author JiangXian~
* @version 1.0
*/
public class StringBuffer01 {
public static void main(String[] args) {
// 1.StringBuffer 的直接父类是 AbstractStringBuilder;
// 2.StringBuffer 实现了 Serializable,即StringBuffer的对象可以串行化;
// 3.在父类 AbstractStringBuilder 有属性 char[] value,
// 其与String的属性value是不同的,其不是final,该 value 数组存放字符串内容,引出存放在堆中。
// 4.StringBuffer 是一个 final 类,不能被继承;
// 5.因为StringBuffer字符内容是存在 char[] value,所以在变化(增加/删除)
// 不用每次都更换地址(即不是每次创建新对象),所以效率高于String
StringBuffer stringBuffer = new StringBuffer("hello");
System.out.println(stringBuffer);
}
}
AbstractStringBuilder 的 char[] value不是final,所以存放在堆中。
String 和 StringBuffer 相互转换:
在开发过程中,我们通常需要将 String 和 StringBuffer 进行转换。
package com.jiangxian.stringbuffer_;
import java.nio.Buffer;
/**
* @author JiangXian~
* @version 1.0
*/
public class StringAndStringBuffer {
public static void main(String[] args) {
// 看 String ——》StringBuffer:
String str = "hello tom";
// 方式1:使用构造器
// 注意:返回的才是 StringBuffer 对象,对 str 本身没有影响。
StringBuffer stringBuffer = new StringBuffer(str);
// 方式2:使用append方法
StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1 = stringBuffer1.append(str);
// StringBuffer ——》String:
StringBuffer stringBuffer3 = new StringBuffer("JiangXian");
// 方式1:使用 StringBuffer 提供的 toString 方法。
String str1 = stringBuffer3.toString();
// 方式2:使用构造器来搞定。
String str2 = new String(stringBuffer3);
}
}
StringBuffer类常见方法:
增删改查操作时我们常用的,其它方法和String类一样~
- append——增;
- delete——删;
- replace——改;
- insert——插入。
package com.jiangxian.stringbuffer_;
/**
* @author JiangXian~
* @version 1.0
*/
public class StringBufferMethod {
public static void main(String[] args) {
StringBuffer s = new StringBuffer("hello");
// 增:
s.append(','); //hello,
s.append("张三丰"); // hello,张三丰
s.append("赵敏").append(100).append(true).append(10.5); // hello,张三丰赵敏100true10.5
// 删:
/*
删除索引为 >= start && < end 处的字符;
即左闭右开
*/
s.delete(11,14); // 删除了100
System.out.println(s);
// 改:
s.replace(9,11,"周芷若");
System.out.println(s); // 使用周芷若,替换 索引9-11的字符[9,10]处的赵敏
// 插:
s.insert(9,"赵敏");
System.out.println(s);
}
}
练习:
Exercise01:
package com.jiangxian.stringbuffer_;
/**
* @author JiangXian~
* @version 1.0
*/
public class StringBufferExercise01 {
public static void main(String[] args) {
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str);
/*
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
*/
System.out.println(sb.length());
System.out.println(sb);
// 但是不能这样写:
// 为什么呢?
/*
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
*/
// 我们发现,在接受String的构造器里,在调用父类的构造器时,需要str.length();
// 所以String对象不能时空。
StringBuffer sb1 = new StringBuffer(str);
System.out.println(sb1);
}
}
Exercise02:
输入商品名称和商品价格,要求打印效果实例为:商品名 商品价格,要求:价格的小数点前面每三位用逗号隔开,再输出。
package com.jiangxian.stringbuffer_;
import java.util.Scanner;
/**
* @author JiangXian~
* @version 1.0
*/
public class StringBufferExercise02 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("======请输入商品名称=====");
String name = scanner.next();
StringBuffer sb = new StringBuffer();
System.out.println("=====请输入商品价格=====");
sb.append(scanner.next());
int pointIndex = sb.indexOf(".");
for (int i = pointIndex - 3; i > 0; i-=3) {
sb.insert(i,',');
}
System.out.println("=====修改后的结果=====");
System.out.println(name + " " + sb);
}
}
StringBuilder类:
基本介绍:
- 一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步(即不保证线程安全)。此类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。若可能,建议先使用该类,因为再大多实现中,比 StringBuffer 快;
- 在 StringBuilder 上的主要操作时 append 和 insert 方法,可重载这些方法,以接受任意类型的数据;
- StringBuilder 是final;
- 继承了 AbstractStringBuilder,属性 char[] value,内容存到 value——即存放在堆内;
- 实现了 Serializable 接口,可以串行化,可网络传输与保存到文件。
StringBuilder常用方法:
StringBuilder 和 StringBuffer 均代表可变的字符序列,方法是一样的,所以使用和 StringBuffer 一样。
package com.jiangxian.stringbuilder_;
/**
* @author JiangXian~
* @version 1.0
*/
public class StringBuilder01 {
public static void main(String[] args) {
// 1.StringBuilder 继承了 AbstractStringBuilder 类;
// 2.实现了 Serializable 接口,说明 StringBuilder 对象是可以串行化
// (对象可以网络传输,保存在文件中);
// 3.StringBuilder 对象字符仍然是存放在其父类 AbstractStringBuilder 的 char[] value;
// 因此,字符序列存放在堆中;
// 4.StringBuilder 是 final 类,不能被继承;
// 5.StringBuilder 的方法,没有做互斥的处理,即没有 synchronized 关键字,
// 因此在单线程的情况下使用 StringBuilder。
StringBuilder stringBuilder = new StringBuilder();
}
}
String、StringBuffer和StringBuilder的比较:
- StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且方法也一样;
- String:不可变字符序列,效率低,但是复用率高(字符串常量存放在常量池中,有多个对象指向);
- StringBuffer:可变字符序列,效率较高(增删改查),线程安全,看源码;
- StringBuilder:可变字符序列,效率最高,但是线程不安全(没有synchronized修饰);
- String 使用注意事项说明:
- String s = “a”; //创建了一个字符串
- s += “b”; // 实际上原来常量池中的"a"字符串对象已经丢弃了,现在又产生了一个新的字符串对象"ab"。现在s指向常量池中的"ab"字符串对象。若多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。若这样的操作放到循环中,会极大影响程序的性能。
- 由上文得,若要对字符序列大量修改,不要用String。
String、StringBuffer和StringBuilder的选择:
使用的原则:
- 若字符串存在大量的修改操作,一般使用StringBuffer 或 StringBuilder;
- 若字符串存在大量的修改操作,且是单线程,使用StringBuilder;
- 若字符串存在大量的修改操作,且是多线程,使用StringBuffer;
- 若我们的字符串很少修改,被多个对象引用,使用String,比如配置信息等。
Math:
基本介绍:
Math 类包含用于执行基本数学运算的,如初等指数、对数、平方根和三角函数。
方法(均为静态方法):
- abs——返回绝对值;
- acos——返回一个值的反余弦值,返回的角度在 0.0 到 pi 之间;
- asin——返回一个值的反正弦值,返回的角度在 -pi/2 到 pi/2 之间;
- atan——返回一个值的反正切值,返回的角度在 -pi/2 到 pi/2 之间;
- atan2(double y, double x)——将矩形坐标(x,y)转换成极坐标(r, theta),返回所得角 theta;
- cbrt——返回 double 值的立方根。
package com.jiangxian.math_;
/**
* @author JiangXian~
* @version 1.0
*/
public class MathMethod_ {
public static void main(String[] args) {
// 1.abs 绝对值:
int abs = Math.abs(-9);
System.out.println(abs);
// 2.pow 求幂:
double pow = Math.pow(2, 4);
System.out.println(pow);
// 3.ceil 向上取整,返回 >= 该参数的最小整数(转成double):
double ceil = Math.ceil(3.9);
System.out.println(ceil);
// 4.floor 向下取整,返回 <= 该参数的最小整数(转成double):
double floor = Math.floor(-4.1);
System.out.println(floor);
double floor1 = Math.floor(3.9);
System.out.println(floor1);
// 5.round 四舍五入,
long round = Math.round(5.51);
System.out.println(round);
// 6.sqrt 开方:
double sqrt = Math.sqrt(9);
System.out.println(sqrt);
// 7.random 求随机数:
// 返回的是 0 <= x < 1之间的一个随机小数
// 那我们要怎么创建一个a~b之间的随机整数呢?
// (int)(a + Math.random() * (b-a+1))
// 这样就得到了 a<=x<=b
System.out.println("====100个2~7的随机整数====");
for (int i = 0; i < 100; i++) {
System.out.println((int)(2 + Math.random()*(6)));
}
// 8.max 最大值:
int max = Math.max(1, 2);
System.out.println("max" + max);
// 9.min 最小值:
int min = Math.min(1, 2);
System.out.println("min" + min);
}
}
Arrays类:
常见方法:
Arrays 里面包含了一系列的静态方法,用于管理和操作数组(比如排序和搜索).
- toString——返回数组的字符串形式;
- sort——排序(自然排序和定制排序);
- binarySearch——通过二分搜索法进行搜查,要求必须排好序;
- copyOf——数组元素的复制;
- fill——数组元素的填充;
- equals——比较两个数组元素内容是否一致。
package com.jiangxian.arrays_;
import java.util.Arrays;
import java.util.Comparator;
/**
* @author JiangXian~
* @version 1.0
*/
public class ArraysMethod {
public static void main(String[] args) {
Integer[] integers = {1, 20 , 90};
// 遍历数组:
// for(int i = 0; i < integers.length; i++){
// System.out.println(integers[i]);
// }
// 直接使用toString 方法,显示数组:
System.out.println(Arrays.toString(integers));
// 演示 sort方法的使用:
Integer[] arr = {1, -1, 7, 0, 89};
// Arrays.sort(arr); // 默认排序方法。
// 定制排序:
Arrays.sort(arr,new Comparator(){
@Override
public int compare(Object o1, Object o2) {
Integer i1 = (Integer)o1;
Integer i2 = (Integer)o2;
return i2 - i1;
}
});
// 分析源码:
// 1.Arrays.sort(arr, new Comparator(){})
// 2.最终到 TimSort类的
// private static <T> void binarySort(T[] a, int lo, int hi, int start,
// Comparator<?super T>c)()
// 3.执行到 binarySort 方法的代码,会根据动态绑定机制 c.compare()执行我们传入的
// 匿名内部类的 compare()
// while (left < right) {
// int mid = (left + right) >>> 1;
// if (c.compare(pivot, a[mid]) < 0)
// right = mid;
// else
// left = mid + 1;
// }
// 4.可以看到我们创建的Comparator会因为我们返回值的正负来决定排序的顺序
// 这体现了 接口编程+动态绑定+匿名内部类的综合使用
// 在下面的学习底层框架和源码的使用方法,会非常常见。
System.out.println(Arrays.toString(arr));
}
}
对定制排序的进一步解读:
package com.jiangxian.arrays_;
import com.jiangxian.wrapper_.integer_.Integer01;
import java.util.Arrays;
import java.util.Comparator;
/**
* @author JiangXian~
* @version 1.0
*/
public class ArraysSortCustom {
public static void main(String[] args) {
int[] arr = {1, -1, 8, 0, 20};
bubble02(arr, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
Integer i1 = (Integer)o1;
Integer i2 = (Integer)o2;
return i1 - i2;
}
});
System.out.println(Arrays.toString(arr));
}
// 使用冒泡排序:
public static void bubble01(int[] arr){
int tmp = 0;
for(int i = 0; i < arr.length - 1; i++){
for(int j = 0; j < arr.length -1 - i; j++){
if(arr[j] > arr[j+1]){
tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
// 冒泡结合定制:
public static void bubble02(int[] arr, Comparator c){
int tmp = 0;
for(int i = 0; i < arr.length - 1; i++){
for(int j = 0; j < arr.length -1 - i; j++){
// if(arr[j] > arr[j+1]){}
// 数组排序由c.compare(arr[j], arr[j+1])的返回值决定
if(c.compare(arr[j], arr[j+1]) > 0){
// (1)若返回的是 i1 - i2;
// 当前一个元素比后一个元素大时,返回的是>0;
// 所以执行交换,最后的结果为从小到大的排序。
// (2)若返回的是 i2 - i1;
// 当后一个元素比前一个元素大时,返回的是>0;
// 所以执行交换,最后的结果为从大到小的排序。
tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
}
package com.jiangxian.arrays_;
import java.util.Arrays;
import java.util.List;
/**
* @author JiangXian~
* @version 1.0
*/
public class ArraysMethod02 {
public static void main(String[] args) {
Integer[] arr = {1, 2, 90, 123, 567};
// 1.binarySearch 通过二分搜索法进行查找,要求必须排序好
// 为什么呢?
// 这种搜索就是将要查找的值,与数组中间的数比较,以此缩减长度
// 所以其必须是有序的
// 若数组中不存在该元素,就返回 -(low+1)
// 就是这个元素要是存在应该在的位置。
int index = Arrays.binarySearch(arr,567);
int notFound = Arrays.binarySearch(arr,91);
System.out.println("567's index: " + index);
System.out.println("91's index: " + notFound);
// 2.copyOf 数组元素复制:
/*
1.从 arr 数组中,拷贝 arr.length 个元素到 newArr数组中;
2.若拷贝的长度 > arr.length 就在新数组的后面,增加 null;
3.若拷贝长度 < 0 就抛出异常 NegativeArraySizeException
4.该方法的底层使用的是System.arraycopy()
*/
Integer[] newArr = Arrays.copyOf(arr, arr.length);
System.out.println(Arrays.toString(newArr));
// 3.fill 数组元素的填充:
Integer[] num = new Integer[]{9,3,2};
Arrays.fill(num, 99);
System.out.println("==num 数组填充后==");
System.out.println(Arrays.toString(num));
// 4.equals 比较两个数组元素内容是否完全一致
Integer[] arr2 = {1, 2, 90, 123};
// (1)若arr和arr2数组的元素一样,则方法true;
// (2)若不是完全一样,就返回false。
boolean equals = Arrays.equals(arr,arr2);
System.out.println("equals" + equals);
// 5.asList 将一组值,转换成List
// (1) asList 方法,会将(2,3,4,5,6,1)数据转成一个List集合
// (2) 返回 asList 编译类型 List(接口)
// (3) asList 运行类型 java.util.Arrays$ArrayList, 是Arrays类的
List asList = Arrays.asList(2,3,4,5,6,1);
System.out.println("asList:" + asList);
System.out.println("asList的运行类型" + asList.getClass());
}
}
Arrays练习:
自定义Book类,里面包含name 和 price,按price 排序(从大到小)。要求使用两种方法排序(默认和定制)排序,有一个 Book[] books = 4本书对象。
默认排序我懒得写了,只写了定制。
package com.jiangxian.arrays_;
import java.util.Arrays;
import java.util.Comparator;
/**
* @author JiangXian~
* @version 1.0
*/
public class ArraysExercise {
public static void main(String[] args) {
Book[] books = new Book[4];
books[0] = new Book("红楼梦", 100);
books[1] = new Book("金瓶梅新", 90);
books[2] = new Book("青年文摘20年", 20);
books[3] = new Book("java从入门到放弃~", 300);
Arrays.sort(books, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
Book b1 = (Book) o1;
Book b2 = (Book) o2;
double difference = b1.getPrice() - b2.getPrice();
// 价格从小到大
if (difference > 0){
return 1;
}else if (difference <0){
return -1;
}else{
return 0;
}
}
});
System.out.println("=====按价格从小到大排序:=====");
System.out.println(Arrays.toString(books));
Arrays.sort(books, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
Book b1 = (Book) o1;
Book b2 = (Book) o2;
double difference = b2.getPrice() - b1.getPrice();
if (difference > 0){
return 1;
}else if (difference <0){
return -1;
}else{
return 0;
}
}
});
System.out.println("=====按价格从大到小排序:=====");
System.out.println(Arrays.toString(books));
Arrays.sort(books, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
Book b1 = (Book) o1;
Book b2 = (Book) o2;
return b2.getTitle().length() - b1.getTitle().length();
}
});
System.out.println("=====按照书名长度排序=====");
System.out.println(Arrays.toString(books));
}
}
class Book{
private String title;
private double price;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"title='" + title + '\'' +
", price=" + price +
'}';
}
}
System类:
常见方法:
- exit——退出当前程序;
- arraycopy——复制数组元素,比较适合底层调用,一般使用 Arrays.copyOf 完成复制数组;
- currentTimeMillens——返回当前时间距离1970-1-1的毫秒数;
- gc——垃圾回收机制。
package com.jiangxian.system;
import java.util.Arrays;
/**
* @author JiangXian~
* @version 1.0
*/
public class System_ {
public static void main(String[] args) {
// 1.exit 退出当前程序。
// System.out.println("Hello.");
// System.exit(0);// 0表示一个状态,正常的状态
// System.out.println("World.");
// 2.arraycopy 复制数组元素,比较适合底层调用,
// 一般使用 Arrays.copyOf完成复制数组
int[] src = {1, 2, 3};
int[] dest = new int[3]; // dest 当前是 {0, 0, 0}
System.arraycopy(src, 1, dest, 1, 2);
/*
src – the source array.
srcPos – starting position in the source array.
dest – the destination array.
destPos – starting position in the destination data.
length – the number of array elements to be copied.
*/
System.out.println("dest=" + Arrays.toString(dest));
// 3.currentTimeMillens 返回当前时间距离 1970-1-1的毫秒数
System.out.println(System.currentTimeMillis());
}
}
BigInteger 和 BigDecimal类:
BigInteger 和 BigDecimal 介绍:
应用场景:
- BigInteger 适合保存比较大的整型;
- BigDecimal 适合保存精度更高的浮点型(小数)。
常见方法:
- add 加;
- subtract 减;
- multiply 乘;
- divide 除。
package com.jiangxian.bignum_;
import java.math.BigDecimal;
/**
* @author JiangXian~
* @version 1.0
*/
public class BigDecimal_ {
public static void main(String[] args) {
// 当我们保存一个浮点数时,double的精度可能不够用;
// double d = 1999.111111111111111111111111111111111111111111111111111;
BigDecimal bigDecimal = new BigDecimal("1999.111111111111111111111111111");
BigDecimal bigDecimal2 = new BigDecimal("3");
System.out.println(bigDecimal);
// 若对BigDecimal进行运算,和BigInteger类似
// 不同的是,在BigDecimal的除法中可能出现无限小数。
// 所以我们在进行除法的时候,指定精度即可,BigDecimal.ROUND_CEILING
// 这样若有无限小数,只会保留分子的精度。
System.out.println(bigDecimal.divide(bigDecimal2,BigDecimal.ROUND_CEILING));
}
}
日期类:
我觉得这边没有什么需要刻意去记得,需要用的时候去查询即可。所以写的比较简略。
第一代日期类Date:
- Date:精确到毫秒,代表特定的时间;
- SimpleDateFormat:格式和解析日期的类——其允许进行格式化(日期->文本)、解析(文本->日期)和规范化。
- 语法(仅是常用的):
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format = sdf.format(d1);// 将日期转换成指定格式的字符串
- Date parse = sdf.parse(format);// 将字符串转换为Date
- 语法(仅是常用的):
第二代日期类Calendar:
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间提供了一些转换方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
- Calendar 是一个抽象类,且构造器是private的;
- 可以通过 getInstance() 来获取实例;
- 提供大量的方法和字段提供给程序员;
- Calendar 没有提供对应的格式化的类,因此需要程序员自己组合来输出;
- 若我们需要按照24小时进制来获取时间,Calendar.Hour;——》Calendar.HOUR_OF_DAY;
第三代日期类:
前两代的不足:
- Date——在jdk1.0就已经存在,太多的方法已经被弃用;
- Calendar:
- 可变性:像日期和时间这样的类应该是不可变的;
- 偏移性:Date中的年份是从1900开始的,而月份都从0开始,和实际不符;
- 格式化:格式化只对Date有用,Calendar没有格式化;
- 线程不安全;
- 不能处理闰秒。
介绍:
- LocalDate(日期/年月日),可以获取日期字段;
- LocalTime(时间/时分秒),可以获取时间字段;
- LocalDateTime(日期时间/年月日时分秒),可以获取日期和时间字段。
- 是在JDK8才加入的。
DateTimeFormatter 格式日期类:
DateTimeFormat dtf = DateTimeFormatter.ofPattern(格式);
String str = dtf.format(日期对象);
Instant时间戳:
类似于Date,提供了一系列和Date类转换的方式。
- Instant——》Date:
- Date date = Date.from(Instant);
- Date——》Instant:
- Instant instant = date.toInstant();
我觉得这边没有什么需要刻意去记得,需要用的时候去查询即可。所以写的比较简略。
- Instant instant = date.toInstant();
第一代日期类Date:
- Date:精确到毫秒,代表特定的时间;
- SimpleDateFormat:格式和解析日期的类——其允许进行格式化(日期->文本)、解析(文本->日期)和规范化。
- 语法(仅是常用的):
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format = sdf.format(d1);// 将日期转换成指定格式的字符串
- Date parse = sdf.parse(format);// 将字符串转换为Date
- 语法(仅是常用的):
第二代日期类Calendar:
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间提供了一些转换方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
- Calendar 是一个抽象类,且构造器是private的;
- 可以通过 getInstance() 来获取实例;
- 提供大量的方法和字段提供给程序员;
- Calendar 没有提供对应的格式化的类,因此需要程序员自己组合来输出;
- 若我们需要按照24小时进制来获取时间,Calendar.Hour;——》Calendar.HOUR_OF_DAY;
第三代日期类:
前两代的不足:
- Date——在jdk1.0就已经存在,太多的方法已经被弃用;
- Calendar:
- 可变性:像日期和时间这样的类应该是不可变的;
- 偏移性:Date中的年份是从1900开始的,而月份都从0开始,和实际不符;
- 格式化:格式化只对Date有用,Calendar没有格式化;
- 线程不安全;
- 不能处理闰秒。
介绍:
- LocalDate(日期/年月日),可以获取日期字段;
- LocalTime(时间/时分秒),可以获取时间字段;
- LocalDateTime(日期时间/年月日时分秒),可以获取日期和时间字段。
- 是在JDK8才加入的。
DateTimeFormatter 格式日期类:
DateTimeFormat dtf = DateTimeFormatter.ofPattern(格式);
String str = dtf.format(日期对象);
Instant时间戳:
类似于Date,提供了一系列和Date类转换的方式。
- Instant——》Date:
- Date date = Date.from(Instant);
- Date——》Instant:
- Instant instant = date.toInstant();