常用类
1. Object类中的方法:
相对路径:将该项目作为根目录(com.shujia.wyh.day13.changyonglei.Student)
绝对路径/完整路径:带上盘符(D:\IdeaProjects\bigdata15\src\com\shujia\wyh\day13\changyonglei\Student.java)
Object:Class Object是类Object结构的根。 每个类都有Object作为超类。所有对象(包括数组)都实现了这个类的方法。 java中每个类都直接或者间接的继承了Object类
2.hashCode()和getClass() 方法
public int hashCode()返回对象的哈希码值。
支持这种方法是为了散列表,如HashMap提供的那样。
注意:这里的哈希码值是根据哈希算法计算出来的一个值。这个值和地址有关系,但是这里返回的地址值并不是实际的地址值
你们现在就简单理解为地址值的另外一种表现形式。
public final Class getClass()
//返回的是该对象的类对象
返回此Object的运行时类。 返回的类对象是被表示类的static synchronized方法锁定的对象。
举例:
public class ChangYongDemo11 {
public static void main(String[] args) {
ChangYongDemo11 c1=new ChangYongDemo11();
ChangYongDemo11 c2=new ChangYongDemo11();
ChangYongDemo11 c3=c1;
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c1.getClass());
System.out.println(c2.getClass());
System.out.println(c3.getClass());
}
}
结果:
3.toString()方法
(1) public String toString()返回对象的字符串表示形式。
一般来说, toString方法返回一个“textually代表”这个对象的字符串。
结果应该是一个简明扼要的表达,容易让人阅读。 建议所有子类覆盖此方法。
该toString类方法Object返回一个由其中的对象是一个实例,该符号字符`的类的名称的字符串@ ”和对象的哈希码的无符号的十六进制表示。 换句话说,这个方法返回一个等于下列值的字符串:
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
(2)
Integer:
public static String toHexString(int i)
返回整数参数的字符串表示形式,作为16位中的无符号整数。 将哈希值转化一个地址值。
我们虽然掌握了toString()的方法使用,但是呢打印的一个结果是一个我们看不懂的地址值,换句话我们拿到这个结果没有意义
返回对象的字符串表示形式,实际上我们更想去看的是该对象中各个成员变量的值。
恰好toString()方法是被public修饰的,也恰好它的返回值是String类型的,所以我们可以在其他类中对它做重写
今后无特殊情况不需要自己手写,自动生成即可。
一个标准类的4.0版本:
成员变量:使用private关键字修饰
构造方法:一个无参。一个带所有参数的方法。
成员方法:setXxx(…)/getXxx()
toString():自动生成即可,替代掉我们之前show方法。
举例:
public class ChangYongDemo12 {
public static void main(String[] args) {
Student1 s=new Student1("小王",25);
System.out.println(s.toString());
}
}
class Student1 extends Object{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student1(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {//重写toString方法
return "Student1{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
结果:
4.equals()方法
public boolean equals(Object obj)指示一些其他对象是否等于此。
今后我们想要弄清楚一个方法的实现的时候,想要弄明白结果是为什么的时候,看源码
将鼠标光标放置要看的方法上,按下ctrl+鼠标左键查看源码
通过观察源码发现:Object类中的equals方法实现底层依旧是==
public boolean equals(Object obj) {
return (this == obj);
}
而==比较引用数据类型的时候,比较是地址值,当地址值不一样的时候,返回的是false
==:
基本数据类型的时候:比较的是两个值是否一样
引用数据类型的时候:比较的是两个对象的地址值是否一样
equals:只能比较的引用数据类型
实际开发的时候,调用equals方法更希望它比较的是成员变量的值是否一样
所以我们应该在子类中进行重写
不需要我们自己动手,自动生成即可
总结:
子类若是没有重写equals方法,使用的是父类Object类中的方法,比较的是地址值。
子类要是重写了equals方法,比较的是成员变量值是否相同。
(2)比较地址值的情况
public class ChangYongDemo13 {
public static void main(String[] args) {
Teacher t1=new Teacher("小红",19);
Teacher t2=new Teacher("小红",19);
Teacher t3=new Teacher("小明",20);
Teacher t4=t1;
System.out.println(t1.equals(t2));//false
System.out.println(t1.equals(t3));//false
System.out.println(t1.equals(t4));//true
System.out.println(t2.equals(t3));//false
}
}
class Teacher extends Object{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
结果:
(2)重写equals()方法的情况比较的是具体的内容
equals:只能比较的引用数据类型
实际开发的时候,调用equals方法更希望它比较的是成员变量的值是否一样
所以我们应该在子类中进行重写
不需要我们自己动手,自动生成即可
总结:
子类若是没有重写equals方法,使用的是父类Object类中的方法,比较的是地址值。
子类要是重写了equals方法,比较的是成员变量值是否相同。
public class ChangYongDemo14 {
public static void main(String[] args) {
Person1 p1=new Person1("网民",25);
Person1 p2=new Person1("网民",25);
Person1 p3=new Person1("算法",23);
Person1 p4=p1;
System.out.println(p1.equals(p2));//true
System.out.println(p1.equals(p3));//false
System.out.println(p1.equals(p4));//true
System.out.println(p3.equals(p4));//false
}
}
class Person1{
private String name;
private int age;
public Person1(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override//equals方法的重写
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person1 person1 = (Person1) o;
return age == person1.age && Objects.equals(name, person1.name);
}
}
结果:
5.clone()方法(重点)
protected Object clone() 创建并返回此对象的副本。
执行特定的克隆工作。
其他包中的子类要想使用被protected修饰的方法,使用super关键字调用。
clone的方法Object执行特定的克隆操作。
首先,如果此对象的类不实现接口Cloneable ,则抛出CloneNotSupportedException 。
一个类要想使用clone(),就必须实现Cloneable接口
通过观察API发现,Cloneable接口中没有常量,也没有抽象方法
今后看到类似于Cloneable一样,里面什么都没有的接口,我们称之为标记接口。
举例(重点):
public class ChangYongDemo15 {
public static void main(String[] args) throws
CloneNotSupportedException { //1.此地方要抛出异常
Demo demo=new Demo();
Person3 p1=new Person3("小兰",19,demo);
//这里其实隐含了一个多态
Object p2=p1.clone();
//1.
System.out.println(p1.toString());
//Person3{name='小兰', age=19, demo='com.shujia.wyh.
//day02.day13.Demo@4554617c'}
System.out.println(p2.toString());
//Person3{name='小兰', age=19, demo='com.shujia.wyh.day02.
//day13.Demo@4554617c'}
//此时打印出来的内容是一样的
//2.拷贝前的demo与拷贝后demo的地址值做比较
//发现demo地址值是一样的,
System.out.println(p1.getDemo().hashCode());
//1163157884
/*由于Object类中没有demo对象,所以不能用p2直接去调用,
因此需要向下转型才能调用*/
Person3 p3=(Person3) p2;
System.out.println(p3.getDemo().hashCode());
//1163157884
//3.拷贝前整体对象的地址值与拷贝后整体对象的地址值
// 发现拷贝后的地址值与原来对象的地址值不一样
System.out.println(p1.hashCode());//1956725890
System.out.println(p2.hashCode());//356573597
//最终证明克隆是一个浅拷贝的
}
}
class Demo{}
class Person3 extends Object implements Cloneable{//此类要实现克隆接口标记,从而说明这个类是可以被克隆的
private String name;
private int age;
private Demo demo;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Demo getDemo() {
return demo;
}
public void setDemo(Demo demo) {
this.demo = demo;
}
public Person3(String name, int age, Demo demo) {
this.name = name;
this.age = age;
this.demo = demo;
}
@Override
public String toString() {
return "Person3{" +
"name='" + name + '\'' +
", age=" + age +
", demo='" + demo + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person3 person3 = (Person3) o;
return age == person3.age && Objects.equals(name, person3.name) && Objects.equals(demo, person3.demo);
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
**结果:
protected void finalize():
当垃圾收集确定不再有对该对象的引用时,垃圾收集器在对象上调用该对象。
一个子类覆盖了处理系统资源或执行其他清理的finalize方法。
你们就简单理解这个方法为用于垃圾回收的,什么时候回收,不确定
GC机制,标记法。
浅拷贝和浅拷贝(重点)
拷贝在IT行业中常见两种:
浅拷贝:
浅拷贝是指我们拷贝出来的对象的内部引用类型变量和原来的对象内部引用类型变量的地址值是一样的(指向的是同一个对象)
但是整个拷贝出来的对象和新对象不是同一个地址值。
浅拷贝::
全部拷贝对象的内容,包括内存的引用类型也进行拷贝,拷贝的时候,重新创建一个对象,成员变量值和原来被拷贝的一样。
但是后续再对拷贝后的引用数据类型变量做修改,不会影响到原来被拷贝的。
浅拷贝:
深拷贝:
最终证明克隆是一个浅拷贝的