一、简介Object类
1、Object类是所有类的父类,即每个类都直接或简介继承自该类。所以一个Object类型的变量可以引用任何对象,不论是类实例还是数组。
在不明确给出父类的情况下,Java会自动把Object作为要定义类的父类。
Object类有一个默认构造方法public Object(),在构造子类实例时,都会先调用这个默认构造方法。
二、方法预览
1、Object()
默认构造方法
2、clone()
创建并返回此对象的一个副本(复制对象)
3、equals(Object obj)
指示某个其他对象是否与此对象"相等"。
4、finalize()
当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法,该方法用于释放资源。
5、getClass()
返回一个对象的运行时类,获得类型的信息。
6、hashcode()
该方法将对象的内存地址进行哈希运算,返回一个int类型的哈希值(返回该对象的哈希码值)。
功能:是相等对象拥有相同的哈希码,尽量让不等的对象具有不同的哈希码。
7、notify()
唤醒在此对象监视器上等待的单个线程。
8、notifyAll()
唤醒在次对象监视器上等待的所有线程。
9、toString()
返回该对象的字符串表示。以便用户能够获得一些有关对象状态的基本信息。简单说就是利用字符串来表示对象。
10、wait()
导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法。
11、wait(long timeout)
导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量。
12、wait(long timeout, int nanos)
导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
三、
1、为什么要重写equals()方法?
因为Object类中定义的equals()方法是用来比较两个引用所指向的对象的内存地址是否一致。
源码:
public boolean equals(Object obj) {
return (this == obj);
}
("=="两边是基本类型比较的是内容,"=="两边是引用类型(class)比较的是否对同一对象的引用,即比较两个引用所指向的对象的内存地址是否一致。)
而我们经常会希望两个不同对象的某些属性值相同时,就认为它们相同。所以我们要重新equals()方法。
2、为什么要重写hashCode()方法?
需要注意的是:
a、在java应用程序运行时,无论何时多次调用同一个对象时的hashCode()方法,这个对象的hashCode()方法的返回值必须是相同的一个int值
b、如果两个对象equals()返回值为true,则它们的hashCode()也必须返回相同的int值
c、如果两个对象equals()返回值为false,则它们的hashCode()返回值也必须不同
由于hashCode方法定义在Object类中,因此每个对象都有一个默认的散列码,其值为对象的存储地址。如果重新定义equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中。(要保证上面所述b,c原则)
二、Java - String 类常用方法
JackWu JavaGolang 3月18日
字符串操作是计算机程序设计中最常见的行为,本文继续介绍 String 类常用方法。
重载 "+" 与 StringBuilder
我们都知道 String 对象是不可变的,可以给一个 String 对象加任意多个别名,因为它具有只读特性,所以指向它的任何一个引用都不会改变它的值,因此任意多个引用也不会有什么相互影响。
但是这样的不可变性会带来一定的效率问题,比如 String 对象重载的 "+" 操作符,操作符重载的含义:一个操作符应用于特定的类时,被设计者赋予了特殊含义(在 Java 中 String 类仅有 “+” 和 “+=” 两个重载操作符)。
测试代码:
publicclassTestString{
publicstaticvoidmain(String[] args){
String str ="a"+"b"+10;
System.out.println(str);
}
}
反编译结果:
Code:
0: ldc#2// String a
2: astore_1
3: new#3// class java/lang/StringBuilder
6: dup
7: invokespecial#4// Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual#5// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc#6// String b10
16: invokevirtual#5// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual#7// Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_1
23: getstatic#8// Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_1
27: invokevirtual#9// Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: return
我们可以惊奇的发现:代码中使用的是 “+” 重载符,没有使用到 StringBuilder 类,但是编译器为了优化它自作主张的使用了 StringBuilder 类,因为 StringBuilder 类更高效,大家会不会觉得反正编译器可以帮我们用 StringBuilder 优化,那是不是意味着我们可以随意使用 “+” 重载操作符呢?再来看下面这个例子:
测试代码:
publicstaticvoidmain(String[] args){
String result ="";
for(inti =0; i <100; i ++) {
result += i;
}
System.out.println(result);
}
反编译:
Code:
0: ldc#2// String
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: bipush100
8: if_icmpge36
11: new#3// class java/lang/StringBuilder
14: dup
15: invokespecial#4// Method java/lang/StringBuilder."<init>":()V
18: aload_1
19: invokevirtual#5// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: iload_2
23: invokevirtual#6// Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
26: invokevirtual#7// Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: astore_1
30: iinc2,1
33:goto5
36: getstatic#8// Field java/lang/System.out:Ljava/io/PrintStream;
39: aload_1
40: invokevirtual#9// Method java/io/PrintStream.println:(Ljava/lang/String;)V
主要是关注编号为第 5 到第 33 : 这里明显看出 “+=” 操作符编译器还是使用 StringBuilder 类进行优化,但是需要强烈注意的是:StringBuilder 的初始化是在循环体内创建的,即每循环一次,就会创建新的 StringBuilder 对象,这样会造成大量的对象垃圾导致 GC 操作频繁。
**优化**:要进行大量字符串拼接操作,最好的方式是定义一个 StringBuilder 或 StringBuffer 对象进行字符串连接,少量的字符串拼接可以使用重载操作符 “+” 或 “+=”。
优化代码:
StringBuilder sb =newStringBuilder();
for(inti =0; i <100; i ++) {
sb.append(i);
}
System.out.println(sb);
极容易忽略的:无意识递归
来看一个简单的代码:
publicclassTestStringStackOverflow{
// 定义一个 Person 类
staticclassPerson{
privateString name;
publicPerson(String name){
this.name = name;
}
/**
* 重写 toString() 方法,注意最后的 this 关键字
*/
@Override
publicStringtoString()
{
return"Person{"+"name='"+ name +'\''+'}'+this;
}
}
publicstaticvoidmain(String[] args){
Person person =newPerson("jackwu");
System.out.println(person);
}
}
不知道各位有没有发现存在什么问题?这里一不小心写了无限循环的递归调用,会导致`java.lang.StackOverflowError`异常,所以千万不要在 toString() 方法输出 this。
Exceptioninthread"main"java.lang.StackOverflowError
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:449)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at com.java.blog.base.TestStringStackOverflow$Person.toString(TestStringStackOverflow.java:19)
解决方案: 使用super.toString() 方法打印内存地址.这里的 super 父类是Object类。
String 操作方法
String 操作方法当需要改变字符串的内容时,String类的方法都会返回一个新的String对象。如果内容没有发生改变,String 的方法只是返回指向原对象的引用而已,这节省了存储空间以及避免了额外的花销。
方法参数,重载版本应用
构造器String()
String(String original)
String(char value[])
String(char value[], int offset, int count)
String(byte bytes[])
String(StringBuffer buffer)
String(StringBuilder builder)
创建String对象
length()int length()String中字符的个数
charAt()charAt(int index)取得String中该索引位置上的char
getChars(),getBytes()getChars(char dst[], int dstBegin)
getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)
getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin)
getBytes(String charsetName)
getBytes(Charset charset)
getBytes()
复制char或byte到一个目标数组中
toCharArray()char[] toCharArray()生成一个char[],包含String的所有字符
equals(),equalsIgnoreCase()boolean equals(Object anObject)
qualsIgnoreCase(String anotherString)
比较两个String的内容是否相同
compareTocompareTo(String anotherString)按词典顺序比较String的内容,比较结果为负数,零或正数.注意,大小写并不等价
containsboolean contains(CharSequence s)当且仅当此字符串包含指定的时,才返回true
contentEquals()boolean contentEquals(StringBuffer sb)
boolean contentEquals(CharSequence cs)
如果该String与参数的内容完全一致,则返回true
equalsIgnoreCaseboolean equalsIgnoreCase(String anotherString)与之进行比较的String 忽略大小写,如果两个String的内容相同,则返回true
regionMatches()regionMatches(int toffset, String other, int ooffset,int len)返回boolean结果,以表明所比较区域是否相等
startsWith()boolean startsWith(String prefix, int toffset)
boolean startsWith(String prefix)
返回boolean结果,以表明String是否以此参数起始
endsWith()boolean endsWith(String suffix)返回boolean结果,以表明此参数在String中的起始索引.lastIndexOf()是从后向前搜索
indexOf(),lastIndexOf()int indexOf(int ch)
indexOf(int ch, int fromIndex)
int lastIndexOf(int ch)
lastIndexOf(int ch, int fromIndex)
如果该String并不包含此参数,就返回-1;否则返回此参数在String中起始的索引.lastIndexOf()是从后向前搜索
substring(subSequence())String substring(int beginIndex)
String substring(int beginIndex, int endIndex)
CharSequence subSequence(int beginIndex, int endIndex)
返回一个新的String,以包含参数指定的子字符串
concat()String concat(String str)返回一个新的String对象,内容为起始Stirng连接上参数String
replace()String replace(char oldChar, char newChar)返回替换字符后的新String对象.如果没有替换发生,则返回原始的String对象
toLowerCase,toUpperCase()String toLowerCase(Locale locale)
String toLowerCase()
String toUpperCase(Locale locale)
String toUpperCase()
将字符的大小写改变后,返回一个新String对象.如果没有发生改变,则返回原始的String对象
trim()String trim()将String两端的空白字符删除后,返回一个新的String对象.如果没有改变发生,则返回原始的String对象
valueOf()重载版本:Object;char[];char[],偏移量,字符个数; boolean; char; int; long; float; double返回一个表示参数内容的String
intern()native String intern()为每个唯一的字符序列生成一个且仅生成一个String引用
格式化输出
System.out.format()
用于PrintStream或PrintWriter对象,其中包括System.out对象。
System.out.format("%-15s %5s %10s\n","item","qty","price");
System.out.format("%-15s %5s %10s\n","----","---","-----");
System.out.format("%-15.15s %5d %10.2f\n","lalala",4,4.25);
输出
item qty price
---- --- -----
lalala44.25
Formatter类
Formatter 类可以将格式化字符串与数据翻译成需要的结果,Formatter类格式化抽象语法: %[argument_index][flags][width][.precision]conversion
用"-"标志来改变对齐方向(默认右对齐),添加了"-"表示左对齐 ;
width: 控制一个域的最小尺寸;
precision: 用来指明最大尺寸,用于String时,它表示打印String时输出字符的最大数量.用于浮点数时,表示小数显示的位数(默认6位),小数过多则舍入,过少则在尾部补零,用于整数时,会出发异常。
Formatter 转换
类型转换字符说明
d整数型(十进制)
cUnicode字符
bBoolean值
sString
f浮点数(十进制)
e浮点数(科学计数法)
x整数(十六进制)
h散列码(十六进制)
%字符'%'
String.format()
是一个 static 方法,接受与 Formatter.format() 方法一样的参数,但返回一个 String 对象。
String.format() 内部,它创建一个Formatter对象,然后将你传入的参数转给 Formatter 。