Object
Object类是类层次结构的根类。每个类都使用 Object 作为超类。每个类都直接或者间接的继承自Object类。
Object 中常用方法有:
public int hashCode() //返回该对象的哈希码值。
// 注意:哈希值是根据哈希算法计算出来的一个值,这个值和地址值有关,但是不是实际地址值。
public final Class getClass() //返回此 Object 的运行时类
public String toString() //返回该对象的字符串表示。
protected Object clone() //创建并返回此对象的一个副本。可重写该方法
protected void finalize()
// 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。用于垃圾回收,但是什么时候回收不确定。
- equals()
对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false
实现:
1.检查是否为同一个对象的引用,如果是直接返回 true;
2.检查是否是同一个类型,如果不是,直接返回 false;
3.将 Object 对象进行转型;
4.判断每个关键域是否相等。 - hashCode() :hashCode() 返回散列值
等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。 - toString()
默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。
ToStringExample@4554617c
- clone()
- Cloneable
clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。
public class CloneExample {
private int a;
private int b;
// CloneExample 默认继承 Object
}
CloneExample e1 = new CloneExample();
// CloneExample e2 = e1.clone();
// 'clone()' has protected access in 'java.lang.Object'
clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。
Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。
public class CloneExample implements Cloneable {
private int a;
private int b;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
2.浅拷贝
拷贝对象和原始对象的引用类型引用同一个对象。
@Override
protected ShallowCloneExample clone() throws CloneNotSupportedException {
return (ShallowCloneExample) super.clone();
}
- 深拷贝
拷贝对象和原始对象的引用类型引用不同对象。 重写Clone方法时候,重新创对象。
@Override
protected DeepCloneExample clone() throws CloneNotSupportedException {
DeepCloneExample result = (DeepCloneExample) super.clone();
// 创建新对象
result.arr = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
result.arr[i] = arr[i];
}
return result;
}
- clone() 的替代方案
使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。 Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。
public class CloneConstructorExample {
private int[] arr;
public CloneConstructorExample() { //构造函数
arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
}
public CloneConstructorExample(CloneConstructorExample original) { // 拷贝构造函数
arr = new int[original.arr.length];
for (int i = 0; i < original.arr.length; i++) {
arr[i] = original.arr[i];
}
}
public void set(int index, int value) {
arr[index] = value;
}
public int get(int index) {
return arr[index];
}
}
String :String 被声明为 final,因此它不可被继承。
内部使用 char 数组存储数据,该数组被声明为 final, 这意味着 value 数组初始化之后就不能再引用其它数组。 并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
String用法:
public class StringDemo {
public static void main(String[] args) {
//public String():空构造
String s=new String();
System.out.println("s:"+s);
System.out.println("s.length="+s.length());
System.out.println("-----------------------");
//public String(byte[] bytes):把字节数组转成字符串
byte[] bys={97,98,99,100,101};
String s2=new String(bys);
System.out.println("s2:"+s2);
System.out.println("s2.length="+s2.length());
System.out.println("-----------------------");
//public String(byte[] bytes,int index,int length):把字节数组的一部分转成字符串
String s3=new String(bys,0,3); //从0位置开始,3个字符
System.out.println("s3:"+s3);//s3:abc
System.out.println("s3.length="+s3.length());//s3.length=3
System.out.println("-----------------------");
//public String(char[] value):把字符数组转成字符串
char[] chs={'a','b','c','d','e'};
String s4=new String(chs); //从0位置开始,3个字符
System.out.println("s4:"+s4);
System.out.println("s4.length="+s4.length());
System.out.println("-----------------------");
//public String(char[] value,int index,int count):把字符数组的一部分转成字符串
String s5=new String(chs,0,3); //从0位置开始,3个字符
System.out.println("s5:"+s5);
System.out.println("s5.length="+s5.length());
System.out.println("-----------------------");
//public String(String original):把字符串常量值转成字符串
String s6=new String("abcde");
System.out.println("s6:"+s6);
System.out.println("s6.length="+s6.length());
}
}
判断功能:
boolean equals(Object obj) //比较字符串的内容是否相同,区分大小写
boolean equalsIgnoreCase(String str) //比较字符串的内容是否相同,忽略大小写
boolean contains(String str) //判断大字符串中是否包含小字符串
boolean startsWith(String str) //判断字符串是否以某个指定的字符串开头
boolean endsWith(String str) //判断字符串是否以某个指定的字符串结尾
boolean isEmpty()// 判断字符串是否为空
public class StringDemo3 {
public static void main(String[] args) {
// 创建字符串对象
String s1 = "helloworld";
String s2 = "helloworld";
String s3 = "HelloWorld";
// boolean equals(Object obj):比较字符串的内容是否相同,区分大小写
System.out.println("equals:" + s1.equals(s2));//true
System.out.println("equals:" + s1.equals(s3));//false
System.out.println("-----------------------");
// boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写
System.out.println("equals:" + s1.equalsIgnoreCase(s2));//true
System.out.println("equals:" + s1.equalsIgnoreCase(s3));//true
System.out.println("-----------------------");
// boolean contains(String str):判断大字符串中是否包含小字符串
System.out.println("contains:" + s1.contains("hello"));//true
System.out.println("contains:" + s1.contains("hw"));//false
System.out.println("-----------------------");
// boolean startsWith(String str):判断字符串是否以某个指定的字符串开头
System.out.println("startsWith:" + s1.startsWith("h"));//true
System.out.println("startsWith:" + s1.startsWith("hello"));//true
System.out.println("startsWith:" + s1.startsWith("world"));//false
System.out.println("-----------------------");
//boolean endsWith(String str):判断字符串是否以某个指定的字符串结尾
System.out.println("startsWith:" + s1.endsWith("d"));//true
System.out.println("startsWith:" + s1.endsWith("world"));//true
System.out.println("startsWith:" + s1.endsWith("hello"));//false
System.out.println("-----------------------");
// boolean isEmpty():判断字符串是否为空。
System.out.println("isEmpty:" + s1.isEmpty());//false
String s4 = ""; //字符串内容为空
String s5 = null;//字符串对象为空
System.out.println("isEmpty:" + s4.isEmpty());//true
// NullPointerException
// s5对象都不存在,所以不能调用方法,空指针异常
//System.out.println("isEmpty:" + s5.isEmpty());
}
}
获取功能
int length() //获取字符串的长度。
char charAt(int index) //获取指定索引位置的字符
int indexOf(int ch) //返回指定字符在此字符串中第一次出现处的索引。为什么这里参数int类型,而不是char类型?原因是:'a'和97其实都可以代表'a'
int indexOf(String str) //返回指定字符串在此字符串中第一次出现处的索引。
int indexOf(int ch,int fromIndex) //返回指定字符在此字符串中从指定位置后第一次出现处的索引。
int indexOf(String str,int fromIndex) //返回指定字符串在此字符串中从指定位置后第一次出现处的索引。
String substring(int start) //从指定位置开始截取字符串,默认到末尾。
String substring(int start,int end) //从指定位置开始到指定位置结束截取字符串。左闭右开
public class StringDemo4 {
public static void main(String[] args) {
// 定义一个字符串对象
String s = "helloworld";
// int length():获取字符串的长度。
System.out.println("s.length:" + s.length());//10
System.out.println("----------------------");
// char charAt(int index):获取指定索引位置的字符
System.out.println("charAt:" + s.charAt(7));//r
System.out.println("----------------------");
// int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引。
System.out.println("indexOf:" + s.indexOf('l'));//2
System.out.println("----------------------");
// int indexOf(String str):返回指定字符串在此字符串中第一次出现处的索引。
System.out.println("indexOf:" + s.indexOf("owo"));//4
System.out.println("----------------------");
// int indexOf(int ch,int fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引。
System.out.println("indexOf:" + s.indexOf('l', 4));//8
System.out.println("indexOf:" + s.indexOf('k', 4)); // -1
System.out.println("indexOf:" + s.indexOf('l', 40)); // -1
System.out.println("----------------------");
// int indexOf(String str,intfromIndex):返回指定字符串在此字符串中从指定位置后第一次出现处的索引。
System.out.println("indexOf:" + s.indexOf("owo", 4));//4
System.out.println("indexOf:" + s.indexOf("ll", 4)); //-1
System.out.println("indexOf:" + s.indexOf("ld", 40)); // -1
System.out.println("----------------------");
// String substring(int start):从指定位置开始截取字符串,默认到末尾。包含start这个索引
System.out.println("substring:" + s.substring(5));//world
System.out.println("substring:" + s.substring(0));//helloworld
System.out.println("----------------------");
// String substring(int start,int
// end):从指定位置开始到指定位置结束截取字符串。包括start索引但是不包end索引
System.out.println("substring:" + s.substring(3, 8));//lowor
System.out.println("substring:" + s.substring(0, s.length()));//helloworld
/**
* 获取 字符串中的每个字符
*/
for(int i=0;i<s.length();i++){
System.out.println(s.charAt(i));
}
}
}
byte[] getBytes() //字符串转换为字节数组。
char[] toCharArray() //把字符串转换为字符数组。
static String valueOf(char[] chs) //把字符数组转成字符串。
static String valueOf(int i) //把int类型的数据转成字符串。注意:String类的valueOf方法可以把任意类型的数据转成字符串。
String toLowerCase() //把字符串转成小写。
String toUpperCase() //把字符串转成大写。
String concat(String str) //把字符串拼接。
//替换功能:
String replace(char old,char new)
String replace(String old,String new)
//去除字符串两端空格
String trim()
//按字典顺序比较两个字符串
int compareTo(String str)
int compareToIgnoreCase(String str)
StringBuffer
//StirngBuffer的构造方法
public StringBuffer() //无参构造方法
public StringBuffer(int capacity) //指定容量的字符串缓冲区对象
public StringBuffer(String str) //指定字符串内容的字符串缓冲区对象
//StringBuffer的方法
public int capacity() //返回当前容量。 理论值
public int length() //返回长度(字符数)。 实际值
public static void main(String[] args) {
// public StringBuffer():无参构造方法
StringBuffer sb = new StringBuffer();
System.out.println("sb:" + sb);
System.out.println("sb.capacity():" + sb.capacity()); //StringBuffer默认的指定容量是16
System.out.println("sb.length():" + sb.length());//0
System.out.println("--------------------------");
// public StringBuffer(int capacity):指定容量的字符串缓冲区对象
StringBuffer sb2 = new StringBuffer(50);
System.out.println("sb2:" + sb2);//""
System.out.println("sb2.capacity():" + sb2.capacity());//50
System.out.println("sb2.length():" + sb2.length());//0
System.out.println("--------------------------");
// public StringBuffer(String str):指定字符串内容的字符串缓冲区对象
StringBuffer sb3 = new StringBuffer("hello");
System.out.println("sb3:" + sb3);//hello
System.out.println("sb3.capacity():" + sb3.capacity());//16+5=21
System.out.println("sb3.length():" + sb3.length());//5
}
public StringBuffer append(String str)
//可以把任意类型数据添加到字符串缓冲区里面,并返回字符串缓冲区本身
public StringBuffer insert(int offset,String str)
//在指定位置把任意类型的数据插入到字符串缓冲区里面,并返回字符串缓冲区本身
public static void main(String[] args) {
// 创建字符串缓冲区对象
StringBuffer sb = new StringBuffer();
// 链式编程
sb.append("hello").append(true).append(12).append(34.56);
System.out.println("sb:" + sb);
// public StringBuffer insert(int offset,String
// str):在指定位置把任意类型的数据插入到字符串缓冲区里面,并返回字符串缓冲区本身
sb.insert(5, "world");
System.out.println("sb:" + sb);
}
public StringBuffer deleteCharAt(int index)
//删除指定位置的字符,并返回本身
public StringBuffer delete(int start,int end)
//删除从指定位置开始指定位置结束的内容,并返回本身
public StringBuffer replace(int start,int end,String str)
//从start开始到end用str替换
public StringBuffer reverse()
public String substring(int start) // 注意截取返回的是String,而不是StringBuffer了
public String substring(int start,int end)
String 和 StringBuffer 的相互转换
public class StringBufferDemo7 {
public static void main(String[] args) {
String s="hello";
System.out.println(stringToStringBuffer(s)); //hello
System.out.println(stringBufferToString(stringToStringBuffer(s)));//hello
}
// String -->StringBuffer
public static StringBuffer stringToStringBuffer(String s) {
// 注意:不能把字符串的值直接赋值给StringBuffer
// StringBuffer sb = "hello";
// StringBuffer sb = s;
// 方式1:通过构造方法
/* StringBuffer sb = new StringBuffer(s);
return sb;*/
// 方式2:通过append()方法
StringBuffer sb2 = new StringBuffer();
sb2.append(s);
return sb2;
}
//StringBuffer -->String
public static String stringBufferToString(StringBuffer buffer){
// 方式1:通过构造方法
/* String str = new String(buffer);
return str;*/
// 方式2:通过toString()方法
String str2 = buffer.toString();
return str2;
}
}
String, StringBuffer and StringBuilder
- 可变性
String 不可变
StringBuffer 和 StringBuilder 可变
2.线程安全
String 不可变,因此是线程安全的
StringBuilder 不是线程安全的
StringBuffer 是线程安全的,内部使用 synchronized 进行同步
3. 性能
Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢
StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用
StringBuilder每次都会对StringBuilder对象本身进行操作,而不是生成新的对象并改变对象引用。 相同情况下使用StirngBuilder相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却冒多线程不安全的风险。
三者使用的总结
操作少量的数据,使用String
单线程操作字符串缓冲区下操作大量数据,使用StringBuilder
多线程操作字符串缓冲区下操作大量数据,使用StringBuffer