Java中所有类都直接或间接继承Object类,而String类是Java中最常用的类之一,总结一下这两个类的一些常用方法。
Object类的常用方法
- clone()
clone方法可以实现Java对象的复制,然而如果被复制的对象中有引用类型的成员,该方法只是将对应成员变量设置为同样的引用对象,原对象和复制出来的对象的该成员变量是同一个引用变量,修改其中之一会影响另外一个对象,这种复制被称为浅复制。
一个类要调用Object的clone方法,需要实现Cloneable接口。
package model;
public class Student implements Cloneable {
public String name;
public int age;
public Teacher teacher;
public Student(String name, int age, Teacher teacher) {
this.name = name;
this.age = age;
this.teacher = teacher;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package model;
public class Teacher {
public String name;
public int age;
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
}
import model.Student;
import model.Teacher;
public class Main {
public static void main(String[] args) {
Teacher zhang = new Teacher("Zhang", 40);
Student liu = new Student("Liu", 20, zhang);
System.out.println("复制前" + liu.teacher.name);
try {
Student wang = (Student) liu.clone();
wang.teacher.name = "Li";
System.out.println("复制后" + liu.teacher.name);
System.out.println("复制后" + wang.teacher.name);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
输出结果如下,用clone方法将liu复制给wang,修改wang的teacher属性,liu的teacher也跟着变化了。
复制前Zhang
复制后Li
复制后Li
要实现深复制,需要修改Student类中引用类型成员,让其也实现clone方法,同时在Student的clone方法中调用。
将Student和Teacher类修改为
package model;
public class Student implements Cloneable {
public String name;
public int age;
public Teacher teacher;
public Student(String name, int age, Teacher teacher) {
this.name = name;
this.age = age;
this.teacher = teacher;
}
@Override
public Object clone() throws CloneNotSupportedException {
Student stu = (Student) super.clone();
stu.teacher = (Teacher) teacher.clone();
return stu;
}
}
package model;
public class Teacher implements Cloneable {
public String name;
public int age;
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
输出结果
复制前Zhang
复制后Zhang
复制后Li
- hashCode()
hashCode()是Object的方法,可以获取对象的散列码,散列码是根据对象的内容计算出来的一个int型整数,散列码用于一些数据结构的存储中,可以优化数据存储结构,一般用在hashmap,hashset中,确定数据的存储位置。
要注意的有三点:- 两个相等的对象的hashCode()必须是相等的。
- 如果两个对象的hashCode()相等,这两个对象不一定相等(发生了哈希碰撞)。
- hashCode()的返回值并不能说是对象的存储位置,因为在发生了哈希碰撞的情况下会作进一步处理。
- equals()
equals()是Object的方法,用于判断this对象与传入参数是否相等,返回boolean类型值true或false。源码如下,可以看出来默认的equals()是用==判断两个对象是否相等,即判断是否是同一个引用对象,想要用equals()判断两个对象的值是否相等,需要重写该方法。
public boolean equals(Object obj){
return (this==obj);
}
Java一些内置的引用类型都重写了equals方法,而当我们给自定义的数据类型重写equals方法时,需要注意以下几点:
1. 自反性(reflexive),对于任意不为 null 的引用值 x,x.equals(x) 一定是 true。
2. 对称性(symmetric),对于任意不为 null 的引用值 x 和 y ,当且仅当x.equals(y)是 true 时,y.equals(x)也是true。
3. 传递性(transitive),对于任意不为 null 的引用值x、y和z,如果 x.equals(y) 是 true,同时 y.equals(z) 是 true,那么x.equals(z)一定是 true。
4. 一致性 (consistent),对于任意不为null的引用值x和y,如果用于equals比较的对象信息没有被修改的话,多次调用时 x.equals(y) 要么一致地返回 true 要么一致地返回 false。
5. 对于任意非null的对象x,x.equals(null)返回false。
- getClass()
getClass()同样是Object的方法,调用对象的getClass方法可以返回该对象的类型类。类型类是指代表一个类型的类,是Class类的实例。
同样可以获取类型类的方法还有:- 调用类的静态成员class
- 调用Class类的静态方法forName(String className)
public class Main {
public static void main(String[] args) {
System.out.println(zhang.name.getClass());
System.out.println(String.class);
try {
System.out.println(Class.forName("java.lang.String"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
输出
class java.lang.String
class java.lang.String
class java.lang.String
- toString()
同样是Object的常用方法之一,默认返回字符串"类名@哈希码",源码如下:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
当自定义类需要特定的toString返回值,需要重写该方法。
String类的常用方法
- compareTo()
该方法用来对比两个String类型,源码如下,从源码可以看出该方法进行了以下操作:
取出两个字符串中较小的长度,在该长度内,比较两个字符串相同位置上的字符,如果出现不同字符,则返回字符的unicode编码差值,如果该长度范围内字符都相同,则返回两个字符差长度之差。
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
运行一下代码
public class Main {
public static void main(String[] args) {
String str1 = "hello";
System.out.println(str1.compareTo("hi"));
System.out.println(str1.compareTo("hello"));
System.out.println(str1.compareTo("hello1"));
}
}
结果如下
-4
0
-1
- concat()
concat方法用于连接两个字符串,返回连接后的字符串,源码如下:
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
- equals()
equals方法用于判断两个字符串是否相等,类似的方法有contentEquals(),两者的区别是前者会判断传入参数是否是String类型,而后者只比较两者的内容时候相同。 - join()
用特定字符连接字符串数组,返回字符串,传入参数可以是(String, String[])或多个字符串的形式,传入多个字符串时,将第一个字符串插入都后面的字符串之间形成新的字符串。 - split()
按照特定字符分割字符串,返回数组。
该方法可以传入一个参数或两个参数,传入一个参数时实际调用split(String regex, 0),第二个参数为int类型,指分割后返回数组的元素个数。 - trim()
去除字符串首尾的空格。 - isEmpty()
判断是否是空字符串。
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
String str1 = "Hello world!";
String str2 = str1.concat(" This is java.");
System.out.println(str2);
StringBuffer str3 = new StringBuffer("Hello world!");
System.out.println(str1.equals(str3));
System.out.println(str1.contentEquals(str3));
String.join("-", new String[]{"java", "is", "cool"});
System.out.println(String.join("-", new String[]{"java", "is", "cool"}));
List<String> list = new ArrayList<>();
list.add("java");
list.add("is");
list.add("cool");
String str4 = String.join(" ", list);
System.out.println(str4);
String[] strArr = str4.split(" ", 2);
for (String str : strArr) {
System.out.println(str);
}
String str5 = " java is cool ";
System.out.println(str5);
System.out.println(str5.trim());
System.out.println(str5.isEmpty());
String str6 = "";
System.out.println(str6.isEmpty());
}
}
输出如下:
Hello world! This is java.
false
true
java-is-cool
java is cool
java
is cool
java is cool
java is cool
false
true