进阶Java编程(5)基础类库
Java基础类库
1,StringBuffer类
String类是在所有项目开发之中一定会使用到的一个功能类,并且这个类拥有如下的特点:
①每一个字符串的常量都属于一个String类的匿名对象,并且不可更改;
②String有两个常量池:静态常量池、运行时常量池;
③String类对象实例化建议使用直接赋值的形式完成,这样可以直接将对象保存在对象池之中以方便下次重用。
虽然String类很好使用,但是如果认真去思考也会发现其最大的弊端:内容不允许修改,虽然大部分情况下都不会涉及到字符串内容的频繁修改,但是依然可能会存在有这样的情况,所以为了解决此问题,专门提供了一个StringBuffer类可以实现字符串内容的修改处理。
StringBuffer并不像String类那样拥有两种对象的实例化方式,StringBuffer必须像普通类对象那样首先进行对象实例化,而后才可以进行调用方法执行处理,而这个时候可以考虑StringBuffer类中的如下方法:
·构造方法:public StringBuffer()
·一参构造方法:public StringBuffer(String str)
·数据追加:public StringBuffer append(数据类型 变量),相当于字符串中的【+】操作;
·范例:观察String与StringBuffer对比
String类对象引用传递 |
StringBuffer类对象引用 |
public class Main { //内容没有发生修改!!! |
public class Main { //内容没有发生修改!!! |
Hello |
Hello World ! |
实际上大部分的情况下,很少会出现有字符串内容的改变,这种改变指的并不是针对于静态常量池的改变。
·范例:分析以下已有问题
1 public class Main { 2 public static void main(String[] args){ 3 String strA = "www.mldn.cn"; 4 String strB = "www."+"mldn."+"cn"; 5 System.out.println(strA==strB); 6 System.out.println(strA.equals(strB)); 7 } 8 }
这个时候的strB对象的内容并不算改变,或者更加严格意义上来讲,对于现在的strB当程序编译之后会变成如下的形式:
String |
String strB = "www."+"mldn."+"cn"; |
StringBuffer |
StringBuffer buf=new StringBuffer(); |
所有【+】在编译之后都变为了StringBuffer中的append()方法,并且来讲在程序之中StringBuffer与String类之间本来就可以直接互相转换。
①String类对象变为StringBuffer可以依靠StringBuffer类的构造方法或者使用append方法;
②所有类对象都可以通过toString()方法将其转变为String类型。
在StringBuffer类里面除了可以支持有字符串内容的修改之外,实际上也提供有了一些String类所不具备的方法。例如insert()追加数据,删除指定范围的数据delete(),字符串反转reverse()
实际上与StringBuffer类还有一个类似的功能类:StringBuilder类(JDK1.5),与StringBuffer类的功能基本相同。
最大的区别在于StringBuffer类中的方法属于线程安全的,全部使用了synchronized关键字进行标注,而StringBuilder类属于非线程安全的。
面试题:请解释String、StringBuffer、StringBuilder的区别? ①String类是字符串的首选类型,其最大的特定是内容不允许修改; ②StringBuffer类与StringBuilder类的内容允许修改; ③StringBuffer是在JDK1.0提供,属于线程安全的操作,而StringBuilder是在JDK1.5提供属于非线程安全操作。 |
2,CharSequence接口
CharSequence是一个描述字符串结构的接口,在这个接口里面一般发现有三种常用的子类:
String类 |
StringBuffer类 |
StringBuilder类 |
public final class String extends Object implements Serializable Comparable<String>,CharSequence |
public final class StringBuffer extends Object implements Serializable ,CharSequence |
public final class StringBr extends Object implements Serializable ,CharSequence |
现在只要有字符串就可以为CharSequence接口实例化。
·范例:
public class Main { public static void main(String[] args) throws CloneNotSupportedException{ CharSequence str="hello,Mufasa"; } }
获取指定索引字符 |
public char charAt(int index) |
获取字符串长度 |
public int length() |
截取部分字符串 |
public CharSequence subSequence(int start,int end) |
CharSequence本身是一个接口,在该接口之中也定义有如下操作方法:
·范例:字符串的截取
1 public class Main { 2 public static void main(String[] args) throws CloneNotSupportedException{ 3 CharSequence str="hello,Mufasa"; 4 CharSequence sub=str.subSequence(2,5); 5 System.out.println(sub); 6 } 7 }
3,AutoCloseable接口 CharSequence描述的就是一个字符串。
AutoCloseable主要是用于日后进行资源开发的处理上,以实现资源的自动关闭(释放资源),例如:以后进行文件、网络、数据库开发的过程之中由于服务器的资源有限,所以使用之后一定要关闭资源,这样才可以被更多的使用者所使用。
下面为了更好的说明资源的问题,将通过一个消息的发送处理来完成。
·范例:手工实现资源处理
1 interface IMessage{ 2 public void send(); 3 } 4 class NetMessage implements IMessage{ 5 private String msg; 6 public NetMessage(String msg) { 7 this.msg = msg; 8 } 9 public boolean open(){ 10 System.out.println("【OPEN】获取消息发送连接资源"); 11 return true; 12 } 13 @Override 14 public void send() { 15 System.out.println("【发送消息】"+this.msg); 16 } 17 public void close(){ 18 System.out.println("【CLOSE】关闭消息发送通道"); 19 } 20 } 21 public class Main { 22 public static void main(String[] args) throws CloneNotSupportedException{ 23 NetMessage netMessage=new NetMessage("Mufasa"); 24 25 //定义发送处理 26 if(netMessage.open()){//是否打开了连接 27 netMessage.send();//消息的发送 28 netMessage.close();//关闭连接 29 } 30 } 31 }
关闭方法:public void close() thrws Exception; 此时有位设计师说了,既然所有的资源完成处理之后都需要进行关闭操作,那么能否实现一种自动关闭的功能呢?再这样的要求下推出了AutoCloseable访问接口,这个接口是在JDK1.7的时候提供的,并且该接口只提供有一个方法:
要想实现自动关闭处理,除了要使用AutoCloseable之外,还要结合异常处理语句才可以正常调用。
·范例:实现自动关闭处理
1 interface IMessage extends AutoCloseable{ 2 public void send(); 3 } 4 class NetMessage implements IMessage{ 5 private String msg; 6 public NetMessage(String msg) { 7 this.msg = msg; 8 } 9 public boolean open(){ 10 System.out.println("【OPEN】获取消息发送连接资源"); 11 return true; 12 } 13 @Override 14 public void send() { 15 System.out.println("【发送消息】"+this.msg); 16 } 17 public void close() throws Exception{ 18 System.out.println("【CLOSE】关闭消息发送通道"); 19 } 20 } 21 public class Main { 22 public static void main(String[] args) throws Exception{ 23 try(IMessage nm=new NetMessage("Mufasa")){ 24 nm.send(); 25 }catch (Exception e){ 26 e.printStackTrace(); 27 } 28 } 29 }
4,Runtime类 以后的章节之中会接触到资源的关闭问题,往往都会见到AutoCloseable接口的使用。
Runtime描述的是运行时的状态,也就是说在整个的JVM重,Runtime类是唯一一个与JVM运行状态有关的类,并且都会默认提供有一个该类的实例化对象。
由于在每一个JVM进程里面只提供有一个Runtime类的对象,所以这个类的构造方法被默认私有化了,那么就证明该类使用的是单例设计模式,并且单例设计模式一定会提供有一个static方法获取本类实例。
由于Runtime类属于单例设计模式,如果要想获取实例化对象,那么就可以使用类中的getRuntime()方法完成。
获取实例化对象 |
public static Runtime getRuntime() |
·范例:获取Runtime对象
1 public class Main { 2 public static void main(String[] args) { 3 Runtime run=Runtime.getRuntime(); 4 System.out.println(run.availableProcessors());//8核心CPU 5 } 6 }
但是除了以上方法之外,在Runtime类里面还提供有以下四个重要的操作方法: 通过这个类中的【availableProcessors()】方法可以获取本机的CPU的内核数量。
获取最大可用内存空间 |
public long maxMemory() |
默认为本机内存的1/4 |
获取可用内存空间 |
public long totalMemory() |
默认为本机内存的1/64 |
获取空闲内存空间 |
public long freeMemory() |
|
手动GC处理 |
public void gc() |
面试题:什么是GC?如何处理?
答:GC(garbage collector)垃圾收集器,是可以由系统自动调用的垃圾释放功能,或者使用Runtime类中的GC手工调用。
5,System类
System类是一直陪伴着我们学习的程序类【System.out.println()】
数组拷贝 |
public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length) |
获取当前日期时间 |
public static long currentTimeMillis() |
进行垃圾回收 |
public static void gc() |
·范例:操作耗时的统计
1 public class Main { 2 public static void main(String[] args) { 3 long start=System.currentTimeMillis(); 4 String str=""; 5 for(int x=0;x<30000;x++){ 6 str+=x; 7 } 8 long end = System.currentTimeMillis(); 9 System.out.println("操作耗时:"+(end-start)); 10 } 11 }
操作耗时:602
在System类中也提供一个【gc()】方法,但是这个gc()方法并不是重新定义的新方法,而是继续执行【Runtime.getRuntime.gc()】。
6,Cleaner类
Cleaner是在JDK1.9之后提供的对象清理操作,其主要功能是进行【finialize()】方法的替代。在C++语言里面有两种特殊的函数:①构造函数(对象初始化);②析构函数(对象手工回收),在Java里面所有的垃圾空间都是通过GC进行自动回收的,所以很多情况下是不需要使用这类析构函数的,也正是因为如此,所以Java并没有提供这一方面的支持。
但是Java本身依然提供了给用户收尾的操作,每一个实例化对象在回收之前至少给它一个喘息的机会,最初提供对象收尾处理的方法是Object类中所提供的【finalize】方法,这个方法的定义如下:
1 @Deprecated(since="9") 2 protected void finalize() throws Throwable
·范例:观察传统回收 该替换指的是不建议继续使用这个方法了,而是子类可以继续使用这个方法名称。这个方法最大的特征是Throwable异常类型,而这个异常类型分为:Error、Exception,平常所处理的都是Exception。
1 class Member{ 2 public Member(){ 3 System.out.println("【构造】实例化对象诞生"); 4 } 5 @Override 6 protected void finalize() throws Throwable { 7 System.out.println("【回收】实例化对象收尾"); 8 throw new Exception("还想继续存在"); 9 } 10 } 11 public class Main { 12 public static void main(String[] args) throws Exception{ 13 Member member=new Member(); 14 member=null; 15 System.out.println("对象失去索引称为垃圾"); 16 Runtime.getRuntime().gc(); 17 System.out.println("手动进行GC处理"); 18 } 19 }
1 import java.lang.ref.Cleaner; 2 class Member implements Runnable{ 3 public Member(){ 4 System.out.println("【构造】实例化对象诞生"); 5 } 6 @Override 7 public void run() {//执行清除最终执行的是此操作 8 System.out.println("【回收】实例化对象收尾"); 9 } 10 } 11 class MemberCleaning implements AutoCloseable{//实现清除的处理 12 private static final Cleaner CLEANER=Cleaner.create(); 13 //创建一个清除处理 14 private Member member; 15 private Cleaner.Cleanable cleanable; 16 public MemberCleaning(){ 17 this.member=new Member();//创建新对象 18 this.cleanable=this.CLEANER.register(this,this.member); 19 //注册使用的对象 20 } 21 @Override 22 public void close() throws Exception { 23 this.cleanable.clean();//启动多线程 24 } 25 } 26 public class Main { 27 public static void main(String[] args) throws Exception{ 28 try(MemberCleaning mc=new MemberCleaning()) { 29 ; 30 }catch (Exception e){ 31 e.printStackTrace(); 32 } 33 } 34 }
在新一代的清除回收处理过程之中,更多情况下考虑的是多线程的使用,即:为了防止有可能造成的延迟处理,所以许多对象回收前的处理都是单独通过一个线程完成的。 但是从JDK1.9开始,这个操作已经不建议使用了,而对于对象的回收释放。从JDK1.9开始建议开发者使用AutoCloseable或者使用java.lang.ref.Cleaner类进行回收处理(Cleaner也支持有AutoCloseable处理)。
7,对象与克隆
所谓的对象克隆指的就是对象的复制,而且属于全新的复制。即:使用已有对象创建新对象,使用Object类中提供的clone()方法。
所有的类都会继承Object父类,所以所有的类都一定会有clone()方法,但是并不是所有的类都希望被克隆。所以如果想要实现对象克隆,那么对象所在的类需要实现一个Cloneable接口,此接口没有任何方法提供,是因为它描述的是一种能力。
备注:接口的作用①标准;②能力(接口没有方法是一种能力标识的接口)
·范例:实现对象克隆
1 class Member implements Cloneable{//clone是一个protected权限方法 2 private String name; 3 private int age; 4 public Member(String name, int age) { 5 this.name = name; 6 this.age = age; 7 } 8 @Override 9 public String toString() { 10 return "【"+super.toString()+"】name="+this.name+",age="+this.age; 11 } 12 @Override 13 public Object clone() throws CloneNotSupportedException { 14 return super.clone();//覆写clone方法,调用父类方法,更改权限 15 } 16 } 17 public class Main { 18 public static void main(String[] args) throws CloneNotSupportedException{ 19 Member memberA=new Member("万雨",25); 20 Member memberB=(Member) memberA.clone(); 21 System.out.println(memberA.toString()); 22 System.out.println(memberB.toString()); 23 } 24 }
如果在开发之中不是非常特别的需求下,很少会出现对象克隆的需求。