添加链接描述
由官方介绍可见,Object属于
Java.lang
包内的一个类,而且提供了很多种方法, Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。 简单的说 Object类就是所有类的父类,包括我们所写的类,我们在使用类的时候就会利用 Object类中的方法,因为所有的父类都自动的继承了这个类,所以我们在日常学习和开发中见不到 Object这个类。子类拥有 Object类的所有方法,并且可以对这些方法进行重写,满足我们的业务需求。
返回此 Object 运行时的类,获取对象的真实类的全名称。比如:在使用多态时,父类引用变量,使用getClass()方法就可以看到真实的类:
应用场景:
- 查看当前使用该方法的对象,到底是哪个类;
- 在使用多态时,当代码多的时候使用 getClass()方法可以方便、快捷的知道 指向的是哪个子类。
package com.lCommonClasses.obj;
public class Object1 {
public void eat(){
System.out.println("吃");
}
}
class Test{
public static void main(String[] args) {
Object1 obj1 = new HashTest();//使用多态
Object1 obj2 = new Object1();
obj1.eat(); //子类重写了父类的eat(),使用的是子类的方法
/**1.getClass():查看obj1归属于哪个 class*/
//结果:class com.lClass.HashTest
System.out.println(obj1.getClass());
//结果:class com.lClass.Object1
System.out.println(obj2.getClass());
}
}
package com.lCommonClasses.obj;
public class HashTest extends Object1{
@Override
public void eat() {
System.out.println("吃水果");
}
}
作用是获取哈希码,也称为散列码;它实际上是返回一个int整 数。这个哈希码的作用是
确定该对象在哈希表中的索引位置。
package com.lCommonClasses.obj;
public class Object1 {
public static void main(String[] args) {
HashTest hash1 = new HashTest(8);
HashTest hash2 = new HashTest(8);
/**1.调用hashCode()方法:
* 460141958:这个数也就是哈希码,也称为散列码,
* 作用:是确定该对象在哈希表中的索引位置*/
System.out.println(hash1.hashCode());
}
}
package com.lCommonClasses.obj;
public class Object1 {
public static void main(String[] args) {
HashTest hash1 = new HashTest(8);
HashTest hash2 = new HashTest(8);
/**2.调用equals()方法:
* 没有重写equals方法前为false;重写之后为true*/
System.out.println(hash1.equals(hash2));
}
}
源码很简单,不就是两个==号,但是我们知道类的引用类型的数据,而用两个等于号去判断两个引用类型,是去判断两者的内存地址是否相同,当一个类去new
一个新对象时,是在堆内存内开辟了一个新的空间;创建两个或者多个类的时候,每个类肯定有属于自己的空间,所有也有一个独一无二的地址,这就是为什么这个判断为什么不成立的原因。
但是比较对象的引用对于我们在实际开发中没有意义,我们一般还是要重写该方法,比如去判断两者的参数是否相等:
package com.lClass;
public class HashTest {
private int age;
public HashTest() {
}
public HashTest(int age) {
this.age = age;}
public int getAge() {
return age;}
public void setAge(int age) {
this.age = age;}
/*重写equals方法,只要HashTest生成的对象,
传入age参数相等,即可判断两者一致重写后的equals,
就不再是去判断两者的地址是否相同*/
@Override
public boolean equals(Object obj) {
HashTest h = (HashTest) obj; //多态
if(this.age == h.getAge()) {
return true;
}
return false;
}
}
1)== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同 一个对象。
- (基本数据类型== 比较的是值,引用数据类型 == 比较的是内存地址)
2)equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
- 若该类没有重写equals() 方法。当通过 equals() 比较该类的两个对象时, 等价于通过“==”比较这两个对象。
- 若该类重写了 equals() 方法。一般,我们都覆盖 equals() 方法 将两个对象 的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)
如果两个对象相等,则hashcode一定也是相同的 两个对象相等,对两个对象分别调用equals方法都返回true, 两个对象有相同的hashcode值,它们也不一定是相等的。因此,equals 方法被重写过,则 hashCode 方法也必须被重写,hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象 指向相同的数据)
返回一个字符串来标识当前对象,就是 类名+符号@+对象的哈希码值
class Test{
public static void main(String[] args) {
Object1 obj1 = new HashTest();//使用多态
Object1 obj2 = new Object1();
/**4.toString():但是这个返回值视乎没什么意义,
* 所以为了返回值有更多的意义,我们可以重写这个方法*/
System.out.println(obj1);
System.out.println(obj1.toString());
System.out.println(obj2.toString());
}
}
其他方法
clone()
notify()
wait()
class Test{
public static void main(String[] args) {
/**5.将Object类型转换为int类型*/
Object obj = "-416464";
try{
Integer.parseInt(obj.toString());
} catch (NumberFormatException e) {
System.out.println("输入不是 int类型");
}finally {
System.out.println("obj="+obj);
}
}
}
class Test{
public static void main(String[] args) {
/**6.将String类型转换为int类型
两个结果不同:false;true;
底层是:-128 ~ 127时,两者相同,超出范围后就不同*/
String str= "129";
System.out.println(Integer.valueOf(str) == Integer.valueOf("129"));
//当数值超出范围后,用`equals()方法`
if (Integer.valueOf(str).equals(Integer.valueOf("129"))){
System.out.println("true");
}else{
System.out.println("false");
}
}
}
特点不可变性 final-操作量较少
String类、StringBuilder类、StringBuffer类是三个字符串相关类。String类的对象代表不可变的字符序列,StringBuilder类和StringBuffer类代表可变字符序列
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
}
final:String类是不可以被继承的
Serializable:可序列化接口。凡是实现此接口的对象就可以通过网络 或本地流进行数据的传输;
Comparable:凡是实现此接口的类,其对象都可以比较大小。
/**Jdk1.8中:
1.存储字符串数据的容器
2.final:指明此 value数组一旦初始化,其地址就不可变。 */
private final char value[];
/**Jdk1.9开始:为了节省内部空间
1.存储字符串数据的容器 */
private final byte value[];
字符串常量都存储在字符串常量池(StringTable)中;
字符串常量池:不允许存放两个相同的字符串常量
字符串常量池:在不同 Jdk 版本中存储位置不同:
(1)jdk1.7之前: 字符串常量池存放在方法区(jdk1.8称其为元空间)
(2)jdk1.7之后(包括jdk1.7):存放在堆空间
package com.kString;
import org.junit.Test;
public class String0 {
@Test
public void test1() {
String str1 = "hello";//字面量的定义
String str2 = "hello";
//字面量相同时使用同一个对象,即引用的地址相同
System.out.println(str1 == str2);//true
}
@Test
public void test2() {
/**
* String的不可变性
* ①当对字符串变量重新赋值时,需要重新指定一个字符串常量的
* 位置进行赋值,不能在原有的位置修改;
*/
String str1 = "hello";
String str2 = "hello";
str2 = "hi";
System.out.println(str1);//hello
System.out.println(str2);//hi
}
@Test
public void test3() {
/**
* String的不可变性;
* ②在对现有字符串进行拼接操作时,需要重新开辟空间保存拼接
* 以后的字符串,不能在原有的位置修改;
*/
String str1 = "hello";
String str2 = "hello";
/* 在`堆`中开辟了一处新空间,str2指向这个新空间
String str2 = new String();
str2 = str2 + " hi";
*/
str2 += " hi";
System.out.println(str1);//hello
System.out.println(str2);//hello hi
}
@Test
public void test4() {
String str1 = "hello";
String str2 = "hello";
/**
* String的不可变性;
* ③当调用字符串的 replace()替换现有的字符时,需要重新开辟空间后,
* 保存修改后的字符串,不能在原有的位置修改;
*/
/* 取代:replace(char oldChar, char newChar)
返回的是一个新的 字符串*/
String str3 = str2.replace('l', 'o');
System.out.println(str1);//hello
System.out.println(str2);//hello
System.out.println(str3);//heooo
}
}
不可变性练习
String str="good";
char[] ch = {
't','e','s','t'};
//传参时:基本数据类型传的是值,引用数据类型传的是地址
public void change(String str, char[] ch){
//这里是 new了一个对象用来存储改变后的值
str="test ok";
System.out.println(str);//test ok
ch[0]='b';
}
@Test
public void test10(){
String0 s0 = new String0();
s0.change(s0.str,s0.ch);
System.out.println(s0.str);//good
System.out.println(s0.ch);//best
}
String实例化的两种方式:
(1) String str1 = “hello”;
(2) String str2 = new String(“hello”);
package com.kString;
import org.junit.Test;
public class String0 {
@Test
public void test5() {
String str1 = "hello";
String str2 = "hello";
String s1 = new String("hello");
String s2 = new String("hello");
//==:比较对象时是地址; equals比较的是内容
System.out.println(str1 == str2);//true
System.out.println(str1 == s1);//false
System.out.println(s1 == s2);//false
System.out.println(str1.equals(s1));//true
System.out.println(s1.equals(s2));//true
}
}
思考:String s1 = new String(“hello”);在内存中创建了几个对象?
两个对象:①在堆空间 new的对象;②在字符串常量池中生成的字面量
package com.kString;
import org.junit.Test;
public class String0 {
@Test
public void test6() {
Person p1 = new Person();
Person p2 = new Person();
/*
①p1 和 p2 在堆中的地址不同,在常量池中指向的值都是 Tom
②常量池添加新的字面量 Jerry;
③将 p1指向的地址变为 Jerry的地址
*/
p1.name= "Tom";
p2.name= "Tom";
p1.name= "Jerry";
System.out.println(p1.name);//Jerry
System.out.println(p2.name);//Tom
}
}
class Person{
String name;
}
常量 + 常量
:结果仍存储在字符串常量池中,返回此字面量的地址。注:此时的常量可能是字面量,也可能是final修饰的常量;常量 + 变量
; 变量 + 常量
:都会通过 new的方式创建一个新的字符串,返回的是堆空间中此字符串对象的地址,和concat(String otherString)一样创建新的对象;String.intern()
:返回的是字符串在常量池中字面量的地址,而不是对象的地址。package com.kString;
import org.junit.Test;
/**情况Ⅰ~Ⅲ */
public class String0 {
@Test
public void test7() {
String s1 = "Hello";
String s2 = "World";
String s3 = "HelloWorld";
String s4 = "Hello" + "World";
/*底层new 了一个StringBuilder调用了调用了它的
toString() 方法,就是在该方法中 new 了一个新对象*/
String s5 = s1 + "World";
String s6 = "Hello" + s2;//
String s7 = s1 + s2;
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s5 == s6);//false
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false
/*返回的是字符串在常量池中字面量的地址,
而不是对象的地址。*/
String s8=s5.intern();
System.out.println(s4 == s8);//true
}
@Test
public void test8() {
final String s1 = "Hello";
final String s2 =