常见类库
String类简介
String类不能被继承
通过源码可以看到String类前面加了final修饰,因此String类是不能够被继承的。将其设置为不能被继承的原因是为了减少歧义。
字符串(String)的不可变性
String创建好之后值是不可以被改变的,这里指的是在堆中的字符串的值是不可以被改变。
示例:
/*
String是不能被改变的
*/
public class String02 {
public static void main(String[] args) {
String s = "monkey";
change(s);
System.out.println("main:" + s);//monkey
}
public static void change(String s) {
s = "good";
System.out.println("change:" + s);
}
}
String是引用数据类型,但是这里作为方法参数传递的时候,效果跟基本数据类型是一样的。也就是说在堆中创建出来的字符串”monkey”是不能被改变的,如果要修改,系统会在堆中重新开辟内存空间将”good”放入,然后将change方法中的s重新引用这个新的内存地址上的”good”。
String不可变的主要原因是其底层使用了一个final修饰的byte数组(jdk9之后版本中),final修饰的变量是不能被改变的。在jdk8版本中,String底层使用的是final修饰的char数组。这个版本之间的变化。
字符串常量池
我们声明的字符串会放到一个叫做字符串常量池的地方,这样可以减少内存的使用,字符串常量池是堆的一部分。
String s1 = "monkey";//这种写法会利用字符串常量池,减少内存的使用
String s2 = "monkey";
String s3 = new String("monkey");
String s4 = new String("good");
System.out.println(s1 == s2);//true s1和s2的内存地址相同
System.out.println(s1 == s3);//false
System.out.println(s1.equals(s3));//true
上面代码中,创建s1时,字符串常量池中还不存在堆中monkey的引用,因此jvm会在常量池中创建一个引用指向堆中的这个字符串对象,创建s2时,jvm会去常量池中搜索,此时常量池中有monkey的引用,所以就不创建了,直接让s2指向之前创建的monkey,所以s1和s2指向的是同一个堆内存中的对象。
创建s3时,因为使用了new关键字,所以会在堆中开辟一块内存地址将其放入,s3指向这个新的内存地址,所以s3和s1指向的不是同一个内存地址。
创建s4时,使用了new关键字,会在堆中开辟一块内存地址,s4指向这个内存地址,然后字符串常量池中没有指向good的引用,所以会再重新开辟一块空间,将good放入,然后在字符串常量池中指向这个地址。
开发中建议使用String s = “monkey1024”;这种方式创建字符串对象,可以减少堆内存的使用。
注意:比较两个字符串是否一致最好使用equals方法
String类常用方法
-
char charAt(int index);获取index位置的字符
-
boolean contains(CharSequence s);判断字符串中是否包含某个字符串
-
boolean endsWith(String endStr);判断是否是以某个字符串结尾
-
boolean equalsIgnoreCase(String anotherString);忽略大小写比较两个字符串是否相等
-
byte[] getBytes();转换成byte数组
-
int indexOf(String str);取得指定字符在字符串的位置
-
int indexOf(String str, int fromIndex);从指定的下标开始取得指定字符在字符串的位置
-
int lastIndexOf(String str);从后面开始取得指定字符在字符串最后出现的的位置
-
int length();获取字符串的长度
-
String replaceAll(String s1,String s2);替换字符串中的内容
-
String[] split(String s);根据指定的表达式拆分字符串
-
boolean startsWith(String s);判断是否是以某个字符串开始
-
String substring(int begin);根据传入的索引位置截子串
-
String substring(int beginIndex, int endIndex);根据传入的起始和结束位置截子串
-
char[] toCharArray();将字符串转换为char数组
-
void toUpperCase();转换为大写
-
void toLowerCase();转换为小写
-
String trim();去除首尾空格
-
String valueOf(Object obj);将其他类型转换为字符串类型
String s1 = "monkey1024"; // char charAt(int index);获取index位置的字符 System.out.println(s1.charAt(5)); // boolean contains(CharSequence s);判断字符串中是否包含某个字符串 System.out.println(s1.contains("key")); // boolean endsWith(String endStr);判断是否是以某个字符串结尾 System.out.println(s1.endsWith("1028")); // boolean equalsIgnoreCase(String anotherString);忽略大小写比较两个字符串是否相等 System.out.println(s1.equalsIgnoreCase("Monkey1024")); // byte[] getBytes();转换成byte数组 String s2 = "abc"; byte[] b1 = s2.getBytes(); for(int i=0; i<b1.length; i++){ System.out.print(b1[i] + " "); } System.out.println(); // int indexOf(String str);取得指定字符在字符串的位置 System.out.println(s1.indexOf("y")); // int indexOf(String str, int fromIndex);从指定的下标开始取得指定字符在字符串的位置 String s3 = "monkey1024monkeyy"; System.out.println(s3.indexOf("y", 6)); // int lastIndexOf(String str);从后面开始取得指定字符在字符串最后出现的的位置 System.out.println(s3.lastIndexOf("y")); // int length();获取字符串的长度 System.out.println(s3.length()); // String replaceAll(String s1,String s2);替换字符串中的内容 String s4 = "monkeymonkey1024monkey"; System.out.println(s4.replaceAll("key", "YYY")); // String[] split(String s);根据指定的表达式拆分字符串 String s5 = "a,b,c,d"; String[] array1 = s5.split(","); for(int i=0; i<array1.length; i++){ System.out.print(array1[i] + " "); } System.out.println(); // boolean startsWith(String s);判断是否是以某个字符串开始 System.out.println(s3.startsWith("m1")); // String substring(int begin);根据传入的索引位置截子串 System.out.println(s3.substring(5)); // String substring(int beginIndex, int endIndex);根据传入的起始和结束位置截子串 System.out.println(s3.substring(6, 10)); // char[] toCharArray();将字符串转换为char数组 char[] array2 = s5.toCharArray(); for(int i=0; i<array2.length; i++){ System.out.print(array2[i] + " "); } System.out.println(); // void toUpperCase();转换为大写 System.out.println(s5.toUpperCase()); // void toLowerCase();转换为小写 System.out.println(s5.toLowerCase()); // String trim();去除首尾空格 String s6 = " java good ok "; System.out.println(s6.trim()); // String valueOf(Object obj);将其他类型转换为字符串类型 Object o = new Object(); o = null; System.out.println(String.valueOf(o));//建议使用这种方法转换字符串 //System.out.println(o.toString());//报出空指针错误
debug的使用
debug简介
通过debug功能可以方便程序员一步一步的观察程序运行中的数据变化。在很多集成开发环境中都有提供,比如IDEA,eclipse,myeclipse。
debug的作用:
- 可以帮助程序员快速定位问题
- 帮助程序员快速上手代码
debug的使用
首先在代码的某一行上添加断点,然后在idea中使用debug运行,就会出现下面的界面,里面的按钮我做了标号,下面有对应的解释
-
show execution point
快速定位到当前程序执行的位置
-
step over(F8)
让程序执行到下一行
-
step into(F7)
进入到方法中执行
-
force step into(alt shfit f7)
强制进入到方法中执行,适合进入第三方编写的方法当中
-
step out(shift F8)
跳出方法,在debug进入到某个方法中的时候可以跳出方法
-
drop frame
多次进出方法,当debug某个方法运行一部分之后,希望该方法再次进入debug,可以使用该按钮
-
run to curser(alt F9)
快速执行到当前光标所在的位置
-
evaluate expression(alt F8)
运行一些简短的代码,方便我们在debug的时候查看
-
trace current stream chain
在debug Stream流部分代码的时候可以帮助我们看到数据的变化
-
rerun(alt F5)
重新以debug方式运行
-
resume program(F9)
如果当前代码后面有断点则执行到下个断点所在的位置,否则程序运行结束
-
pause program
当程序以debug运行且执行到某个比较耗时操作的时候,点击按钮,会进入到debug模式运行程序
-
stop program(ctrl F2)
停止程序
-
view breakpoint (ctrl shift F8)
查看所有断点
-
mute breakpoint
断点全部失效/生效
-
get thread dump
查看线程的状态
-
restore layout
恢复debug布局
-
settings
设置
通过下面代码进行debug的演示
import java.util.ArrayList;
import java.util.Arrays;
/*
IDEA中的debug断点调试功能
*/
public class DebugTest01 {
public static void main(String[] args) throws InterruptedException {
int addResult = add();
int subtractResult = subtract();
System.out.println(addResult);
System.out.println(subtractResult);
Object o1 = new Object();
Object o2 = new Object();
//shift + f7 智能步入,进入到我们指定的方法中
System.out.println(o1.equals(o2));
}
public static int add() {
int a = 10;
int b = 15;
int c = a + b;
return c;
}
public static int subtract() {
int a = 30;
int b = 45;
int c = a - b;
return c;
}
}
正则表达式简介
正则表达式简介
有的地方也叫做规则表达式,通过正则可以将符合某种规则的字符串匹配出来,比如要将"monkey1024study1j2a3v4a"这个字符串中的数字替换为"中",可以使用正则表达式匹配数字,然后进行替换即可,正则表达式是一门独立的学科,这里这是简单介绍一下,以后在工作中用到的时候,可以去网上查。
“^m{2}$” 表示 2个m字符.等同于 “mm”
\d 表示数字
\D 表示非数字
\w 表示英文字母
\W 表示非英文字母
除了这些还有很多,工作中常用的有
匹配邮箱格式:\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+.)+[A-Za-z]{2,14}
匹配手机号:0?(13|14|15|18)[0-9]{9}
System.out.println("mm".matches("^m{2}$"));
String s1 = "monkey1024study1j2a3v4a";
//将数字替换为"中"
System.out.println(s1.replaceAll("\\d", "中"));
//匹配手机号
System.out.println("15188888888".matches("0?(13|14|15|18)[0-9]{9}"));
//匹配邮箱
System.out.println("monkey@monkey1024.com".matches("\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}"));
String相关练习题
String练习题
- 字符串反转,例如将"abc"变成"cba"
- 统计一个字符串里面另一个字符串出现的次数,例如统计"monkey"在"I am monkey1024.monkey like banana.little monkey is smart."中出现的次数
- 统计一个字符串中大写字母出现的次数
答案
1.思路:字符串是由多个字符组成的,可以将字符串转换为字符(char)数组,然后倒序遍历数组即可
package com.monkey1024.string;
import java.util.Scanner;
/**
* 字符串反转
*
*/
public class Exercise01 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
String input = s.next();
//将输入的字符串转换为char类型数组
char[] charArray = input.toCharArray();
//遍历数组并倒着输出
for(int i=charArray.length-1; i>=0; i--){
System.out.print(charArray[i]);
}
}
}
2.思路:通过indexOf方法在大的字符串中查找小字符串的索引值,找到后将这个索引值和小字符串的长度相加,之后将大的字符串截取根据相加的结果截取子串,然后继续在剩下的字符串中查找小字符串的索引值,直到索引值返回-1为止
package com.monkey1024.string;
/**
* 统计一个字符串里面另一个字符串出现的次数
*
*/
public class Exercise02 {
public static void main(String[] args) {
String src = "I am monkey1024.monkey like banana.little monkey is smart.";
String dest = "monkey";
//定义出现的次数
int count = 0;
//定义索引值
int index = 0;
while((index = src.indexOf(dest)) != -1){
count++;
//将src截取子串
src = src.substring(index + dest.length());
}
System.out.println("出现的次数是:" + count);
}
}
3.思路:每个大写字母都是一个字符char,而大写字母A~Z是有范围的,只要统计这个范围内的字符即可
package com.monkey1024.string;
public class Exercise03 {
public static void main(String[] args) {
String src = "monkEY";
//统计大写字母出现的次数
int count = 0;
//将字符串转换为字符数组
char[] c = src.toCharArray();
for(int i=0; i<c.length; i++){
//判断是否为大写字母
if(c[i] >= 'A' && c[i] <= 'Z'){
count++;
}
}
System.out.println("大写字母出现的次数:" + count);
}
}
StringBuffer和StringBuilder
StringBuffer简介
不要频繁的对字符进行拼接操作,例如下面代码:
String str = "";
for (int i = 0; i < 100; i++) {
str += i;//str = str + i; 造成内存空间的浪费
}
System.out.println(str);
每次对字符串修改,底层都会重新开辟新的堆内存空间,这样会开辟很多个空间地址,造成浪费。
如果需要对字符串进行频繁拼接的话,建议使用StringBuffer或者StringBuilder,两者的使用方法一致,下面以StringBuffer为例说明。
StringBuffer是一个字符串缓冲区,如果需要频繁的对字符串进行拼接时,建议使用StringBuffer。
工作原理
StringBuffer的底层是byte数组(jdk9之后),jdk8中底层是char数组,如果没有明确设定,则系统会默认创建一个长度为16的byte类型数组,在使用时如果数组容量不够了,则会通过数组的拷贝对数组进行扩容,所以在使用StringBuffer时最好预测并手动初始化长度,这样能够减少数组的拷贝,从而提高效率。
String与StringBuffer的区别?
String是不可变字符序列,存储在字符串常量池中
StringBuffer的底层是byte数组,系统会对该数组进行扩容
如何使用StringBuffer进行字符串拼接?
//创建对象
//StringBuffer sb = new StringBuffer();//底层会创建一个长度是16的byte数组
StringBuffer sb = new StringBuffer(300);//底层会创建一个长度是300的byte数组,对数据长度进行预估
for (int i = 0; i < 100; i++) {
sb.append(i);//拼接操作
}
System.out.println(sb);
StringBuilder和StringBuffer的区别
通过API可以看到StringBuilder和StringBuffer里面的方法是一样的,那他们有什么区别呢?
StringBuffer是jdk1.0版本中加入的,是线程安全的,效率低
StringBuilder是jdk5版本加入的,是线程不安全的,效率高
基本类型和包装类
包装类
什么是包装类?
Java里面8个基本数据类型都有相应的类,这些类叫做包装类。
包装类有什么优点
可以在对象中定义更多的功能方法操作该数据,方便开发者操作数据,例如基本数据类型和字符串之间的转换。
基本数据类型和对应的包装类
包装类都在java.lang包里面
基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
下面以Integer为例来学习一下包装类,Integer底层实际上就是一个final修饰的int成员变量。
获取int类型的最小值:
Integer.MIN_VALUE
获取int类型的最大值:
Integer.MAX_VALUE
创建Integer对象:
1.传入int类型,会将int类型的10转换为Integer类型,该构造方法已被废弃:
Integer i1 = new Integer(10);
2.传入String类型,会将String类型的”1024″转换为Integer类型,注意:如果传入的字符串不是数字,将会报出NumberFormatException。该构造方法已被废弃。
Integer i2 = new Integer("1024");
3.自动装箱,把基本类型转换为包装类类型,推荐使用
Integer i3 = 1024;
除此之外还有自动拆箱,可以将Integer类型的变量直接赋值给int类型:
Integer i4 = 1024;
int i5 = i4
将String类型转换为int类型,传入的字符串必须是数字字符串:
int i6 = Integer.parseInt("10");
将String类型转换为Integer类型:
Integer i7 = Integer.valueOf("10");
将int类型的十进制转换成2进制:
String s1 = Integer.toBinaryString(10);
将int类型的十进制转换成16进制:
String s2 = Integer.toHexString(10);
将int类型的十进制转换成8进制:
String s3 = Integer.toOctalString(10);
注意:Integer是引用数据类型,在判断两个Integer类型是否相等时,要使用equals方法,不能使用”==”,Integer已经重写了Object中的equals方法。
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3==i4);//false
整型缓存池
如果Integer的值是在[-128~127]之间,这些值会从Integer中的“整型缓存池”获取。
观察下面程序打印的结果
Integer i5 = 127;
Integer i6 = 127;
System.out.println(i5 == i6); //true
上面程序不会在堆中新建对象,会直接从整型常量池中拿。在比较Integer的值是否相等时,一定要使用equals方法,这里用==比较是为了引出整型缓存池
在Integer的源码中可以看到有一个静态内部类IntegerCache,该类中维护了一个数组,整型缓存池的本质就是一个数组,该数组中默认的存储范围是[-128,127],也就是说当Integer的值在这个范围内的话,会从数组中获取,这就是为什么上面代码结果是true的原因了。另外我们可以通过参数来设置缓存池的上限。输入下面参数:
-XX:AutoBoxCacheMax=256
这样整型缓存池的上限就到了256,即在[-128,256]范围内的值会从数组中获取。
拆箱装箱和整型缓存
什么是自动拆箱和自动装箱?
-
自动装箱:把基本类型转换为包装类类型
Integer i1 = 10;
-
自动拆箱:把包装类类型转换为基本类型
Integer i1 = 10; int i2 = i1;
以上特性是jdk5中加入的,也就是说在jdk5版本之前是不支持自动装箱和自动拆箱的。
注意:在判断两个Integer类型是否相等时,要使用equals方法,不能使用”==”,Integer已经重写了Object中的equals方法。
这种写法
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3==i4);//false
相当于
Integer i3 = new Integer(128);
Integer i4 = new Integer(128);
System.out.println(i3==i4);//false
整型缓存池
如果Integer的值是在[-128~127]之间,这些值会从Integer中的“整型缓存池”获取。
观察下面程序打印的结果
Integer i5 = 127;
Integer i6 = 127;
System.out.println(i5 == i6); //true
上面程序不会在堆中新建对象,会直接从整型常量池中拿。在比较Integer的值是否相等时,一定要使用equals方法,这里用==比较是为了引出整型缓存池
在Integer的源码中可以看到有一个静态内部类IntegerCache,该类中维护了一个数组,数组中默认的存储范围是[-128,127],也就是说当Integer的值在这个范围内的话,会从数组中获取,这就是为什么上面代码结果是true的原因了。另外我们可以通过参数来设置缓存池的上限。输入下面参数:
-XX:AutoBoxCacheMax=256
这样整型缓存池的上限就到了256,即在[-128,256]范围内的值会从数组中获取。
日期类型
获取毫秒数
工作中基本上都会需要使用对时间的操作,java也提供了一些时间相关的类。
下面代码可以获取自 1970年1月1日 00时00分00秒 000毫秒 到当前的毫秒数。
package com.monkey1024.date;
/**
* 获取自 1970年1月1日 00时00分00秒 000毫秒 到当前的毫秒数
* 演示String和StringBuffer分别进行字符串拼接所需要的毫秒数
*/
public class DateTest01 {
public static void main(String[] args) {
long now = System.currentTimeMillis();
System.out.println(now);
String s = "";
StringBuffer sb = new StringBuffer();
//获取拼接前的毫秒数
long before = System.currentTimeMillis();
for(int i=0; i<=100; i++){
// s += i;拼接String
// sb.append(i);拼接StringBuffer
}
//拼接后的毫秒数
long after = System.currentTimeMillis();
//总共耗时毫秒
System.out.println(after - before);
}
}
获取系统当前时间
在java.util包下面有个Date类,通过这个类可以获取系统的当前时间
package com.monkey1024.date;
import java.util.Date;
/**
*
* 获取系统当前时间
*
*/
public class DateTest02 {
public static void main(String[] args) {
//获取系统当前时间
Date nowTime = new Date();
System.out.println(nowTime);
Date d1 = new Date(0);//如果构造方法中参数传为0代表的是1970年1月1日
System.out.println(d1);
}
}
日期格式化类
上面代码中打印的日期格式不太符合中国的风格,国人一般习惯的时期格式是:
1970年01月01日 00时00分00秒
在java.text包下有个SimpleDateFormat类,通过这个类可以将日期修改为我们想要的风格
package com.monkey1024.date;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* 日期格式化
*
*/
public class DateTest02 {
public static void main(String[] args) {
//获取系统当前时间
Date nowTime = new Date();
System.out.println(nowTime);
Date d1 = new Date(0);//如果构造方法中参数传为0代表的是1970年1月1日
System.out.println(d1);
//1.创建日期格式化对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss SSS");
//可以改成其他格式
//SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
//2.开始格式化(Date--->String)
String strTime = sdf.format(nowTime);
System.out.println(strTime);
}
}
上面代码中需要注意大小写区分:
y表示年
M表示月
d表示日
H表示小时
m表示分钟
s表示秒
S表示毫秒
将String类型转换为Date类型
package com.monkey1024.date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* 将String类型转换为Date类型
*
*/
public class DateTest03 {
public static void main(String[] args) {
String strTime = "2017年01月01日 00:00:00 000";
//将String日期转换成日期类型Date
//String-->Date
//1.创建日期格式化对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss SSS"); //格式不能随意,应该和上面的字符串格式相同。
//2.将字符串转换成日期类型
Date d = new Date();
try {
d = sdf.parse(strTime);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(d);
}
}
Calendar简介
Calendar 类是一个抽象类,为操作日历方面提供了一些方法
package com.monkey1024.date;
import java.util.Calendar;
/**
*
* Calendar
*
*/
public class DateTest04 {
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
//查看当前日期是星期几
int i = c.get(Calendar.DAY_OF_WEEK);
System.out.println(i); //外国人将周日看做是第一天
System.out.println(c.get(Calendar.DAY_OF_MONTH));
}
}
关于@Deprecated的说明
通过源码可以看到,在java.util.Date类中的源码里面可以看到很多方法上面标有@Deprecated,这些方法是已经不建议使用了,对于开发者来说最好不要使用标有@Deprecated的方法了。
练习
1.编写代码获取2008年8月8日是星期几?
2.算一下你来到这个世界多少天?
答案
1.分析:首先获取2008年8月8日的Date类型,然后通过Calendar里面的DAY_OF_WEEK属性可以判断出示星期几
package com.monkey1024.date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
*
* 编写代码获取2008年8月8日是星期几
*
*/
public class Exercise01 {
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
//获取2008-8-8的日历
String strTime = "2008-08-08";
Date d = new Date();
try {
d = new SimpleDateFormat("yyyy-MM-dd").parse(strTime);
} catch (ParseException e) {
e.printStackTrace();
}
c.setTime(d);
System.out.println(c.get(Calendar.DAY_OF_WEEK));
}
}
2.分析:获取出生日期和当前日期的Date类型,然后将两个日期的毫秒值做减法,之后用这个毫秒值除以1000,再除以60,再除以60,再除以24得到天
package com.monkey1024.date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* 算一下你来到这个世界多少天
*
*/
public class DateTest04 {
public static void main(String[] args) throws ParseException {
//生日
String birthday = "2016年06月15日";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
//将生日字符串转换成日期对象
Date d1 = sdf.parse(birthday);
Date d2 = new Date();
//将两个日期的毫秒值做减法
long time = d2.getTime() - d1.getTime();
//除以1000,再除以60,再除以60,再除以24得到天
System.out.println(time / 1000 / 60 / 60 / 24 );
}
}
Math类简介
Math类概述
在java.lang包下,有个Math类,这个类包含用于执行基本数学运算的方法,如四舍五入,开方等等。
package com.monkey1024.math;
/**
* Math类常用方法
*
*/
public class MathTest {
public static void main(String[] args) {
//圆周率
System.out.println(Math.PI);
//取绝对值
System.out.println(Math.abs(-10));
//ceil天花板,会向上取值,结果是double
System.out.println(Math.ceil(12.3));
System.out.println(Math.ceil(12.99));
System.out.println("-----------");
//floor地板,会向下取整,结果是double
System.out.println(Math.floor(12.3));
System.out.println(Math.floor(12.99));
//获取两个值中的最大值
System.out.println(Math.max(20, 30));
//前面的数是底数,后面的数是指数,即2的3次方
System.out.println(Math.pow(2, 3));
//生成0.0到1.0之间的随机小数,包括0.0,不包括1.0
System.out.println(Math.random());
//四舍五入
System.out.println(Math.round(12.3f));
System.out.println(Math.round(12.9f));
//开平方
System.out.println(Math.sqrt(16));
}
}
BigInteger类简介
BigInteger类概述
BigInteger类可以让超过Integer范围的数据进行运算,通常在对数字计算比较大的行业中应用的多一些。
package com.monkey1024.big;
import java.math.BigInteger;
/**
* BigInteger可以让超过Integer范围的数据进行运算
*
*/
public class BigIntegerTest01 {
public static void main(String[] args) {
BigInteger bi1 = new BigInteger("100");
BigInteger bi2 = new BigInteger("2");
System.out.println(bi1.add(bi2)); //+
System.out.println(bi1.subtract(bi2)); //-
System.out.println(bi1.multiply(bi2)); //*
System.out.println(bi1.divide(bi2)); ///(除)
BigInteger[] arr = bi1.divideAndRemainder(bi2); //取除数和余数
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
BigDecimal类简介
BigDecimal类概述
由于在运算的时候,float类型和double很容易丢失精度,在金融、银行等对数值精度要求非常高的领域里面,就不能使用float或double了,为了能精确的表示、计算浮点数,Java提供了BigDecimal。
注意:如果对计算的数据要求高精度时,必须使用BigDecimal类
package com.monkey1024.big;
import java.math.BigDecimal;
/**
* BigDecimal简介
*
*/
public class BigDecimalTest01 {
public static void main(String[] args) {
System.out.println(2.0 - 1.1);
//这种方式在开发中不推荐,因为不够精确
BigDecimal bd1 = new BigDecimal(2.0);
BigDecimal bd2 = new BigDecimal(1.1);
System.out.println(bd1.subtract(bd2));
//开发时推荐通过传入字符串的方式
BigDecimal bd3 = new BigDecimal("2.0");
BigDecimal bd4 = new BigDecimal("1.1");
System.out.println(bd3.subtract(bd4));
//这种方式在开发中也是推荐的
BigDecimal bd5 = BigDecimal.valueOf(2.0);
BigDecimal bd6 = BigDecimal.valueOf(1.1);
System.out.println(bd5.subtract(bd6));
//计算除法的时候需要设置保留小数的个数
BigDecimal bd3 = new BigDecimal("10");
BigDecimal bd4 = new BigDecimal("3");
//四舍五入保留两位小数
BigDecimal result = bd3.divide(bd4,2,BigDecimal.ROUND_HALF_UP);
//上面方法在jdk9中被废弃了,推荐使用下面方法
BigDecimal result = bd3.divide(bd4,2, RoundingMode.HALF_UP);
}
}
DecimalFormat类
DecimalFormat类概述
在一些金融或者银行的业务里面,会出现这样千分位格式的数字,¥123,456.00,表示人民币壹拾贰万叁仟肆佰伍拾陆元整,java.text包下提供了一个DecimalFormat的类可以满足这样的需求。
package com.monkey1024.big;
import java.text.DecimalFormat;
/**
* DecimalFormat简介
*
*/
public class DecimalFormatTest01 {
public static void main(String[] args) {
//格式化人民币
String money = DecimalFormat.getCurrencyInstance().format(123456);
System.out.println(money);
//创建数字格式化对象
//需求:加入千分位.
DecimalFormat df = new DecimalFormat("###,###");
//开始格式化
System.out.println(df.format(1234567)); //"1,234,567"
//加入千分位,保留2位小数
DecimalFormat df1 = new DecimalFormat("###,###.##");
System.out.println(df1.format(1234567.123)); //"1,234,567.12"
//加入千分位,保留4位小数,并且不够补0
DecimalFormat df2 = new DecimalFormat("###,###.0000");
System.out.println(df2.format(1234567.123));
}
}
enum简介
enum简介
在日常开发中可能有一些数值是固定的,比如一年只有4个季节,春夏秋冬。我们可以自己定义一个类里面存放这4个季节。在jdk5之后,引入了枚举(enum)的概念,可以通过enum去定义这四个季节。enum本质还是一个类,枚举类型的父类:java.lang.enum。
定义常量类,里面存放四季
package com.monkey1024.enumtest;
/**
* 常量类
*
*/
public class Constant {
public static final String SPRING = "spring";
public static final String SUMMER = "summer";
public static final String AUTUMN = "autumn";
public static final String WINTER = "winter";
}
定义枚举类存放四季
//使用枚举存放四季
public enum Season{
Spring,Summer,Autumn,Winter
}
使用枚举
//调用枚举
System.out.println(Season.Summer);
//调用常量
System.out.println(Constant.SUMMER);
我们可以在枚举中添加属性,提供对应的构造方法进行赋值
package com.monkey1024.fnumber;
//使用枚举存放四季
public enum Season {
Spring(1,"春天"),Summer(2,"夏天"),Autumn(3,"秋天"),Winter(4,"冬天");
//添加属性
private int id;
private String name;
//构造方法
Season(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
获取枚举中的属性
System.out.println(Season.Summer.getName());
伪随机数
Random类概述
Random类在java.util包下,使用这个类可以生成随机数
package com.monkey1024.random;
import java.util.Random;
public class RandomTest01 {
public static void main(String[] args) {
Random r = new Random();
//生成int类型的随机数
int ran = r.nextInt(101); //[0-100]之间的随机数
System.out.println(ran);
//循环生成5个随机数
for(int i=0;i<5;i++){
System.out.println(r.nextInt(101));
}
}
}
SecureRandom简介
Random生成的随机数是可预测的,属于弱随机数,对于随机数敏感的场景,比如抽大奖,需要使用SecureRandom来生成随机数,该类生成的随机数是强随机数,强随机数生成的结果取决于内存状态,硬盘空闲空间,进程数量等等。
下面示例演示了使用相同的种子,弱随机数和强随机数生成的结果:
//弱随机数
Random r1 = new Random(1);
Random r2 = new Random(1);
//循环10次,打印结果一致
for (int i = 0; i < 10; i++) {
System.out.println(r1.nextInt(100));
System.out.println(r2.nextInt(100));
}
//强随机数
byte[] bytes = new byte[3];
SecureRandom sr1 = new SecureRandom(bytes);
SecureRandom sr2 = new SecureRandom(bytes);
//打印结果不一致
for (int i = 0; i < 10; i++) {
System.out.println(sr1.nextInt(100));
System.out.println(sr2.nextInt(100));
}
练习
完成一个彩票机选号码生成器,这里以双色球为例,双色球每注中奖号码由6个不同的红色球号码和1个蓝色球号码组成。红色球号码从133中选择;蓝色球号码从116中选择。
答案
分析:随机的从133中选择6个不同的数字,需要去重,随机从116中选择1个数字,可以组成一注中奖号码。
import java.util.Arrays;
import java.util.Random;
/*
完成一个彩票机选号码生成器,这里以双色球为例,
双色球每注中奖号码由6个不同的红色球号码和1个蓝色球号码组成。
红色球号码从1~33中选择;蓝色球号码从1~16中选择。
*/
public class ColorBall {
public static void main(String[] args) {
//初始化双色球号码
int[] balls = new int[33];
for (int i = 0; i < balls.length ; i++) {
balls[i] = i + 1;
}
//定义数组保存6个红球号码
int[] result = new int[6];
//定义下标的变量
int index = 0;
Random r = new Random();
//创建数组标记红球是否重复
boolean[] isUsed = new boolean[balls.length];
while (true) {
//生成随机数作为数组下标
int red = r.nextInt(33);
//判断该随机数是否生成过
if (isUsed[red]){
continue;
}
//将当前随机数标记为使用过
isUsed[red] = true;
//根据下标获取一个红球号码,放入到result数组中
result[index++] = balls[red];
//判断是否生成了6个红球
if (index == 6) {
break;
}
}
//排序
Arrays.sort(result);
System.out.println("红球:" + Arrays.toString(result));
//生成篮球
int blue = r.nextInt(16);
System.out.println("蓝球:" + balls[blue]);
}
}