Java基础类库

内容学习于:edu.aliyun.com


1. StringBuffer类

  String类是在所有项目开发之中一定会使用到的一个功能类,并且这个类拥有如下的特点:

  • 每一个字符串的常量都属于一个String类的匿名对象,并且不可更改;
  • String有两个常量池:静态常量池、运行时常量池;
  • String 类对象实例化建议使用直接赋值的形式完成,这样可以直接将对象保存在对象池之中以方便下次重用:
      虽然String类很好使用,但是如果认真去思考也会发现其最大的弊端:内容不允许修改,虽然大部分的情况下都不会涉及到字符串内容的频繁修改,但是依然可能会存在有这样的情况,所以为了解决此问题,专门提供有一个StringBuffer类可以实现字符串内容的修改处理。
      StringBuffer并不像String类那样拥有两种对象实例化方式,StringBuffer必须像普通类对象那样首先进行对象实例化,而后才可以调用方法执行处理,而这个时候可以考虑使用StringBuffer类中的如下方法:
  • 构造方法:public StringBuffer()
  • 构造方法:public StringBuffer(String str),可以接收字符串进行初始化
  • 追加方法:public StringBuffer append(数据类型 变量),相当于字符串的+操作

String类引用传递代码:

public class JavaAPIDemo {
    public static void main(String[] args) {
        String str = "Hello";
        change(str);
        System.out.println(str);
    }

    public static void change(String str) { 
        str += "World!!"; //内容并没有发生改变
    }
}

结果:

Hello

StringBuffer的引用传递代码:

public class JavaAPIDemo {
    public static void main(String[] args) {
        StringBuffer buf = new StringBuffer("Hello ");
        change(buf);
        System.out.println(buf);
    }

    public static void change(StringBuffer str) {
        str.append("World!!");
    }
}

结果:

Hello World!!

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

分析下列代码:

public class JavaAPIDemo {
    public static void main(String[] args) {
        String strA = "www.mldn.cn";
        String strB = "www" + ".mldn" + ".cn";
        System.out.println(strA == strB);
    }
}

结果:

true

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

  • StringBuffer strB = new StringBuffer();→strB.append(“www”).append(".mldn").append(".cn");

  所有的“+”在编译之后都变为了StringBuffer 中的append()方法,并且在程序之中StringBuffer 与 String类之间本来就可以直接互相转换:

  • String类对象变为StringBuffer可以依靠StringBuffer类的构造方法或者使用append()方法;
    所有类对象都可以通过toString()方法将其变为String类型。

观察下列代码:

public class JavaAPIDemo {
    public static void main(String[] args) {
        String strA = "www.mldn.cn";
        StringBuffer strB = new StringBuffer();
        strB.append("www").append(".mldn").append(".cn");
        System.out.println(strA.equals(strB.toString()));
        System.out.println(strA == strB.toString());
    }
}

结果:

true
false

  Stringbuffer是动态字符串数组,append( )是往动态字符串数组添加,跟“xxxx”+“yyyy”相当‘+’号。
  跟String不同的是Stringbuffer是放一起的,String1+String2和Stringbuffer1.append(“yyyy”)虽然打印效果一样,但在内存中表示却不一样,String1+String2 存在于不同的两个地址内存,Stringbuffer1.append(Stringbuffer2)放在一起。

  String类中不具备的方法:

  • a.插入数据:public StringBuffer insert(int offset, 数据类型 变量)

插入操作代码:

public class JavaAPIDemo {
    public static void main(String[] args) {
        StringBuffer strB = new StringBuffer();
        strB.append(".cn").insert(0, "www.").insert(4, "mldn");
        System.out.println(strB);
    }
}

结果:

www.mldn.cn

  • b.删除指定范围内的数据:public StringBuffer delete(int start, int end)

删除指定范围代码:

public class JavaAPIDemo {
    public static void main(String[] args) {
        StringBuffer strB = new StringBuffer();
        strB.append("Hello World !").delete(6,12);
        System.out.println(strB);
    }
}

结果:

Hello !

  • c.字符串翻转:public StringBuffer reverse()

翻转代码:

public class JavaAPIDemo {
    public static void main(String[] args) {
        StringBuffer strB = new StringBuffer();
        strB.append("Hello World !").reverse();
        System.out.println(strB);
    }
}

结果:

! dlroW olleH

  实际上与StringBuffer类还有一个类似的功能类: StringBuilder 类,这个类是在JDK 1.5 的时候提供的,该类中提供的方法与StringBuffer功能相同,最大的区别在于StringBuffer 类中的方法属于线程安全的,全部使用了synchronized 关键字进行标注,而StringBuilder类属于非线程安全的。

  面试题:请解释String、StringBuffer、 StringBuilder 的区别?

String类是字符串的首选类型,其最大的特点是内容不允许修改;
StringBuffer与StringBuilder 类的内容允许修改;
StringBuffer 是在JDK 1.0 的时候提供的,属于线程安全的操作,而StringBuilder是在JDK 1.5 之后提供的,属于非线程安全的操作。

2. CharSequence接口

  CharSequence是一个描述字符串结构的接口,在这个接口里面一般发现有三种常用子类:

String类StringBuffer类StringBuilder类
public final class Stringextends Object implements Serializable, Comparable, CharSequencepublic final class StringBuffer extends Object implements Serializable, CharSequencepublic final class StringBuilder extends Object implements Serializable, CharSequence

  如下图所示:在这里插入图片描述

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

代码:

public class JavaAPIDemo {
    public static void main(String[] args) {
        CharSequence sequence = "www.mldn.cn";//子类实例向父接口转型
        System.out.println(sequence);
    }
}

结果:

www.mldn.cn

  CharSequence本身是一个接口,在该接口之中也定义有如下操作方法:

  • 获取指定字符:char charAt(int index)
  • 获取字符串的长度:int length()
  • 截取部分字符串:CharSequence subSequence(int start,int end)

字符串截取代码:

public class JavaAPIDemo {
    public static void main(String[] args) {
        CharSequence sequence = "www.mldn.cn";
        CharSequence sub = sequence.subSequence(4, 8);
        System.out.println(sub);
    }
}

结果:

mldn

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

3. AutoCloseable接口

  AutoCloseable主要是用于日后进行资源开发的处理上,以实现资源的自动关闭(释放资源),例如:在以后进行文件、网络、数据库开发过程之中由于服务器的资源有限,所以使用之后一定要关闭资源,这样才可以被更多的使用者所使用。
  下面为了更好的说明资源的问题,将通过一个消息的发送处理来完成。

手工实现资源处理:

interface IMessage {
    void send();//消息发送
}

class NetMessage implements IMessage {//实现消息处理的机制
    private String msg;

    public NetMessage(String msg) {
        this.msg = msg;
    }

    public boolean open() {//获取连接资源
        System.out.println("【open】获取消息发送的资源");
        return true;
    }


    public void close() {
        System.out.println("【close】关闭消息发送的资源");
    }

    @Override
    public void send() {
        if (this.open())//是否打开了连接
            System.out.println("【发送消息】" + this.msg);
    }
}

public class JavaAPIDemo {
    public static void main(String[] args) {
        NetMessage nm = new NetMessage("www.mldn.cn");//定义要发送的消息
        nm.send();//消息发送
        nm.close();//关闭连接
    }
}

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

  • 关闭方法:void close() throws Exception

  如下图所示:在这里插入图片描述

实现自动关闭操作代码:

interface IMessage extends AutoCloseable {//继承AutoCloseable类
    void send();//消息发送
}

class NetMessage implements IMessage {//实现消息处理的机制
    private String msg;

    public NetMessage(String msg) {
        this.msg = msg;
    }

    public boolean open() {//获取连接资源
        System.out.println("【open】获取消息发送的资源");
        return true;
    }

    @Override
    public void close() throws Exception {
        System.out.println("【close】关闭消息发送的资源");
    }

    @Override
    public void send() {
        if (this.open())//是否打开了连接
            System.out.println("【发送消息】" + this.msg);
    }
}

public class JavaAPIDemo {
    public static void main(String[] args) {
        try (IMessage nm = new NetMessage("www.mldn.cn")) {//需要通过try...catch实现自动关闭
            nm.send();//消息发送
        } catch (Exception e) {

        }
    }
}

结果:

【open】获取消息发送的资源
【发送消息】www.mldn.cn
【close】关闭消息发送的资源

4. Runtime类

  Runtime描述的是运行时的状态,也就是说在整个的JVM之中,Runtime 类是唯一个与JVM运行状态有关的类,并且都会默认提供有一个该类的实例化对象。
  由于在最每一个JVM进程里面只允许提供有一个Runtime类的对象,所以这个类的构造方法被默认私有化了,那么就证明该类使用的是单例设计模式,并且单例设计模式一定会提供有一个static方法获取本类实例。

  • 获取实例化对象:public static Runtime getRuntime()

  如下图所示:在这里插入图片描述

  通过这个类中的availableProcessors()方法可以获取本机的CPU内核数: public int availableProcessors();

获取Runtime类对象代码:

public class JavaAPIDemo {
    public static void main(String[] args) {
        Runtime run = Runtime.getRuntime();//获取实例化对象
        System.out.println(run.availableProcessors());//获取CPU的内核数
    }
}

结果:

8

  但是除了以上的方法之外,在Runtime类里面还提供有以下四个重要的操作方法:

  • 获取最大可用内存空间:public long maxMemory(),默认配置为系统内存的四分之一
  • 获取可用内存空间:public long totalMemory(),默认配置为系统内存的64分之一
  • 获取空闲内存空间:public long freeMemory()
  • 手动进行GC处理:public void gc()

代码:

public class JavaAPIDemo {
    public static void main(String[] args) throws InterruptedException {
        Runtime run = Runtime.getRuntime();//获取实例化对象
        System.out.println("【1】MAX_MEMORY:" + run.maxMemory());
        System.out.println("【1】TOTAL_MEMORY:" + run.totalMemory());
        System.out.println("【1】FREE_MEMORY:" + run.freeMemory());
        String str = "";
        for (int i = 0; i < 30000; i++) {
            str += i;
        }
        System.out.println("【2】MAX_MEMORY:" + run.maxMemory());
        System.out.println("【2】TOTAL_MEMORY:" + run.totalMemory());
        System.out.println("【2】FREE_MEMORY:" + run.freeMemory());
        Thread.sleep(200);
        run.gc();

        System.out.println("【3】MAX_MEMORY:" + run.maxMemory());
        System.out.println("【3】TOTAL_MEMORY:" + run.totalMemory());
        System.out.println("【3】FREE_MEMORY:" + run.freeMemory());
    }
}

结果:

【1】MAX_MEMORY:2116026368
【1】TOTAL_MEMORY:134217728
【1】FREE_MEMORY:132158872
【2】MAX_MEMORY:2116026368
【2】TOTAL_MEMORY:398458880
【2】FREE_MEMORY:387975832
【3】MAX_MEMORY:2116026368
【3】TOTAL_MEMORY:10485760
【3】FREE_MEMORY:9182664

  面试题:请问什么是GC?如何处理?

GC (Garbage Collector)垃圾收集器,是可以由系统自动调用的垃圾释放功能,或者使用Runtime类中的gc0手工调用。

5. System类

  System类是一直陪伴着我们学习的程序类,之前使用的系统输出采用的就是System类中的方法,而后在System类 里面也定义有一些其它的处理方法: .

  • 数组拷贝:public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
  • 获取当前日期的数值:public static long currentTimeMillis()
  • 进行垃圾回收:public static void gc()

计算程序耗时时间代码:

public class JavaAPIDemo {
    public static void main(String[] args) throws InterruptedException {
        Runtime run = Runtime.getRuntime();//获取实例化对象
        long start = System.currentTimeMillis();
        String str = "";
        for (int i = 0; i < 30000; i++) {
            str += i;
        }
        long end = System.currentTimeMillis();
        System.out.println("该程序耗时:" + (end - start));//计算系统耗时
    }
}

结果:

该程序耗时:456

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

6. Cleaner类(1.9之后)

  Cleaner是在JDK 1.9 之后提供的一个对象清理操作,其主要的功能是进行finialize()方法的替代。在c++语言里面有两种特殊的函数:构造函数、析构函数(对象手工回收),在Java里面所有的垃圾空间都是通过GC自动回收的,所以很多情况下是不需要使用这类析构函数的,也正是因为如此,所以 Java并没有提供这方面支持。
  但是Java本身依然提供了给用户收尾的操作,每一个实例化对象在回收之前至少给它一个喘息的机会,最初实现对象收尾处理的方法是Object类中所提供的finalize()方法,这个方法的定义如下:

  对象回收方法:

  • @Deprecated(since=“9”)
    protected void finalize()throws Throwable

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

finalize的调用代码:

class Member {
    public Member() {
        System.out.println("在一个风雨交加的夜晚,出生了一个婴儿");
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("人古有一死");
        throw new Exception("我不想死!!!!");//即使抛出了异常,也无法避免该对象的消亡
    }
}

public class JavaAPIDemo {
    public static void main(String[] args) throws InterruptedException {
        Member member = new Member();//对象诞生
        member = null;//该对象挂掉
        System.gc();//手动调用垃圾处理
        System.out.println("太阳照常升起");
    }
}

结果:

在一个风雨交加的夜晚,出生了一个婴儿
太阳照常升起
人古有一死

  但是从JDK 1.9开始,这一操作已经不建议使用了,而对于对象回收释放。从JDK 1.9开始建议开发者使用AutoCloseable或者使用java.lang.ref.Cleaner类进行回收处理(Cleaner 也支持有AutoCloseable 处理)。

新版的对象清除代码:

class Member implements Runnable {
    public Member() {
        System.out.println("【构造】在一个风雨交加的夜晚,出生了一个婴儿");
    }

    @Override
    public void run() {//执行清除的时候执行的是此操作
        System.out.println("【回收】人古有一死");
    }
}

class MemberCleaning implements AutoCloseable {
    private static final Cleaner CLEANER = Cleaner.create();//创建清除处理
    private Member member;
    private Cleaner.Cleanable cleanable;

    public MemberCleaning() {
        this.member = new Member();//创建新对象
        this.cleanable = this.CLEANER.register(this, this.member);//注册使用的对象
    }

    @Override
    public void close() throws Exception {
        cleanable.clean();//启动多线程
    }
}

public class JavaAPIDemo {
    public static void main(String[] args) throws InterruptedException {
        try (MemberCleaning mc = new MemberCleaning()) {
            //在这里可以执行一些代码操作
        } catch (Exception e) {

        }
    }
}

结果:

【构造】在一个风雨交加的夜晚,出生了一个婴儿
【回收】人古有一死

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

  面试题:请解释final、finally、 finalize 的区别? (局限于 JDK 1.9 以前)

final是一个关键字主要定义不能够被继承的父类、不能够被覆写的方法、常量;
finally是一个关键字主要用于异常处理上,不管是否处理异常都要执行finally中的代码;
finliaze()是 Object类中所提供的一个方法,主要是在对象回收前进行收尾处理(一般不考虑),并且在JDK 1.9之后该方法已经默认被废除了,可以使用Cleaner使用多线程的模式来进行回收处理。

finally代码:

public class JavaAPIDemo {
    public static void main(String[] args) throws ParseException {
        System.out.println(get());
    }

    public static int get() {
        try {
            return 100;
        } finally {
            System.out.println("我还是执行了");
        }
    }
}

结果:

我还是执行了
100

  那怕是在方法返回处理的过程之中,finally 也一定要在返回前执行。

7. 对象克隆

  所谓的对象克隆指的就是对象的复制,而且属于全新的复制。即:使用已有对象内容创建一个新的对象,如果要想进行对象克隆需要使用到Object类中提供的clone()方法: protected Object clone() throws CloneNotSupportedException;
  所有的类都会继承Object父类,所以所有的类都一定会有clone()方法,但是并不是所有的类都希望被克隆。所以如果要想实现对象克隆,那么对象所在的类需要实现一个Cloneable接口,此接口并没有任何的方法提供,是因为它描述的是一种能力。

实现对象克隆代码:

class Member implements Cloneable {
    private String name;
    private int age;

    public Member(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "【" + super.toString() + "】" + "、name=" + this.name + "、age=" + this.age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();//想要实现克隆,一定要覆写clone方法
    }
}


public class JavaAPIDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Member memberA = new Member("团子", 30);
        Member memberB = (Member) memberA.clone();
        System.out.println(memberA);
        System.out.println(memberB);
    }
}

结果:

【com.xzzz.e20200114_chapter1.Member@5674cd4d】、name=团子、age=30
【com.xzzz.e20200114_chapter1.Member@7ba4f24f】、name=团子、age=30

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值