6 Java常用类
6.1 字符串
6.1.1 特点
相关的类有:
java.lang.String
java.lang.StringBuilder
java.lang.StringBuffer
String
:- 底层使用
final
修饰的char
数组进行存储(private final char value[];
) - 表示不可变的字符序列,字符串是常量,它们的值在创建后不能被更改
- 双引号标识的一串字符串就是该类的一个对象
- 字符串常量池(
JDK7.0
及之后在堆中,之前在方法区)用来保存字符串常量 String
类的对象内容不可改变,所以每当进行字符串拼接时,总是会在内存中创建一个新的对象
- 底层使用
StringBuilder
,StringBuffer
:(JDK1.5
引入)相同点:
- 底层使用
char
数组进行存储(char[] value;
),默认是一个包含16个字符的数组new char[16];
- 表示可变的字符序列,字符串缓冲区,一个类似于
String
的字符串缓冲区,可以被修改 - 进行字符串拼接时,直接在数组中加入新内容,
StringBuilder
&StringBuffer
会自动维护数组的扩容,不会创建新对象 - 通过
toString()
方法,StringBuilder
&StringBuffer
对象将会转换为不可变的String
对象
- 底层使用
不同点
StringBuilder
:线程不安全,效率高StringBuffer
:线程安全,效率低
6.1.2 代码示例
/**
* 字符串类
*/
public class StringTest {
public static void main(String[] args) {
String str = "abc"; // 存在于字符串常量池中
String str1 = new String("abc"); // 存在于堆中的对象
String str2 = "abc"; // 会从字符串常量池中寻找相同的字符串
System.out.println(str == str2); // true 都是同一个常量池的引用
System.out.println(str == str1); // false 一个在堆中,一个在常量池,属于不同的引用
System.out.println(str.equals(str1)); // true String类重写了equals方法来进行字符串的比较
/*
* intern() 是一个本地方法
* 作用:如果常量池中有与当前字符串equals的字符串,返回常量池中的字符串的引用,
* 如果常量池中没有与当前equals的字符串,则将当前字符串添加到常量池并返回这个字符串的引用
* 注意:JDK6.0中比较都是false,因为字符串常量池不在堆中,在Perm区(持久代,即方法区),所以执行intern()方法后也不会相同
*/
String cc = "33"; // 先定义cc,将"33"放入常量池
String str3 = new String("3")+new String("3"); // 堆中的对象
String aaa = str3.intern(); // 如果常量池中存在,返回常量池的字符串,如果没有,将字符串加入常量池,返回字符串引用
// str3.intern();
System.out.println(str3);
// String cc = "33"; // 后定义cc,此时常量池中已存在str3与”33“相同,这是就会拿到同一个引用
System.out.println(cc == str3); // 先定义cc: false 后定义cc:true
System.out.println(cc == aaa); // 先定义cc: true 后定义cc:true
}
}
/**
* 字符串常用操作
*/
public class StringOperation {
public static void main(String[] args) throws UnsupportedEncodingException {
char[] chr = {'a','b','c'};
// 将char数组转成字符串
String s = new String(chr);
System.out.println("1. 将char数组转成字符串: " + s);
byte[] bt = {97,98,99,100,101};
// 将byte数组转成字符串
String s1 = new String(bt);
System.out.println("2. 将byte数组转成字符串: " + s1);
// 截取数组中某一部分转成字符串
String s2 = new String(bt,2,2);
System.out.println("3. 截取数组中某一部分转成字符串: " + s2);
// 如果截取的长度或者下标超出范围,报异常:StringIndexOutOfBoundsException
// String sch2 = new String(chr,3,1);
String s3 = new String("abcdef");
// charAt(index): 获取字符串中某个字符,下标方式
char ch = s3.charAt(0);
System.out.println("4. charAt: " + ch);
// toCharArray(): 将字符串转换成char数组
char[] chs = s3.toCharArray();
System.out.println("5. toCharArray: "+ chs + " : " + Arrays.toString(chs));
String s4 = new String("abcd");
/*
* compareTo()方法
* 英文 且长度不等
* 字符一样,返回两个长度相减的值
* 长度不一样,前几个字符也不一样,从第一个开始找,找到不一样的字符,返回这两个字符比较的值
* 英文 且长度相等
* 一个字符:ascii 值相减
* 多个字符:第一个字符不同则直接比较第一个字符,第一个字符相同,则直接比较第二个字符,以此类推
*/
int num = s3.compareTo(s4);
System.out.println("6. compareTo: "+num);
// 字符串拼接 concat
String s5 = s3.concat(s4);
System.out.println("7. concat: " + s5);
String s6 = "abc.doc";
String s7 = "ac";
// startsWith()/endsWith(): 判断是否以某个字符串开头和结尾
boolean bn = s6.startsWith(s7);
boolean bn1 = s6.endsWith(s7);
System.out.println("8. startsWith: " + bn);
System.out.println("9. endsWith: " + bn1);
String s8 = new String("abc");
String s9 = new String("ABC");
// equals()/equalsIgnoreCase(): 判断两个字符串是否相等(不忽略大小写,忽略大小写)
System.out.println("10. 大小写:"+s8.equals(s9));
System.out.println("11. 忽略大小写:"+s8.equalsIgnoreCase(s9));
// getBytes(): 将字符串转换成byte数组
byte[] bt1 = s8.getBytes();
System.out.println("12. getBytes: " + bt1 + " : " + Arrays.toString(bt1)); // [97, 98, 99]
/*
* getBytes(charsetName): 通常使用这个进行字符编码的转换
* idea设置默认编码为UTF8 将编码转成 GBK
*/
String name = "李";
byte[] bname = name.getBytes("GBK");
System.out.println("13. getBytes() 转换前的编码: " + Arrays.toString(name.getBytes()));
System.out.println("14. getBytes(charsetName)转换后的编码: " + Arrays.toString(bname));
String s10 = new String("ABCABCABC");
// indexOf(str/int): 返回第一个匹配到的下标
System.out.println("15. indexOf(int): " + s10.indexOf(67));
int in = s10.indexOf("A");
System.out.println("16. indexOf(str): " + in);
// indexOf(str, fromindex):从某个位置开始匹配
int in2 = s10.indexOf("A",4);
System.out.println("17. indexOf(str, fromindex): " + in2);
// -1 :代表没有匹配到相应的数据
int in3 = s10.indexOf("d");
System.out.println("18. indexOf匹配不到: " + in3);
// lastIndexOf(str):从后往前匹配
int in4 = s10.lastIndexOf("A");
System.out.println("19. lastIndexOf: " + in4);
// isEmpty(): 是否为空
boolean bn2 = s10.isEmpty();
System.out.println("20. isEmpty: " + bn2);
// length(): 字符串长度
int length = s10.length();
System.out.println("21. length: " + length);
// replace(oldChar, newChar): 用新的字符替换掉旧的字符,如替换手机号码等 177*****365
String s11 = s10.replace('A','a');
System.out.println("22. replace: " + s11);
// substring(beginIndex): 字符串截取,从beginIndex位置开始
String s12 = s10.substring(2);
System.out.println("23. substring(beginIndex): " + s12);
// substring(beginIndex, endIndex): 截取字符串,从beginIndex位置开始,到endIndex位置结束
String s13 = s10.substring(2,4);
System.out.println("24. substring(beginIndex, endIndex): " + s13);
// 大小写转换 toLowerCase:小写 toUpperCase:大写
String s14 = s10.toLowerCase(); // 小写
System.out.println("25. toLowerCase: " + s14);
// valueOf(): 其他类型转转成String类型方法
boolean bn3 = true;
String s15 = String.valueOf(bn3);
System.out.println("26. valueOf: " + s15);
// 字符串加法(连接字符串)
String s16 = s15+123;
System.out.println("27. 数字与字符串加法(连接字符串): " + s16);
int aaa = 3333;
String s17 = aaa + "";
System.out.println("28. 数字与空字符串加法(连接字符串): " + s17);
String s18 = 2222 + "";
// System.out.println(s17 - s18); // 只能做加法,不能做其他运算
// trim(): 返回一个去掉字符串开头和结尾空格的字符串
String s19 = " abc def ";
System.out.println("29. trim(): " + s19.trim());
/*
* split(regex): 按照指定的字符串或正则表达式将字符串进行分割,返回String[]
* split(regex, limit): 按照regex分割,且返回limit长度的字符串数组
*/
String s20 = "1988-05-29";
s20 = "1988-05--29-";
s20 = "-1988-05--29-";
String[] sarr = s20.split("-");
String[] sarr1 = s20.split("-", 5);
System.out.println(Arrays.toString(sarr) + " length: " + sarr.length);
System.out.println(Arrays.toString(sarr1) + " length: " + sarr1.length);
System.out.println("**" + sarr1[4] + "##"); // 空字符串 ""
}
}
/**
* StringBuffer使用
* StringBuffer与StringBuilder方法类似,这里使用StringBuffer类来举例说明常用方法
*/
public class StringBufferTest {
public static void main(String[] args) {
// 拼接字符串,通常可以使用“+”号,但是每次在内存中都会产生新的对象,造成不必要的浪费
String a = "abc"; // 第1个字符串常量 "abc"
String b = "123"; // 第2个字符串常量 "123"
a = a + b; // 第3个字符串常量 "abc123",并不会改变 "abc" 或者 "123"
// 创建无参数实例
new StringBuffer();
new StringBuilder();
// 创建有参数实例
new StringBuffer("abc");
// 创建指定容量大小的实例,默认是16
new StringBuffer(32);
/*
* 通过制定的字符序列创建 StringBuffer(CharSequence seq),
* String, StringBuffer, StringBuilder 都是 CharSequence 接口的子类
*/
new StringBuffer(new StringBuffer("abc"));
StringBuffer s = new StringBuffer("you ");
// append(任意类型...): 添加任意类型数据的字符串形式,并返回当前对象自身
StringBuffer s1 = s.append("are ");
// s.append(123);
// s.append(true);
System.out.println("1. append(...): " + s); // Hello world
System.out.println("2. append(...): " + s1); // Hello world
System.out.println(s == s1); // true
// 链式调用,可以一直.append
StringBuffer s2 = s.append("a ").append("good ").append("boy.");
// insert(下标,内容): 在某个位置添加内容
s.insert(1,"...");
System.out.println("3. insert(offset, str): " + s);
// delete(start, end): 删除从start开始到end结束,[start,end)区间的内容,不包括end位置的元素
s.delete(1, 4);
System.out.println("4. delete(start, end): " + s);
// deleteCharAt(index): 删除[index]位置的内容
s.deleteCharAt(1);
System.out.println("5. deleteCharAt(index): " + s);
// insert(offset, 内容): 在指定位置插入内容
s.insert(1, 'o');
System.out.println("6. insert(offset, 内容): " + s);
// replace(start, end, str): 把[start,end)位置替换为str
s.replace(10, 14, "bad");
System.out.println("7. replace(start, end, str): " + s);
//setCharAt(index, ch): 替换[index]位置的字符为ch
s.setCharAt(0, 'Y');
System.out.println("8. setCharAt(index, ch): " + s);
// setLength(newLength): 重新设置缓存的长度为newLength
s.setLength(15);
System.out.println("9. setLength(newLength): " + s);
/*
* substring(start): 返回一个从start开始的字符串常量
* substring(start, end): 返回一个从start开始到end结束,[start, end),不包括end,的字符串常量
*/
String subStr = s.substring(2);
String subStr2 = s.substring(2, 5);
System.out.println("10. substring(start): " + subStr);
System.out.println("11. substring(start, end): " + subStr2);
/*
* indexOf(str): 获取某个字符串第一次出现的顺序
* indexOf(str, fromIndex): 获取某个字符串从fromIndex开始往后数第一次出现的顺序
* lastIndexOf(str): 从后往前...
* lastIndexOf(str, fromIndex): 从后往前...
*/
int index = s.indexOf("a");
int index2 = s.indexOf("a", 9);
int lindex = s.lastIndexOf("a");
int lindex2 = s.lastIndexOf("a", 10);
System.out.println("12. indexOf(str): " + index);
System.out.println("13. indexOf(str, fromIndex): " + index2);
System.out.println("14. lastIndexOf(str): " + lindex);
System.out.println("15. lastIndexOf(str, fromIndex): " + lindex2);
// reverse(): 字符串反转
s.reverse();
System.out.println("16. reverse(): " + s);
// 通过toString方法,StringBuilder对象将会转换为不可变的String对象
String toStr = s.toString();
System.out.println("17. toString(): " + toStr);
}
}
/**
* 执行效率测试 String, StringBuilder, StringBuffer
*/
public class StringExecutionEfficiencyTest {
public static final String HOPE = "希望是这个世界上最宝贵的东西。";
public static void main(String[] args) {
/*
* 测试字符串拼接
* String 效率最慢
* StringBuilder, StringBuffer 次数越多,区别越大
*/
testString(); // 10000次: 820ms
testStringBuffer(); // 10000000次:341ms
testStringBuilder(); // 10000000次:202ms
}
public static void testString(){
long start = System.currentTimeMillis(); // 当前系统时间毫秒数
String str = "";
for (int i = 0; i < 10000; i++) {
str = str + HOPE;
}
long end = System.currentTimeMillis();
System.out.println("String+ :"+ (end - start));
}
public static void testStringBuffer(){
long start = System.currentTimeMillis();
StringBuffer str = new StringBuffer("");
for (int i = 0; i < 10000000; i++) {
str = str.append(HOPE);
}
long end = System.currentTimeMillis();
System.out.println("StringBuffer :"+ (end - start));
}
public static void testStringBuilder(){
long start = System.currentTimeMillis();
StringBuilder str = new StringBuilder("");
for (int i = 0; i < 10000000; i++) {
str = str.append(HOPE);
}
long end = System.currentTimeMillis();
System.out.println("StringBuilder :"+ (end - start));
}
}
6.2 包装类
6.2.1 基本数据类型相关的包装类
字节型 | 短整型 | 整型 | 长整型 | 单精度浮点 | 双精度浮点 | 字符型 | 布尔型 | 默认值 | |
---|---|---|---|---|---|---|---|---|---|
基本数 据类型 |
byte | short | int | long | float | double | char | boolean | 0、空格、false |
包装类 | Byte | Short | Integer | Long | Float | Double | Character | Boolean | null |
6.2.2 特点
- 自动装箱:基本数据类型 —> 包装类,例如:
Integer a = 1; // int -> Integer
- 自动拆箱:包装类 —> 基本数据类型,例如:
int c = a; // Integet -> int
包装类型是为了方便对基本数据类型进行操作,包装类型可以解决一些基本类型解决不了的问题:
- 基本类型可以和包装类型直接相互转换,自动装箱拆箱
- 传递参数时,如果函数的参数是引用数据类型而不是基本数据类型,则可以使用包装类
- 集合不允许存放基本数据类型,只能存放应用数据类型
- 包装类中提供了常用的对基本数据类型的操作方法,可以很方便使用,如通过包装类型的
parse()
方法可以实现基本数据类型和String
类型之间的相互转换等等
6.2.3 代码示例
/**
* 包装类
*/
public class Wrapper {
public static void main(String[] args) {
test();
test1();
test2();
}
public static void test(){
int mima = 123456;
String str = String.valueOf(mima);
System.out.println(str);
String str1 = Integer.toString(mima);
System.out.println(str1);
}
public static void test1(){
int a = 123;
Integer a1 = new Integer(a);
Integer a2 = Integer.valueOf(a);
Integer a3 = a; // 自动包装 new Integer(a);
int b = a3.intValue(); // 返回int类型数据
int b1 = a3; // 自动拆箱 intValue();
System.out.println(b1);
}
// 异常: NumberFormatException
public static void test2(){
String abc = "a123456";
Integer integer = Integer.valueOf(abc);
System.out.println(integer);
int in = Integer.parseInt(abc);
System.out.println(in);
}
}
6.3 枚举
6.3.1 特点
相关的类有:
java.lang.Enum
枚举是
JDK1.5
引入的新特性,通过关键字enum
来定义枚举类枚举类是一种特殊类,它和普通类一样可以使用构造器、定义成员变量和方法,也能实现一个或多个接口
枚举类不能继承其他类,他已默认继承
Enum
类(Java只支持单继承)枚举类不能被继承(默认被
final
修饰)枚举类是线程安全的
枚举类型是类型安全的(
typesafe
)
6.3.2 代码示例
/**
* 普通类方式定义常量
*/
public class Genders {
public static final int MAN = 0;
public static final int WOMAN = 1;
public static final int UNKNOWN = 2;
}
/**
* 定义枚举类,使用 enum 代替 class,定义更简洁
*/
public enum GenderEnum {
MAN, WOMAN, UNKNOWN
}
/**
* 枚举类常量可以是对象
*/
public enum Gender1Enum {
MAN{},
WOMAN{},
UNKNOWN{}
}
/**
* 在枚举类中使用抽象方法
*/
public enum Gender2Enum {
MAN{
@Override
public String getInfo() {
return "男性";
}
}, WOMAN{
@Override
public String getInfo() {
return "女性";
}
}, UNKNOWN{
@Override
public String getInfo() {
return "未知";
}
};
/**
* 定义抽象方法
* @return String
*/
public abstract String getInfo();
}
/**
* 定义枚举类其他内容
*/
public enum Gender3Enum implements Runnable { // 可以实现接口
// 带参数的枚举常量,括号中的参数对应的是我们自定义的变量,本例中参数是私有变量(info, i)
MAN("男",1),
WOMAN("女",2),
UNKNOWN("未知",3); // 枚举类型定义必须写在最上面,如果后面有其他非枚举成员,则最后使用分号结尾
// 添加私有变量
private String info;
private int i;
// 可以自定义构造函数,默认是private
Gender3Enum(String info,int i) {
this.info = info;
this.i = i;
}
// 可以重写父类方法
@Override
public String toString() {
return "info=" + info + ", i=" + i;
}
// 可以实现接口方法
@Override
public void run() {
}
}
/**
* 枚举类
*/
public class EnumTest {
public static void main(String[] args) throws Exception {
testEnumConst();
testEnumMethods();
testEnumSwitch(GenderEnum.MAN);
testEnumGetClass();
testEnumAbstractMethod();
testEnumToString();
testEnumReflect();
}
/**
* 获取枚举类常量
*/
public static void testEnumConst() {
// 调用普通类静态常量
System.out.println(Genders.MAN); // 0
// 使用枚举类,直接通过类名调用
System.out.println(GenderEnum.MAN); // MAN
}
/**
* 枚举类常用方法
*/
public static void testEnumMethods() {
// 返回枚举类型 name
System.out.println(GenderEnum.MAN.name()); // MAN
System.out.println(GenderEnum.MAN.toString()); // MAN
// 返回枚举类型序数,通常不使用
System.out.println(GenderEnum.WOMAN.ordinal()); // 1
// 比较大小(底层比较的是序数的大小)
int i = GenderEnum.MAN.compareTo(GenderEnum.WOMAN);
System.out.println(i); // -1
// 判断是否相等,底层使用 == 判断
boolean eq = GenderEnum.MAN.equals(GenderEnum.MAN);
System.out.println(eq); // true
// 根据 name 获取枚举对象
GenderEnum gender = GenderEnum.valueOf("MAN");
System.out.println(gender); // MAN
}
/**
* 在switch case中使用枚举
* @param gender
*/
public static void testEnumSwitch(GenderEnum gender) {
switch (gender) {
case MAN: // 不需要 gender 的引用,直接 case 枚举类型
System.out.println("man"); break; // man
case WOMAN:
System.out.println("woman"); break;
case UNKNOWN:
System.out.println("unknown"); break;
}
}
/**
* 获取枚举类的类型
*/
public static void testEnumGetClass() {
/*
* 当枚举类参数是一个类时,如:enum Gender { MAN{}, WOMAN{}, UNKNOWN{} },
* 此时:Gender.WOMEN.getDeclaringClass(); 返回数据为:*.Gender
* Gender.WOMEN.getClass(); 返回数据为:*.Gender1$2
* 所以如果是获取枚举类类型信息,建议使用 getDeclaringClass() 方法
*/
Class cls = GenderEnum.WOMAN.getDeclaringClass();
Class cls1 = Gender1Enum.WOMAN.getClass();
System.out.println(cls); // class cn.com.liyanlong......GenderEnum
System.out.println(cls1); // class cn.com.liyanlong......Gender1Enum$2
}
/**
* 测试枚举类中的抽象方法
*/
public static void testEnumAbstractMethod() {
System.out.println(Gender2Enum.MAN.getInfo()); // 男性
System.out.println(Gender2Enum.WOMAN.getInfo()); // 女性
System.out.println(Gender2Enum.UNKNOWN.getInfo()); // 未知
}
/**
* 测试获取枚举自定义变量
*/
public static void testEnumToString() {
for (Gender3Enum value : Gender3Enum.values()) {
System.out.println("value: " + value
+ "\t\tname: " + value.name()
+ "\t\ttoString: " + value.toString());
}
/*
* value: 男 name: MAN toString: info=男, i=1
* value: 女 name: WOMAN toString: info=女, i=2
* value: 未知 name: UNKNOWN toString: info=未知, i=3
*/
}
/**
* 测试,不可以通过反射方式获取枚举类实例
* @throws Exception
*/
public static void testEnumReflect() throws Exception{
// 获取类对象
Class<?> cls = Class.forName("cn.com.liyanlong.java.javase._09_frequently_used_classes.enum_class.GenderEnum");
// 获取 color 的构造函数
Constructor<?> constructor = cls.getDeclaredConstructor(String.class, int.class);
// 获取私有变量访问权限
constructor.setAccessible(true);
// 实例化
Object reflectGender = constructor.newInstance("MAN", 0);
/*
* 报错信息:
* Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
* at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
* ......
*/
}
}
# 可以使用javap(反编译class得到汇编)或者jad(反编译class)查看反编译后的内容,可以看到我们的枚举类自动继承了Enum类
# 用jad反编译并生成反编译后的java文件(推荐)
>jad -sjava GenderEnum.class
# 用javap命令可以查看一个java类反汇编、常量池、变量表、指令代码行号表等信息
>javap -c -l GenderEnum.class
# jad工具下载地址:https://varaneckas.com/jad/jad158g.win.zip,下载后将jad.exe文件放入环境变量中就可以使用了
# Java虚拟机指令集:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html
# javap命令详解:https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javap.html
// 使用jad命令反编译后的代码
// 这里默认使用final修饰,所以枚举类不能被继承
public final class GenderEnum extends Enum
{
// 这个方法返回原数组的副本,为了避免返回的数组内容被修改而引起内部值的改变,Enum类中没有此方法
public static GenderEnum[] values()
{
return (GenderEnum[])$VALUES.clone();
}
// 通过name来获取枚举实例
public static GenderEnum valueOf(String name)
{
return (GenderEnum)Enum.valueOf(cn/com/liyanlong/java/javase/_09_frequently_used_classes/enum_class/GenderEnum, name);
// 私有构造函数,不能new对象,自动生成
private GenderEnum(String s, int i)
{
super(s, i);
}
// 我们自己声明的枚举常量,都对应一个枚举类实例,且是static final修饰的常量
public static final GenderEnum MAN;
public static final GenderEnum WOMEN;
public static final GenderEnum UNKNOW;
// 成员变量$VALUES[]包含所有定义的枚举常量,可以通过values()方法获取
private static final GenderEnum $VALUES[];
// 静态初始化代码块,说明在类加载阶段就被实例化了,jvm能够保证类加载线程安全,且自动按照我们写的顺序添加序数,从0开始
sstatic
{
MAN = new GenderEnum("MAN", 0);
WOMAN = new GenderEnum("WOMAN", 1);
UNKNOWN = new GenderEnum("UNKNOWN", 2);
$VALUES = (new GenderEnum[] {
MAN, WOMAN, UNKNOWN
});
}
}
// 普通定义常量类反编译后,所以枚举类编译后,占用的内存稍微多一些
public class Genders
{
public Genders()
{
}
public static final int MAN = 0;
public static final int WOMAN = 1;
public static final int UNKNOWN = 2;
}
// 1. 枚举类不能被克隆,这是Enum类的clone()方法说明
/**
* Throws CloneNotSupportedException. This guarantees that enums
* are never cloned, which is necessary to preserve their "singleton"
* status.
*
* @return (never returns)
*/
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
// 2. 枚举类比较大小的方法最终比较的是初始化枚举类实例的时候自动添加的序数
/**
* Compares this enum with the specified object for order. Returns a
* negative integer, zero, or a positive integer as this object is less
* than, equal to, or greater than the specified object.
*
* Enum constants are only comparable to other enum constants of the
* same enum type. The natural order implemented by this
* method is the order in which the constants are declared.
*/
public final int compareTo(E o) {
Enum<?> other = (Enum<?>)o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}
6.4 数学计算
6.4.1 特点
相关的类有:
java.lang.Math
Math
类封装了与数学运算相关的一些属性和方法
6.4.2 代码示例
/**
* 数学计算相关类 Math
*/
public class MathTest {
public static void main(String[] args) {
// 自然对数的底数(或称为基数)
double e = Math.E;
System.out.println(e); // 2.718281828459045
// 圆周率
System.out.println(Math.PI); // 3.141592653589793
// 求绝对值
double abs = Math.abs(-10.1);
System.out.println(abs); // 10.1
// 求最大值
double max = Math.max(100,99.9);
System.out.println(max); // 100.00
// 求最小值
System.out.println(Math.min(1, 2)); // 1
// Math.pow(x, y): 返回 x的y次幂
System.out.println(Math.pow(2, 3)); // 2³ = 8.0
// Math.scalb(x, y): x*(2的y次幂)
System.out.println(Math.scalb(3, 3)); // 3*2³ = 24.0
// Math.ceil(x): 向上取整
System.out.println(Math.ceil(10.1)); // 11.0
System.out.println(Math.ceil(-10.1)); // -10.0
// Math.floor(x): 向下取整
System.out.println(Math.floor(10.1)); // 10.0
System.out.println(Math.floor(-10.1)); // -11.0
// Math.hypot(x, y): x和y平方和的二次方根,√(x²+y²)
System.out.println(Math.hypot(2, 2)); // 2.8284271247461903
// Math.sqrt(x): 求二次方根,
System.out.println(Math.sqrt(9)); //3.0
System.out.println(Math.sqrt(16)); //4.0
// Math.cbrt(x): 求立方根
System.out.println(Math.cbrt(27.0)); //3.0
System.out.println(Math.cbrt(-64.0)); //-4.0
// Math.log(): 对数函数
System.out.println(Math.log(e)); // 1 以e为底的对数
System.out.println(Math.log10(100)); // 10 以10为底的对数
// Math.log1p(x); // Ln(x+ 1)
// Math.random(): 随机数,范围:[0,1)
double random = Math.random();
System.out.println(random); // 0.6724380240187329
// 例:100以内随机数
int r = (int) (random * 100);
System.out.println(r); // 67
// Math.rint(x): 返回最接近这个数的整数,如果刚好居中,则取偶数
System.out.println(Math.rint(10.1)); // 10.0
System.out.println(Math.rint(-10.1)); // -10.0
System.out.println(Math.rint(10.9)); // 11.0
System.out.println(Math.rint(-10.9)); // -11.0
System.out.println(Math.rint(10.5)); // 10.0
System.out.println(Math.rint(11.5)); // 12.0
// Math.round(): 四舍五入
System.out.println(Math.round(10.5)); // 11 与rint相似,返回值为 long
System.out.println(Math.round(10.4)); // 10 与rint相似,返回值为 long
// 三角函数
// Math.sin(α); //sin(α)的值
// Math.cos(α); //cos(α)的值
// Math.tan(α); //tan(α)的值
// 求角
// Math.asin(x/z); //返回角度值[-π/2,π/2] arc sin(x/z)
// Math.acos(y/z); //返回角度值[0~π] arc cos(y/z)
// Math.atan(y/x); //返回角度值[-π/2,π/2]
// Math.atan2(y-y0, x-x0); //同上,返回经过点(x,y)与原点的的直线和经过点(x0,y0)与原点的直线之间所成的夹角
// Math.sinh(x); //双曲正弦函数sinh(x)=(exp(x) - exp(-x)) / 2.0;
// Math.cosh(x); //双曲余弦函数cosh(x)=(exp(x) + exp(-x)) / 2.0;
// Math.tanh(x); //tanh(x) = sinh(x) / cosh(x);
// 角度弧度互换
// Math.toDegrees(angrad); //角度转换成弧度,返回:angrad * 180d / PI
// Math.toRadians(angdeg); //弧度转换成角度,返回:angdeg / 180d * PI
}
}
6.5 日期时间
6.5.1 基本概念
时间
日期
时区
本地时间
本地化
夏令时
相关的类有:
java.util.Date
:日期类(包含日期和时间)java.util.Calendar
:日历类java.text.SimpleDateFormat
:日期时间格式化类
以上相关类不是
final
修饰的,可以被改变,线程不安全
6.5.2 代码示例
/**
* 日期操作相关类(JDK8之前【了解】)
* JDK8重新设计了新的时间API,建议使用新的API
* @see cn.com.liyanlong.java.javase.new_snytax.jdk8.LocalDateTest
*/
public class DateTest {
public static void main(String[] args) {
testDate();
testSimpleDateFormat();
testCalender();
}
/**
* Date使用
*/
public static void testDate() {
Date date = new Date();
String s = date.toString();
System.out.println(s); // Tue Jun 23 03:16:30 CST 2020
// 1970年1月1日0时到现在的毫秒数
long time = date.getTime();
System.out.println("时间戳:" + time); // 时间戳:1592885386872
/*
Date date1 = new Date(1592854524200L);
Date date2 = new Date("2020/6/23"); // 过时方法
System.out.println(date.equals(date1)); // false
System.out.println(date1.compareTo(date2)); // 1 大于返回1,小于返回-1,等于返回0
System.out.println(date.before(date1)); // false 在...之前
System.out.println(date.after(date1)); // true 在...之后
*/
// 以下方法为已过时方法,不建议使用
// API问题:年份从1900年开始,月份从0开始(新版API中已修正)
/*
System.out.println(date.getYear()); // 120 年份,返回1900年到现在的年数
System.out.println(date.getMonth()); // 5 月份,实际月份-1
System.out.println(date.getDate()); // 23
System.out.println(date.getDay()); // 2
System.out.println(date.getHours()); // 3
System.out.println(date.getMinutes()); // 16
System.out.println(date.getSeconds()); // 30
System.out.println(date.getTimezoneOffset()); // -480
System.out.println(date.toLocaleString()); // 1592853935794
*/
}
/**
* SimpleDateFormat:转换日期时间格式,线程不安全
*/
public static void testSimpleDateFormat() {
Date date = new Date();
// 可以自定义格式:如 yyyy-MM-dd, yyyy年MM月dd日 HH:mm:ss
SimpleDateFormat sdf =
new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
System.out.println(date); // Tue Jun 23 03:42:00 CST 2020
String str = sdf.format(date);
System.out.println(str); // 2020年06月23日 03:42:00
}
/**
* 日历类
*/
public static void testCalender() {
// 获取默认时区时间
Calendar calendar = Calendar.getInstance();
// 获取固定时区时间 (获取东八区时间)
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT+08:00"));
//获取年
int year = c.get(Calendar.YEAR);
//获取月份,0表示1月份
int month = c.get(Calendar.MONTH) + 1;
//获取当前天数
int day = c.get(Calendar.DAY_OF_MONTH);
//获取本月最小天数
int first = c.getActualMinimum(Calendar.DAY_OF_MONTH);
//获取本月最大天数
int last = c.getActualMaximum(Calendar.DAY_OF_MONTH);
//获取当前小时
int time = c.get(Calendar.HOUR_OF_DAY);
//获取当前分钟
int min = c.get(Calendar.MINUTE);
//获取当前秒
int sec = c.get(Calendar.SECOND);
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String curDate = s.format(c.getTime()); //当前日期
System.out.println(curDate); // 2020-06-23 11:15:18
System.out.println("当前时间:" + year + "-" + month + "-" + day + " " + time + ":" + min + ":" + sec);
System.out.println("本月第一天和最后一天:" + first +"," + last);
System.out.println("时间戳:" + calendar.getTimeInMillis());
System.out.println(calendar.getTime()); // Tue Jun 23 11:16:32 CST 2020
System.out.println(calendar.getTimeZone()); // 获取时区信息
int ryear = 2024;
if(ryear%4 == 0 && ryear%100 != 0 || ryear%400 == 0){
System.out.println("是闰年");
} else {
System.out.println("是平年");
}
// isLeapYear(year): 判断是否是闰年
boolean bn = new GregorianCalendar().isLeapYear(ryear);
System.out.println(bn); // true
}
}