浅析Java中的System类、Object类和StringBuilder类

104 阅读5分钟

文章目录


1.System类

java.lang.System类提供了大量的静态方法,可以获取系统相关的信息或执行系统操作,常用方法有:

  • static long currentTimeMillis(): 返回以毫秒为单位的当前时间

  • static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length): 将数组中指定的数据拷贝到另一个数组中

    • src:源数组
    • srcPos:源数组的起始位置
    • dest:目标数组
    • destPos:目标数组的起始位置
    • length:要复制的内容的长度
import java.util.Arrays;

public class SystemMain {
    public static void main(String[] args) {
        long time = System.currentTimeMillis();
        System.out.println(time);  // 1587609427487

        int[] src = new int[]{1,2,3,4};
        int[] dest = new int[]{5,6,7,8};
        System.arraycopy(src, 0, dest, 0, 3);
        System.out.println(Arrays.toString(dest));  // [1, 2, 3, 8]
    }
}

2.StringBuilder类

Java中的字符串的底层实现为一个被final关键字修饰的字节数组,因此,一旦创建就不能改变。如果直接使用+进行字符串的拼接,那么内存会保存拼接的中间结果,这样的方法会占用较多的内存,效率低下。

StringBuilder是字符串缓冲区,它可以提高字符串的操作效率,它的底层实现也是一个数组,但是并没有被final关键字修饰,因此可以改变长度。StringBuilder在内存中始终是一个数组,占用空间少,效率高,如果超出了StringBuilder的容量会自动进行扩容。

  • 构造方法:

    • StringBuilder() :构造一个不带任何字符串的字符串生成器,其实容量为16个字符
    • StringBuilder(String str) :构造一个字符串生成器,并初始化为指定的字符串内容
    public class StringBuilderMain {
        public static void main(String[] args) {
            StringBuilder sb = new StringBuilder();
            System.out.println(sb); // ""
    
            StringBuilder sb1 = new StringBuilder("Forlogen");
            System.out.println(sb1); // Forlgoen
        }
    }
    
  • StringBuilder append(…) :添加任意类型数据的字符串形式,并返回当前对象自身

    public class StringBuilderMain {
        public static void main(String[] args) {
            StringBuilder sb = new StringBuilder();
            System.out.println(sb); // ""
    
            sb.append("Forlogen");
            sb.append(24);
            System.out.println(sb);  // Forlogenkobe24
        }
    }
    
  • StringBuilder和String之间的相互转换:

    • StringBuilder -> String:使用StringBuilder的toString方法
    • String -> StringBuilder:使用上述的构造方法
    public class StringBuilderMain {
        public static void main(String[] args) {
            StringBuilder sb = new StringBuilder("Forlogen");
            System.out.println(sb); // Forlgoen
            System.out.println(sb.toString());  // Forlogen
    
        }
    }
    
  • int length() :获取字符串的长度

  • StringBuilder insert() :将内容插入到StringBuilder对象的指定位置

    public class StringBuilderMain {
        public static void main(String[] args) {
            StringBuilder sb = new StringBuilder("Forlogen");
            System.out.println(sb.length());  // 8
            System.out.println(sb.insert(3, "KOBE")); // ForKOBElogen
    
        }
    }
    

3.Object类

java.lang.Object类所有类的根类,每个类都将Object作为超类,所有类的对象,包括数组都实现这个类的方法。常用的方法:

  • String toString() :返回对象的字符串表示。假设Person定义如下所示,它默认继承了Object这个超类:

    public class Person {
        private String name;
        private int age;
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = 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;
        }
    }
    

    如果我们直接通过对象调用toString方法,最后得到的对象的地址值,本质上和直接输出对象自己没有区别。

    public class ObjectMain {
        public static void main(String[] args) {
            Person person = new Person("Forlogen", 18);
            System.out.println(person); // Object.Person@1b6d3586
    
            // 直接打印对象的名字本质上就是调用了对象的toString方法
            String s = person.toString();
            System.out.println(s); // Object.Person@1b6d3586
    

    所以,为了更加使toString符合具体的应用场景,我们需要重写toString方法,在IDEA中使用自动生成得到:

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    

    如上所示,通过重写方法最后得到的是类的成员变量信息而不是对象的地址值。那么,我们再看一些Java内置的其他类是否也重写了toString方法:

    Random r = new Random();
    System.out.println(r);  // java.util.Random@74a14482
    

    从输出结果可以看出,Random并没有重写toString方法。

    // 重写了toString
    Scanner sc = new Scanner(System.in);
    System.out.println(sc);  // java.util.Scanner[delimiters=\p{javaWhitespace}+][position=0] ...
    

    从输出结果可以看出,Scanner类重写了toString方法,我们通过源码看一下具体的重写过程:

        /**
         * <p>Returns the string representation of this <code>Scanner</code>. The
         * string representation of a <code>Scanner</code> contains information
         * that may be useful for debugging. The exact format is unspecified.
         *
         * @return  The string representation of this scanner
         */
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("java.util.Scanner");
            sb.append("[delimiters=" + delimPattern + "]");
            sb.append("[position=" + position + "]");
            sb.append("[match valid=" + matchValid + "]");
            sb.append("[need input=" + needInput + "]");
            sb.append("[source closed=" + sourceClosed + "]");
            sb.append("[skipped=" + skipped + "]");
            sb.append("[group separator=" + groupSeparator + "]");
            sb.append("[decimal separator=" + decimalSeparator + "]");
            sb.append("[positive prefix=" + positivePrefix + "]");
            sb.append("[negative prefix=" + negativePrefix + "]");
            sb.append("[positive suffix=" + positiveSuffix + "]");
            sb.append("[negative suffix=" + negativeSuffix + "]");
            sb.append("[NaN string=" + nanString + "]");
            sb.append("[infinity string=" + infinityString + "]");
            return sb.toString();
        }
    

    重写过程中使用了StringBuilder来保存输出的结果,最后使用StringBuilder中的toString方法输出字符串。

    ArrayList<String> list = new ArrayList<>();
    list.add("Forlogen");
    list.add("kobe");
    System.out.println(list);  // [Forlogen, kobe]
    

    可以看到ArrayList也重写了toString方法,但是在ArrayList的实现中并没有自己重写toString,而ArrayList继承了java.util包下的AbstractCollention<E>类,该类中进行了toString方法的重写。

    	/**
         * Returns a string representation of this collection.  The string
         * representation consists of a list of the collection's elements in the
         * order they are returned by its iterator, enclosed in square brackets
         * (<tt>"[]"</tt>).  Adjacent elements are separated by the characters
         * <tt>", "</tt> (comma and space).  Elements are converted to strings as
         * by {@link String#valueOf(Object)}.
         *
         * @return a string representation of this collection
         */
        public String toString() {
            Iterator<E> it = iterator();
            if (! it.hasNext())
                return "[]";
    
            StringBuilder sb = new StringBuilder();
            sb.append('[');
            for (;;) {
                E e = it.next();
                sb.append(e == this ? "(this Collection)" : e);
                if (! it.hasNext())
                    return sb.append(']').toString();
                sb.append(',').append(' ');
            }
        }
    

    重写的过程和Scanner是类似的。

  • boolean equals(Object obj): 指示其他某个对象是否和此对象相等,Object类中的equals方法实现代码为:

    public boolean equals(Object obj) {
    	return (this == obj);
    }
    

    它实现了本身和传入的对象的对比。我们知道 == 对于引用类型来说,进行的是地址值的比较,所以如果不是两个完全相同的对象,那么得到的就是false。

    public class ObjectEquals {
        public static void main(String[] args) {
            Person person = new Person("Forlogen", 18);
            Person person1 = new Person("kobe", 24);
            System.out.println(person.equals(person1));  // false
        }
    }
    

    同样为了具体的应用场景,通常需要重写equals方法:

    @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Person)) return false;
            Person person = (Person) o;
            return getAge() == person.getAge() &&
                    Objects.equals(getName(), person.getName());
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(getName(), getAge());
        }
    

    Java内置的其它类中很多也重写了equals方法,如String中就进行了equals方法:

    /**
         * Compares this string to the specified object.  The result is {@code
         * true} if and only if the argument is not {@code null} and is a {@code
         * String} object that represents the same sequence of characters as this
         * object.
         *
         * @param  anObject
         *         The object to compare this {@code String} against
         *
         * @return  {@code true} if the given object represents a {@code String}
         *          equivalent to this string, {@code false} otherwise
         *
         * @see  #compareTo(String)
         * @see  #equalsIgnoreCase(String)
         */
        public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String)anObject;
                int n = value.length;
                if (n == anotherString.value.length) {
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    while (n-- != 0) {
                        if (v1[i] != v2[i])
                            return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
        }
    

    通过对象直接调用

    public class ObjectEquals {
        public static void main(String[] args) {
            String s1 = "abc";
            String s2 = "abc";
    
            System.out.println(s1.equals(s2)); // true
        }
    }
    

    通常为了避免使用equals方法出现空指针异常,可以使用Objects的equals方法:

    public class ObjectEquals {
        public static void main(String[] args) {
            String s1 = null;
            String s2 = "abc";
    
            System.out.println(s1.equals(s2)); // 会出现空指针异常
            System.out.println(Objects.equals(s1, s2));  // false
        }
    }
    

    java中的Object类

    java.lang包【Object类】