七、常用类库API
01.字符串操作
- String类:
1.1 表示一个字符串,还用字符数组存储;
1.2 两种赋值方式:直接赋值(有可能不会创建对象,省内存空间)、通过关键字new调用String的构造方法赋值(至少要创建一个对象,有可能要创建两个);
1.3 String是一个final类,不能被继承;
1.4 直接赋值字符串连接时,考虑编译期和运行期(四种情况):如果在编译期值可以被确定,那么就使用已有的对象,否则会创建新的对象;
1.5 重要的操作方法:charAt(),根据下标索引找到指定的字符;toCharArray(),变成字符数组;String(char数组),把字符数组转换成字符串;String(char数组,int offset,int count),把指定长度的字符数组转换成字符串(注意:不包括count下标);split(),根据指定字符拆分;valueOf(),转换成字符串; - StringBuffer类:
2.1 在实际开发中,使用字符串连接操作,如果用String操作则使用“+”,代码性能会非常低(因为String的内容不可改变),解决方法是使用StringBuffer;
2.2 StringBuffer目的是解决字符串相加是带来的性能问题(常量和变量相加),常量相加没有性能问题;
2.3 内部实现采用字符数组,数组默认长度为16,超过数组大小时动态扩充(原来长度*2+2);
2.4 若已知要添加的数据长度时,建议使用带初始化容量的构造方法,避免动态扩充次数,提高效率;
2.5 线程安全的,会影响性能; - StringBuilder类:
3.1 一个可变的字符序列,提供与StringBuffer兼容的API,但不保证同步;被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候;
3.2 与StringBuffer的区别:StringBuffer线程安全,性能低,适合多线程;StringBuilder线程不安全,性能高,适合单线程使用,这种情况占大多数。
public class Test{
public static void main(String[] args) {
String str1 = "奋奋";//在堆中的常量池
String str2 = new String("奋奋");//在堆中创建对象
System.out.println(str1==str2);//false
String a = "a";//编译时确定
String a1 = a+1;//运行时确定,堆中创建对象
String a2 = "a1";//编译时确定,在常量池中创建
System.out.println(a1==a2);//false
final String b = "b";//b为常量,编译期确定
String b1 = b+1;//编译期确定
String b2 = "b1";//编译期确定
System.out.println(b1==b2);//true
String c = getC();//运行期确定
String c1 = c+1;//运行期确定
String c2 = "c1";//编译期确定
System.out.println(c1==c2);//false
final String d = getD();//运行期确定
String d1 = d+1;//运行期确定
String d2 = "d1";//编译期确定
System.out.println(d1==d2);//false
}
private static String getC() {
return "c";
}
private static String getD() {
return "d";
}
public static void StringBufferTest() {
StringBuffer sb = new StringBuffer();
sb.append(a).append(b).append(1);
System.out.println(sb.toString());
}
}
02.程序国际化
- 同一套程序代码可以在各个语言环境下进行使用,各个语言环境下,只是语言显示的不同,那么具体的程序操作本身都是一样的;
- Locale类:Locale对象表示了特定的地理、政治和文化地区,需要Locale来执行其任务的操作称为语言环境敏感的操作,使用Locale为用户量身定制信息;
- 构造方法:Locale(String language),Locale(String language,String country);
- 创建Locale:静态方法getDefault();
- ResourceBundle类:国际化的实现核心在于显示的语言上,通常的做法是将其定义成若干个属性文件(.properties),属性文件中的格式采用key-value的格式进行操作;ResourceBundle类表示的是一个资源文件的读取操作,所有的资源文件需要使用ResourceBundle进行读取,读取的时候不需要加上文件的后缀;
- 处理动态文本:使用MessageFormat类完成,这个类是Format的子类。
import java.text.MessageFormat;
import java.util.*;
public class LocaleTest {
public static void main(String[] args) {
//创建一个本地语言环境对象,该对象会根据参数设置来自动选择与之相关的语言环境(参数:语言,地区)
Locale locale_CN = new Locale("zh","CN");
Locale locale_US = new Locale("en","US");
//获取当前系统默认的语言环境
Locale locale_default = Locale.getDefault();
Scanner input = new Scanner(System.in);
//用于绑定属性文件的工具类(参数:属性文件的基名,就是前缀),可以添加语言环境,不添加就是用默认的
ResourceBundle rb = ResourceBundle.getBundle("com.se.test.info",locale_CN);
System.out.println(rb.getString("system.name"));
System.out.println(rb.getString("input.username"));
String username = input.nextLine();
System.out.println(rb.getString("input.password"));
String password = input.nextLine();
if("admin".equals(username)&&"123".equals(password)){
System.out.println(rb.getString("login.success"));
String welcome = rb.getString("welcome");
welcome = MessageFormat.format(welcome, username);
System.out.println(welcome);
} else {
System.out.println(rb.getString("login.error"));
}
}
}
//属性文件1
info_en_US.properties
system.name=EMP Manager System
input.username=Input UserName:
input.password=Input Password:
login.success=Login Success!
login.error=Login Error...
welcome=Welcome,{0}!
//属性文件2
info_zh_CH.properties
system.name=\u5458\u5DE5\u7BA1\u7406\u7CFB\u7EDF
input.username=\u8F93\u5165\u7528\u6237\u540D\uFF1A
input.password=\u8F93\u5165\u5BC6\u7801\uFF1A
login.success=\u767B\u5F55\u6210\u529F\uFF01
login.error=\u767B\u5F55\u9519\u8BEF\u3002\u3002\u3002
welcome=\u6B22\u8FCE\u4F60\uFF0C{0}\uFF01
03.Math与Random类
- Math类:包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数;
1.1 两种使用方式:直接使用(默认引入的包)、静态导入(import static java.lang.Math.***);
1.2 一些常用的静态方法:PI,abs,random()(0-1之间的随机数),round(double a),sqrt(double a),floor(double a)(近似值); - Random类:此类的实例用于生成伪随机数流。
import java.util.Random;
import static java.lang.Math.floor;
public class MathTest {
public static void main(String[] args) {
System.out.println(Math.PI);//3.141592653589793
System.out.println(Math.abs(-10));//10
System.out.println(Math.round(Math.random()*1000)/1000.0);//0.203
System.out.println(Math.sqrt(2));//1.4142135623730951
System.out.println(floor(1.23456));//1.0
Random r = new Random();
System.out.println(r.nextLong());//0-long类型最大数的随机数
System.out.println(r.nextInt(10));//int类型0-10之间的随机数,不写10就是0-int最大值之间的随机数
}
}
04.日期操作类
- Date类:表示特定的瞬间,精确到毫秒,也就是程序运行时的当前时间(Date date = new Date(),实例化Date对象,表示当前时间),两个构造方法:
1.1 Date(long date),参数是毫秒;
1.2 Date(),空参;
1.3 实际在开发中都不建议使用; - Calendar类:日历类,使用此类可以将时间精确到毫秒显示(两种实例化方式:Calendar c = Calendar.getInstance();Calendar c = new GregorianCalendar());
- DateFormat类及子类SimpleDateFormat。
import java.text.*;
import java.util.*;
public class DateTest {
public static void main(String[] args) {
Date date = new Date();
System.out.println(date);
Calendar c1 = Calendar.getInstance();
Calendar c2 = new GregorianCalendar();
int year = c1.get(Calendar.YEAR);
int month = c1.get(Calendar.MONTH);
int day = c1.get(Calendar.DAY_OF_MONTH);
int hour = c1.get(Calendar.HOUR_OF_DAY);
int minute = c1.get(Calendar.MINUTE);
int second = c1.get(Calendar.SECOND);
int millisecond = c1.get(Calendar.MILLISECOND);
StringBuilder sb = new StringBuilder();
sb.append(year).append("年").append(month).append("月").append(day).append("日").append(hour).append("时").append(minute).append("分").append(second).append("秒").append(millisecond).append("毫秒");
System.out.println(sb.toString());
//使用DateFormat可以自定义格式,比上面append方式更方便
DateFormat df = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss SSS");
String nowDate = df.format(date);
System.out.println(nowDate);
}
}
05.对象比较器
- 对两个或多个数据项进行比较,以确定它们是否相等,或确定它们之间的大小关系及排列顺序;
- Comparable接口和Comparator接口:
2.1 Comparable接口强行对实现它的每个类的对象进行整体排序(类的自然排序);
2.2 Comparator接口要求自定义类去实现,按照OO原则:对修改关闭,对扩展开放; - 自定义对象要实现比较排序:
3.1 可以实现Comparable接口的compareTo方法;
3.2 实现Comparator接口的compare方法。
//自定义对象
//若不想改Cat类实现Comparable接口,还可以另外定义一个实现Comparator类
public class Cat { //implements Comparable<Cat> {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Cat(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Cat() {
super();
}
@Override
public String toString() {
return "Cat [name=" + name + ", age=" + age + "]";
}
//重写比较方法实现排序
//@Override
//public int compareTo(Cat o) {
//return this.age - o.age;
//}
}
//实现Comparator接口,不修改原类
import java.util.Comparator;
public class CatComparator implements Comparator<Cat> {
@Override
public int compare(Cat o1, Cat o2) {
return o1.getAge()-o2.getAge();
}
}
//测试
import java.util.Arrays;
public class CompareTest {
public static void main(String[] args) {
Cat[] cats = {new Cat("tom",2),new Cat("jim",4),new Cat("ben",1),new Cat("ker",3)};
//Arrays.sort(cats);、、第一种方法
Arrays.sort(cats,new CatComparator());//第二种方法
Arrays.sort(cats);
System.out.println(Arrays.toString(cats));
}
}
06.对象的克隆
- 将一个对象复制一份,称为对象的克隆技术;
- 如果某个类的对象要想被克隆,对象所在的类必须实现Cloneable接口,此接口没有定义任何方法,是一个标记接口;克隆步骤:
2.1 实现Cloneable接口;
2.2 重写Object类中的clone()方法(标记方法)。
//需要克隆对象所在的类
//1.实现Cloneable接口
public class Cat implements Cloneable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Cat(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Cat() {
super();
}
@Override
public String toString() {
return "Cat [name=" + name + ", age=" + age + "]";
}
//2.重写Object的clone()方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
07.System和Runtime类
- System类代表系统,系统的很多属性和控制方法都放置在该类的内部;
1.1 成员变量:in,标准输入流(键盘输入);out,标准输出流(显示器);err,标准错误输出流;
1.2 成员方法:arraycopy,数组拷贝,该方法是native方法比使用循环高效;currentTimeMillis,返回当前计算机的时间,时间表达格式为当前计算机时间和GMT时间所差的毫秒数;exit(),0正常退出虚拟机,非零代表异常退出;gc,请求系统进行垃圾回收(是否立刻回收取决于垃圾回收算法的实现以及系统执行的情况);getProperty(String key),获得系统中属性名为key的属性对应的值; - Runtime类:每个java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接;
2.1 Runtime对象:通过静态方法getRuntime()获得;
2.2 availableProcessors(),处理器数量;
2.3 totalMemory(),JVM总内存数;
2.4 freeMemory(),JVM空闲内参数;
2.5 maxMemory(),JVM可用最大内存数。
import java.io.IOException;
import java.text.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
System.out.println("向控制台输出");
System.err.println("出错了");
int[] num1 = {1,2,3,4,5};
int[] num2 = new int[num1.length];
//参数:原数组,原数组起始位置,目标数组,目标数组起始位置,长度
System.arraycopy(num1, 0, num2, 0, num1.length);
System.out.println(Arrays.toString(num2));
//currentTimeMillis()方法
Date date = new Date(System.currentTimeMillis());
DateFormat fd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SS");
System.out.println(fd.format(date));
//getProperty()方法
System.out.println(System.getProperty("java.version"));//java运行时环境版本
System.out.println(System.getProperty("java.home"));//java安装目录
System.out.println(System.getProperty("os.name"));//操作系统版本
//Runtime类
Runtime rt = Runtime.getRuntime();
System.out.println(rt.availableProcessors());
System.out.println(rt.totalMemory());
System.out.println(rt.freeMemory());
System.out.println(rt.maxMemory());
//在单独的进程中执行指定的字符串命令
try {
rt.exec("notepad");//打开记事本
} catch (IOException e) {
e.printStackTrace();
}
}
}
08.数字处理工具类
- BigInteger:可以让超过Integer范围内的数据进行运算;
- BigDecimal:在运算的时候,float和double类型容易丢失精度,BigDecimal可以精确表示、计算浮点数;
- DecimalFormat:数字格式化,new DecimalFormat(“0.00”).format()(取小数位的格式,0或#表示选择的格式)。
09.MD5工具类
MD5:信息摘要算法(用来对密码等敏感信息进行密文存储)。
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class MD5Test {
public static void main(String[] args) {
String password = "admin12345";//明文
try {
MessageDigest md = MessageDigest.getInstance("md5");
//通过MD5计算摘要
byte[] bytes = md.digest(password.getBytes("UTF-8"));
//使用Base64:a-z A-Z 0-9 / * 对摘要进行编码存储
String str = Base64.getEncoder().encodeToString(bytes);//密文
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
10.数据结构之二叉树
- 树是一种重要的非线性数据结构,它是数据元素(在树中称为节点)按分支关系组织起来的结构;二叉树是每个节点最多有两个子树的有序树,通常子树被称作左子树和右子树;
- 二叉树算法的排序规则:
2.1 选择第一个元素作为根节点;
2.2 之后如果元素大于根节点放在右子树,如果元素小于根节点,放在左子树;
2.3 最后按照中序遍历的方式进行输出(左→根→右)。
public class BinaryTree {
private Node root;
//添加节点
public void add(int data){
if(root==null){
root = new Node(data);
}else{
root.addNode(data);
}
}
//输出节点
public void print(){
root.printNode();
}
//使用内部类实现节点的创建
private class Node{
private int data;
private Node left;
private Node right;
public Node(int data){
this.data = data;
}
public void addNode(int data){
if(this.data>data){
if(this.left==null){
this.left = new Node(data);
}else{
this.left.addNode(data);
}
}else{
if(this.right==null){
this.right = new Node(data);
}else{
this.right.addNode(data);
}
}
}
//中序遍历输出
public void printNode(){
if(this.left!=null){
this.left.printNode();
}
System.out.print(this.data+"->");
if(this.right!=null){
this.right.printNode();
}
}
}
}
public class BinaryTreeTest {
public static void main(String[] args) {
BinaryTree bt = new BinaryTree();
bt.add(8);
bt.add(3);
bt.add(10);
bt.add(1);
bt.add(6);
bt.add(14);
bt.add(4);
bt.add(7);
bt.add(13);
bt.print();
}
}
11.JDK1.8新特性—Lambda表达式
- Lambda表达式:把函数作为一个方法的参数,或者把代码看成数据,用于简化Java中接口式的匿名内部类;
- 语法:(参数1,参数2…)->{…};
- 特点:
3.1 代码更简洁;
3.2 不会单独生成class文件;
3.3 接口里不止一个抽象方法时就不能使用;
3.4 接口中的默认方法(public default void print())不影响使用Lambda表达式;
3.5 接口中的静态方法也不影响使用Lambda表达式。
public class LambdaTest {
public static void main(String[] args) {
//原始创建只有一个方法接口对象的方法
Eat eat1 = new EatImpl();
eat1.eat();
//进阶版创建只有一个方法接口对象,使用匿名内部类
Eat eat2 = new Eat(){
@Override
public void eat() {
System.out.println("eat bnana");
}
};
eat2.eat();
//Lambda表达式(无参数使用)
Eat eat3 = ()->{System.out.println("eat orange");};
eat3.eat();
//Lambda表达式(无参数使用)
//代码块只有一句,可以省略大括号
Eat1 eat4 = (thing)->System.out.println("eat---"+thing);
eat4.eat("orange");
//带返回值的方法
Eat2 eat5 = (thing,weight)->{
System.out.println("eat---"+thing);
return weight;
};
eat5.eat("orange",10);
}
}
//只有一个抽象方法的接口
//无参情况
interface Eat{
public void eat();
}
class EatImpl implements Eat{
@Override
public void eat() {
System.out.println("eat apple");
}
}
//有参情况
interface Eat1{
public void eat(String thing);
}
//有参情况,带返回值
interface Eat2{
public int eat(String thing, int weight);
}
//比较器应用实例
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
super();
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
//测试
import java.util.Arrays;
import java.util.Comparator;
public class StudentTest {
public static void main(String[] args) {
Student[] students = {new Student("Tom",18),new Student("Jim",14),new Student("Ler",20)};
//匿名内部类
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
}
});
System.out.println(Arrays.toString(students));
//Lambda表达式
Arrays.sort(students,(o1,o2)->o1.getAge()-o2.getAge());
System.out.println(Arrays.toString(students));
}
}