1. Object类
Java语言的根类,即所有类的父类。
1.1 clone()
返回一个Object对象的复制。这个复制返回的是一个新对象。
clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写clone(),其它类就不能直接去调用该类实例的 clone() 方法。
1.1.1 浅拷贝
拷贝对象和原始对象的引用类型引用同一个对象。
使用步骤:
- 实现clone的类首先需要继承Cloneable接口(若未实现,就抛出异常:CloneNotSupportedException)。Cloneable接口实际上是一个标识接口,没有任何接口方法。
- 在类中重写Object类的clone()方法;
- 在clone()中调用super.clone()。无论clone类的继承结构是什么,super.clone()会直接或间接调用java.lang.Object类的clone();
- 把浅复制的引用指向原型对象新的克隆体。
class Obj implements Cloneable{
private int aInt=0;
public int getAInt() {
return aInt;
}
public void setAInt(int int1) {
aInt=int1;
}
public void changeInt() {
this.aInt=1;
}
public Object clone() {
Object o=null;
try {
o=(Object)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
public class DBTest{
public static void main(String[] args) {
Obj a=new Obj();
Obj b=(Obj)a.clone();
b.changeInt();
System.out.println("a:"+a.getAInt());
System.out.println("b:"+b.getAInt());
}
}
运行结果:
a:0
b:1
1.1.2 深复制
拷贝对象和原始对象的引用类型引用不同对象。
在对对象调用clone()完成复制之后,接着对对象中的非基本类型的属性也调用clone()完成复制。
import java.util.Date;
class Obj implements Cloneable{
private Date birth=new Date();
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth=birth;
}
public void changeDate() {
this.birth.setMonth(4);
}
public Object clone() {
Obj o=null;
try {
o=(Obj)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
//实现深复制
o.birth=(Date)this.getBirth().clone();
return o;
}
}
public class DBTest{
public static void main(String[] args) {
Obj a=new Obj();
Obj b=(Obj)a.clone();
b.changeDate();
System.out.println("a:"+a.getBirth());
System.out.println("b:"+b.getBirth());
}
}
运行结果:
a:Tue Nov 27 15:40:48 CST 2018
b:Sun May 27 15:40:48 CST 2018
Date.setMonth(int):都标有删除线,因为被废弃了。是因为Date类在设计中有很多问题,如getYear指的是1900年以来的年数,getMonth是从0开始的。
setMonth(4)实际上是设置为5月,May
1.2 equals()
比较两个对象是否相同。
基本类型比较的是值,引用类型比较的是地址。
满足:自反性、对称性、传递性和一致性(多次调用结果一样)。
- x.equals(x); // true
- x.equals(y) == y.equals(x); // true
- if (x.equals(y) && y.equals(z)) x.equals(z); // true;
- x.equals(y) == x.equals(y); // true
与 null 的比较:对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false
要根据对象属性值进行比较时,需重写equals()。
public boolean equals(Object obj) {
if(this==obj)
return true;
if(!(obj instanceof Person))
return false;
//将obj向下转型为Person引用,访问其属性
Person p=(Person) obj;
return this.age==p.age;
}
- 在重写Object中的equals()时,要注意equals(Object obj)的参数类型时Object;
- 在调用对象属性的时候,要进行类型转换,但转换之前,必须进行类型判断。
1.2.1 equals()源码
public boolean equals(Object obj){
return (this==obj);
}
- 使用==
- 比较两个对象的内存地址
1.2.2 equals() 与 ==
- 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
- 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。
1.3 toString()
返回该对象的字符串表示(对象类型+@+内存地址值)
Syso(s);——默认调用toString()
Syso(s.toString());和上面一句输出一样
需按对象的属性得到相应的字符串表示时,需要重写toString();
class Person extends Object{
int age;
public String toString() {
return "Person [age="+age+"]";
}
}
toString()源码
String toString(){
return getClass().getName()+"@"+Integer.toHexString(hashCode());
}
- getClass():返回一个对象。返回Object的运行时类(字节码对象)
- getName():返回字节码名字(类名)
- @:分隔符
- Integer.toHexString():类名调用方法,说明toHexString()是static方法。它以十六进制无符号整数形式返回一个整数参数的字符串表现形式
- hashCode():无对象调用,则属于Object,返回对象的哈希码值。阿静对象的内存地址以整数形式返回。
1.4 hashCode()
hasCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。
等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。
下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。
我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。
EqualExample e1 = new EqualExample(1, 1, 1);
EqualExample e2 = new EqualExample(1, 1, 1);
System.out.println(e1.equals(e2)); // true
HashSet<EqualExample> set = new HashSet<>();
set.add(e1);
set.add(e2);
System.out.println(set.size()); // 2
理想的散列函数应当具有均匀性,即不相等的对象应当均匀分布到所有可能的散列值上。
2. String类
字符串是常量,它们的值在创建之后不能更改
字符串本身不能更改,但str变量中记录的地址值可以改
String str="CSDN";
str="Zxin";
2.1 赋值方式
2.1.1 使用双引号的方式创建的对象和使用new方式(构造函数)创建的对象的区别
String s1=new String("hello");
String s2="hello"
String s3="hello";
s1==s3;//false
s2==s3;//true
字符串内容存储在方法区的常量池里面,便于字符串的重复使用。
public class Code2 {
public static void main(String[] args) {
String s1=new String("hello");
String s2="hello";
String s3="hello";
String s4=new String("hello");
System.out.println(s1==s3);//false
System.out.println(s2==s3);//true
System.out.println(s1==s4);//false
}
}
2.2 构造方法
String();
String(byte[] bytes);
String(byte[] bytes,int offset, int length);
String(char[] value);
String(char[] value,int offset,int length);
String(String original)——把字符串数据封装成字符串对象
2.3 方法
length():字符个数
subString(int beginIndex):从指定位置到字符串末尾的所有字符
subString(int beginIndex,int endIndex):从指定位置开始到指定位置结束的所有字符串[beginIndex,endIndex)trim():去掉字符串两端空格
split(String str):按照指定符号分割字符串
2.3.1 查找
startWith(String prefix):以给定字符串开始
endsWith(String suffix):以给定字符串结尾
contains(CharSequence s):判断是否包含给定字符串
- 是,返回第一次出现该字符串的索引
- 否,返回-1
indexOf(String str):判断是否包含给定字符串
- 是,返回true
- 否,false
charAt(int index):获取字符串第index位置的字符
- index范围:[0,length()-1]
2.3.2 转换
getBytes():将字符串转换成一个字节数组
to CharArray():将字符串转换为一个字符数组
to LowerCase():转换为小写字符串
to UpperCase():转换为大写字符串
2.3.3 判等
equals(Object obj):比为骄傲字符串的内容是否相同
equalsIgnoreCase(String str):忽略大小写
直接打印引用类型变量时,默认调用该类型进行重写后的toString()。
2.4 字符串拼接
String s="hello";
s+="world";
字符串拼接很耗时,也很浪费空间。
- String的值是不可变的,这就导致每次对String的操作都会生成新的字符串内容。
3. StringBuffer
又称不可变字符序列
类似于String的字符缓冲区,通过某些方法调用可以改变该序列的长度和内容。
它是一个容器,可以装很多字符串,并且能够对其中的字符串进行各种操作。
3.1 方法
append(String str):添加字符串
insert(int offset,String str):在指定位置插入
delete(int start,int end):删除子序列
replace(int start,int end,String str):替换指定范围的内容(end-start=str.length()??)
reverse():反转
toString()
以上方法返回的都是当前对象自己——StringBuffer可以改变当前字符序列的长度和内容
3.2 对象的方法链式调用(运行下)
不断添加数据,要对缓冲区的最后数据进行操作,必须转换成为字符串才可以。
String str=sb.append(true).append("hello").toString();
无论多少数据,数据什么类型都不重要,只要最终编程字符互传就可以使用StringBuffer这个容器。
4. StringBuilder
用在字符串缓冲区被单个线程使用时。
若可以,优先采用此类,它比StringBuffer快。
属于java.lang包,不用导包。
String内容是固定的;StringBuilder内容是可变的。
4.1 成员方法
capcacity():返回当前容量——理论值
length():返回长度(字符个数)——实际值
append(任意类型):添加数据,并返回自身对象
reverse()
4.2
StringBuilder sb=bew StringBuilder();
StringBuilder sb2=sb.append("hello");
运行之后,sb和sb2里都是hello。
4.3 String<------>StringBuilder
1、String--->StringBuilder:StringBuilder(String s);构造方法
2、StringBuilder--->String:toString();