API
API(Application Programming Interface):应用程序编程接口
Java API:就是Java提供给我们使用的类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用。
Object类
Object类:类层次结构的根类,所有类都直接或者间接的继承该类。
构造方法:public Object()
Object类属于java.lang包下的类,该包下的类不需要导入就可以访问该包下的类的成员
hashCode()方法
//返回该对象的哈希码值。默认情况下,该方法会根据对象的地址来计算。
public int hashCode()
不同对象的hashCode()一般不会相同 ,但是同一个对象的hashCode()值肯定相同。
不是对象的实际地址值,可以理解为逻辑地址值。
public class Demo {
public static void main(String[] args) {
Object obj1=new Object();
Object obj2=new Object();
System.out.println(obj1.hashCode());
System.out.println(obj2.hashCode());
}
}
/*
输出结果:
460141958
1163157884
*/
getClass()方法
//返回此 Object 运行时的类以及所在的包。
public final Class getClass()
public class Demo2 {
public static void main(String[] args) {
//getClass()
Object obj1=new Object();
Object obj2=new Object();
System.out.println(obj1.getClass());
System.out.println(obj2.getClass());
Student s1=new Student();
System.out.println(s1.getClass());
System.out.println(obj1.getClass().getName());
System.out.println(obj1.getClass()==obj2.getClass());
System.out.println(obj1.getClass()==s1.getClass());
}
}
class Student{}
/*
运行结果:
class java.lang.Object
class java.lang.Object
class com.xupt.Demo2.Student
java.lang.Object
true
false
*/
//可通过getName()方法获取对象的真实类的全名称
//public String getName()
toString()方法
//返回该对象的字符串表示。
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public class Test2 {
public static void main(String[] args) {
Object obj=new Object();
System.out.println(obj);
System.out.println(obj.toString());
}
}
//输出obj默认会调用toString()方法
/*
运行结果:
java.lang.Object@1b6d3586
java.lang.Object@1b6d3586
*/
对于我们来说,获取类名和地址值没有什么意义,所以我们可以重写toString()方法
public class Student {
String name;
int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString()
{
return "姓名:"+this.name+"\n年龄:"+this.age;
}
}
public class Demo {
public static void main(String[] args) {
Student s1=new Student("张三",20);
//我们想让toString返回的是姓名和年龄,需要重写toString方法
System.out.println(s1.toString());
}
}
/*
输出结果:
姓名:张三
年龄:20
*/
equals()方法
//指示一些其他对象是否等于此。
public boolean equals(Object obj) {
return (this == obj);
}
对于字符串即String类来说,两个字符串字面值相等,就代表两个对象相同
String类中将equals()方法重写了,用于比较两个字符串字面值是否相等
public class Demo {
public static void main(String[] args) {
String s1="abc";
String s2="abc";
boolean b=s1.equals(s2);
System.out.println(b);
}
}
/*
输出结果:
true
*/
我们同样可以重写一个类中的equals方法
//我们将equals方法重写为如果Student类对象的name和age相同,就表示这两个对象相同
public class Student {
String name;
int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public boolean equals(Object obj)
{
return this.name.equals(s.name)&&this.age==s.age;
}
}
public class Demo4 {
public static void main(String[] args) {
Student s1=new Student("张三",20);
Student s2 = new Student("张三",20);
//在学生类中,如果姓名和年龄相等,我们就认为这两个对象相等,则需要重写equals方法
System.out.println(s1.equals(s2));
}
}
/*
输出结果:
true
*/
在编程中,我们要提高程序的健壮性,即让其更加周全,还要提高程序的效率
如果我们传入一个非Student类的对象,程序就会报错
如果传入这个对象自身,那么我们可以直接返回true来提高效率
//改进如下
@Override
public boolean equals(Object obj)
{
if(this==obj)
return true;
//判断传入的对象是否为该类对象
if(!(obj instanceof Student))
return false;
Student s=(Student)obj;
return this.name.equals(s.name)&&this.age==s.age;
}
clone()方法
克隆分为浅克隆和深克隆,在此我们只讲浅克隆
对象的深克隆后面讲:采用IO流来实现 使用 ObjectOutputStream 将对象写入文件中,然后再用ObjectInputStream读取回来
//创建并返回此对象的副本
protected Object clone()
throws CloneNotSupportedException
clone()的权限修饰符是受保护的,在使用的时候,让该类重写该方法,并把该方法的权限修饰符改为public
如果一个对象需要调用clone方法,那么该对象所属的类必须要实现Cloneable接口。
//Cloneable接口中没有任何抽象方法
//接口中如果没有定义任何抽象方法,这种接口叫做标记接口
class Student implements Cloneable{
String name;
int age;
public Student() {}
//重写clone方法,将权限修饰符改为public
//要抛出CloneNotSupportedException异常
@Override
public Object clone() throws CloneNotSupportedException {
//我们不需要重写父类的clone方法,直接调用父类的clone方法
return super.clone();
}
}
public class Demo {
//此处也要抛出CloneNotSupportedException异常
public static void main(String[] args) throws CloneNotSupportedException {
Student s1=new Student();
s1.age=15;
//因为返回的是一个Object的对象,所以要向下转型
Student s2=(Student)s1.clone();
s2.age=18;
System.out.println(s1.age);
System.out.println(s2.age);
//s1和s2的地址值是不同的
System.out.println(s1);
System.out.println(s2);
}
}
/*
运行结果:
15
18
com.xupt.Demo.Student@1b6d3586
com.xupt.Demo.Student@4554617c
*/
如果被克隆的对象中维护了另外一个类的对象,这时候只是克隆被维护的对象的地址,而没有把该对象也克隆一份。
class Student implements Cloneable{
String name;
int age;
Book book;
public Student() {}
public Student(String name, int age,Book book)
{
this.name = name;
this.age = age;
this.book=book;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//学生在阅读的书籍
class Book{
String name;
public Book(){}
public Book(String name)
{
this.name=name;
}
}
public class Demo {
public static void main(String[] args) throws CloneNotSupportedException {
Book b=new Book("Math");
Student s1=new Student("张三",15,b);
Student s2=(Student) s1.clone();
s2.book.name ="Chinese";
System.out.println(s1.book.name);
System.out.println(s2.book.name);
}
}
/*
运行结果:
Chinese
Chinese
*/
过程(过程中就暂且不涉及创建对象的内存操作):
- 定义一个Book类型的引用b指向一个Book类型的对象,定义一个Student类型的引用s1指向一个Student类型的对象,在该对象中存在一个Book类型的引用b指向Book类型的对象,如图所示
- 通过clone()方法将s1引用指向的对象克隆一份,在堆内存中新开辟一个空间存储这个对象,并把地址值赋值给引用s2
- 此时通过s2引用改变堆内存中Book对象name的值(堆内存中只有一个Book类型的对象),Math被Chinese覆盖
- 此时该Book类型的对象共有三个引用指向它,如图所示
- 当我们再次通过s1的引用访问该Book对象的name值时,打印出来的自然是Chinese
需要注意的是:Book对象自始至终只有一个,s2中b克隆的只是s1中b的地址值,Book对象不会再被克隆一份

889

被折叠的 条评论
为什么被折叠?



