00 06Java高级之Java基础类库

1 StringBuffer类

String类是在所有项目开发之中一定会使用到的一个功能类,并且这个类拥有如下的几个特点:
(1)每一个字符串的常量都属于一个String类的匿名对象,并且不可以更改;
(2)String有两个常量池:静态常量池和运行时常量池。
(3)String类对象实例化建议使用直接赋值的形式完成,这样可以直接将对象保存在对象池之中以方便下次重用。

虽然String类很好用,但是如果认真去思考也会发现其最大的弊端:内容不允许修改,虽然大部分情况下都不会涉及到字符串内容的频繁修改,但是依然可能会存在有这样的情况,所以为了解决此问题,专门提供了一个StringBuffer类,可以提供字符串内容的修改处理。

StringBuffer并不像String类那样拥有两种对象实例化的方式,StringBuffer必须像普通类对象那样首先进行对象实例化,而后才可以调用方法执行处理,而这个时候可以考虑使用StringBuffer类中的如下方法:
(1)构造方法:public StringBuffer()
(2)构造方法:public StringBuffer​(String str)
(3)数据追加:public java.lang.AbstractStringBuilder append​(数据类型 obj),相当于字符串中的"+"操作
范例:观察String类对象引用传递与StringBuffer类对象引用传递对比

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		String str = "Hello ";
		StringBuffer sbf = new StringBuffer("Hello ");
		changeString(str);
		changeStringBuffer(sbf);
		System.out.println("String: " + str);
		System.out.println("StringBuffer: " + sbf);
	}
	
	public static void changeString(String temp) {
		temp += "World!";
	}
	
	public static void changeStringBuffer(StringBuffer sbf) {
		sbf.append("World!");
	}
}

/*
String: Hello 
StringBuffer: Hello World!
*/

实际上大部分情况下,很少会出现有字符串内容的改变,这种改变指的并不是针对静态常量池的改变

范例:分析一个问题

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		String strA = "lks loves hhy";
		String strB = "lks " + "loves " + "hhy";
		System.out.println("strA == strB: " + (strA==strB));  //true
	}
	
}
/*
strA == strB: true
*/

这个时候的strB对象的内容并不算是改变,或者更加严格的意义上来讲,对于现在的strB当程序编译之后会变为如下的形式。

StringBuffer strC = new StringBuffer("lks").append(" loves").append(" hhy");

所有的"+"再编译之后都变为了StringBuffer中的append()方法,并且来讲在程序之中StringBuffer与String类的对象之间本来就可以直接互相转换:
(1)String类对象变为StringBuffer可以依靠StringBuffer类的构造方法或者使用append()方法。
(2)所有的类对象都可以通过toString()方法将其变为Sting类型。

在StringBuffer类里面除了可以支持有字符串内容的修改之外,实际上也提供有一些String类所不具有的方法:
(1)插入数据:public StringBuffer insert​(int offset, 数据类型 b)
(2)删除指定范围的数据:public StringBuffer delete​(int start, int end)
(3)字符串内容反转:public StringBuffer reverse()

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		StringBuffer strC = new StringBuffer("lks").append(" loves").append(" hhy");
		System.out.println(strC.reverse());
	}
	
}
/*
yhh sevol skl
*/

实际上与StringBuffer类还有一个类似的功能类:StringBuilder类,这个类是在JDK 1.5的时候提供的,该类中提供的方法与StringBuffer功能相同,最大的区别在于StringBuffer类中的方法属于线程安全的,全部使用了synchronized关键字进行了标注,而StringBuilder属于非线程安全的。
面试题:请解释String、StringBuffer和StringBuilder的区别?
(1)String类是字符串的首选类型,其最大的特点是内容不允许修改。
(2)StringBuffer与StringBuilder类的内容允许修改;
(3)StringBuffer是在JDK 1.0的时候提供的,属于线程安全的操作,而StringBuilder是在JDK 1.5的之后提供的,属于非线程安全的操作。

2 CharSequence接口

CharSequence是一个描述字符串结构的接口,在这个接口里面一般可以发现有三种常见的子类:
(1)public final class StringBuffer extends Object implements Serializable, CharSequence
(2)public final class String extends Object implements Serializable, Comparable<String>, CharSequence
(3)public final class StringBuilder extends Object implements Serializable, CharSequence

现在只要有字符串就可以为CharSequence接口实例化。

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		CharSequence chse = "love you";
		System.out.println(chse);
	}
	
}
/*
love you
*/

CharSequence本身是一个接口,在该接口之中也定义有如下操作方法:
(1)获取指定索引字符:char charAt​(int index)
(2)获取字符串长度:int length()
(3)截取部分字符串:CharSequence subSequence​(int start, int end)
范例:字符串的截取

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		CharSequence chse = "love you";
		System.out.println(chse.subSequence(5, 8));
	}
	
}
/*
you
*/

以后只要看见了CharSequence描述的就是一个字符串。

3 AutoCloseable接口

AutoCloseable主要是日后进行资源开发的处理,以实现资源的自动关闭(释放资源),例如,在以后进行文件、网络、以及数据库开发的过程之中由于服务器的资源有限,所以使用之后一定要关闭资源,这样才可以被更多的使用者所使用。

下面为了更好地说明资源的问题,将通过一个消息的发送处理来完成。
范例:手工实现资源处理

package cn.victor.demo;

interface IMessage{
	public abstract void send();
}

class Message implements IMessage{
	private String msg;
	
	public Message() {}
	
	public Message(String msg) {
		this.msg = msg;
	}
	
	public void send() {
		System.out.println(this.msg);
	}
	
	public void open() {
		System.out.println("[Message Send]: begin send");
	}
	
	public void close() {
		System.out.println("[Message Close]: close send");
	}
}

public class JavaAPIDemo {
	public static void main(String[] args) {
		Message msg = new Message("love you");
		msg.open();
		msg.send();
		msg.close();
	}
	
}

/*
[Message Send]: begin send
love you
[Message Close]: close send
*/

此时有位设计师说了,既然所有的资源完成处理之后都必须进行关闭操作,能否实现一种自动关闭的功能?在这种要求下,推出了AutoCloseable接口,这个接口是在JDK 1.7的时候提供的,并且该接口只提供了一个方法:
(1)关闭方法:void close() throws Exception

要想实现自动关闭处理,除了要使用AutoCloseable之外,还需要结合有异常处理语句才可以正常调用。
范例:实现自动关闭处理

package cn.victor.demo;

interface IMessage extends AutoCloseable{
	public abstract void send();
}

class Message implements IMessage{
	private String msg;
	
	public Message() {}
	
	public Message(String msg) {
		this.msg = msg;
	}
	
	public void send() {
		System.out.println(this.msg);
	}
	
	public void open() {
		System.out.println("[Message Send]: begin send");
	}
	
	public void close() {
		System.out.println("[Message Close]: close send");
	}
}

public class JavaAPIDemo {
	public static void main(String[] args) {
		try(IMessage msg = new Message("love you")){
			((Message)msg).open();
			msg.send();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}

4 Runtime类

Runtime描述的是运行时的状态,也就是说在整个的JVM之中,Runtime是唯一一个与JVM运行状态有关的类,并且都会默认提供有一个该类的实例化对象。

由于在每一个JVM进程只允许提供一个Runtime类的对象,所以这个类的构造方法被默认私有化了,那么就证明该类使用的是单例设计模式,并且单例设计模式一定会提供有一个static方法获取本类实例。

由于Runtime类属于单例设计模式,如果要想获取实例化对象,那么就可以依靠类中的getRuntime()方法完成。

通过这个类中的public int availableProcessors()方法可以获取本机的CPU内核数:public int availableProcessors()
(1)获取实例化对象:
范例:获取Runtime类对象

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		Runtime run = Runtime.getRuntime();
		System.out.println(run.availableProcessors());  //获取可用进程数
	}
	
}

除了以上方法之外,在Runtime类里面还提供有以下四个重要的操作方法:
(1)获取最大可用内存空间:public long maxMemory(),默认的配置为本机系统内存的4分之一。
(2)获取可用内存空间:public long totalMemory(), 默认的配置为本机系统内存的64分之一。
(3)获取空闲内存空间:public long freeMemory()
(4)手工进行GC处理:public void gc()

范例:观察内存状态

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		Runtime run = Runtime.getRuntime();
		System.out.println(run.availableProcessors());
		System.out.println("[1]MaxMemory: " + run.maxMemory());
		System.out.println("[1]TotalMemory: " + run.totalMemory());
		System.out.println("[1]FreeMemory: " + run.freeMemory());
		String str = "lks";
		for(int i = 0; i < 50000; i++) {
			str += i;  //创建大量对象
		}
		System.out.println("**************************************");
		System.out.println("[2]MaxMemory: " + run.maxMemory());
		System.out.println("[2]TotalMemory: " + run.totalMemory());
		System.out.println("[2]FreeMemory: " + run.freeMemory());
		run.gc();   //手动回收对象
		System.out.println("**************************************");
		System.out.println("[3]MaxMemory: " + run.maxMemory());
		System.out.println("[3]TotalMemory: " + run.totalMemory());
		System.out.println("[3]FreeMemory: " + run.freeMemory());
	}
	
}

面试题:请问什么是GC?如何处理?
(1)GC(Garbage Collector)垃圾收集器,是可以由系统自动调用的垃圾释放功能,或者使用Runtime类中的gc()手工调用。

5 System类

System类是一直陪伴着我们学习的程序类,之前使用的系统输出采用的就是System类中的方法,除了这些方法之外,在System类中也定义有其他方法:
(1)数组拷贝:public static void arraycopy​(Object src, int srcPos, Object dest, int destPos, int length)
(2)获取当前的日期时间数值:public static long currentTimeMillis()
(3)进行垃圾回收:public static void gc()
范例:操作耗时的统计

package cn.victor.demo;

public class JavaAPIDemo {
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		String str = "lks";
		for(int i = 0; i < 50000; i++) {
			str += i;  //创建大量对象
		}
		long end = System.currentTimeMillis();
		System.out.println(end-start);
	}
	
}

在System类里面会发现也提供有一个gc()方法,但是这个gc()方法并不是重新定义的新方法,而是继续调用Runtime类中的gc()操作。

6 Cleaner类

Cleaner是在JDK 1.9之后提供的一个对象的清理操作,其主要的功能是进行finialize()方法的替代。在C++语言里面有两种特殊的函数:构造函数、析构函数(对象手工回收),在Java里面所有的垃圾空间都是通过GC自动回收的,所以很多情况下是不需要使用这类析构函数的,也正是因为如此,所以Java并没有提供这方面的支持。

但是Java本身依然提供了给用户收尾的操作,每一个实例化对象在回收之前至少给他一个喘息的机会,最初实现对象收尾处理的方法是Object类中提供的finialize()方法,这个方法的定义如下:

@Deprecated(since="9")
protected void finalize() throws Throwable

该替换指的是不建议继续使用这个方法了,而是说子类可以继续使用这个方法名称。但是这个方法最大的特点是抛出了一个Throwable异常类型,而这个异常类型分为两个子类型:Error、Exception,平常所处理的都是Exception。
范例:观察传统回收

package cn.victor.demo;

class Member {
	
	public Member() {
		System.out.println("[Object create]");
	}

	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("[recycle]");
		throw new Throwable("[NO!!!]");
	}
	
	
}

public class JavaAPIDemo {
	public static void main(String[] args) throws Throwable {
		Member mem = new Member();
		mem = null;   //成为垃圾
		System.gc();  //手动执行垃圾回收器
		System.out.println("[Everything normal]");
	}
	
}

但是从JDK 1.9开始,这一操作已经不建议使用了,而对于对象的回收与释放,从JDK 1.9开始建议开发者使用AutoCloseable或者使用Cleaner类进行回收处理。

package cn.victor.demo;

import java.lang.ref.Cleaner;
import java.lang.ref.Cleaner.Cleanable;

class Member implements Runnable{
	
	public Member() {
		System.out.println("[Object create]");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("[recycle]");
	}
}

class MemberCleaner implements AutoCloseable{

	private static final Cleaner cleaner = Cleaner.create();
	
	public Member member;
	public Cleaner.Cleanable cleanable;
	
	public MemberCleaner() {
		this.member = new Member();
		this.cleanable = cleaner.register(this, this.member);
	}
	
	@Override
	public void close() throws Exception {
		// TODO Auto-generated method stub
		this.cleanable.clean();
	}
	
}

public class JavaAPIDemo {
	public static void main(String[] args) throws Throwable {
		try(MemberCleaner mem = new MemberCleaner()){
			//your code
			System.out.println("[Everything normal]");
		}catch(Exception e) {
			
		}
	}
	
}

在新一代的清除回收处理的过程之中,更多的情况下考虑的是多线程的使用,即,为了防止有可能造成的延迟处理,所以许多对象回收前的处理都是单独通过一个线程完成的。

7 对象克隆

所谓对象克隆指的就是对象的复制,而且属于全新的复制。即使用已有对象内容创建一个新的对象,如果要想进行对象的克隆需要使用到Object类中提供的clone()方法。

所有的类都会继承Object父类,所以所有的类一定会有clone()方法,但是并不是所有的类都希望被克隆。所以如果要想实现对象克隆,那么对象所在的类需要实现一个接口Cloneable,此接口并没有任何的方法提供,是因为它描述的是一种能力。
范例:实现对象克隆

package cn.victor.demo;

class Member implements Cloneable{
	private String name;
	private int age;
	
	public Member() {}
	
	public Member(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public String toString() {
		return "name: " + this.name + "; age: " + this.age;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
	
	
	
}

public class JavaAPIDemo {
	public static void main(String[] args) throws Throwable {
		Member memA = new Member("lks", 23);
		Member memB = (Member)memA.clone(); //use clone
		Member memC = memA;  //don't use clone
		System.out.println(memA == memB);  //false
		System.out.println(memA == memC);  //true
	}
	
}

如果在开发之中不是非常特别的需求下,很少会出现有对象克隆的需求。

发布了87 篇原创文章 · 获赞 11 · 访问量 2999

猜你喜欢

转载自blog.csdn.net/weixin_43762330/article/details/104770047