虽然csdn账号注册的久,但是很少进来,也第一次发博客,因为本人比较菜目前还在学习中是一名学生,今天看了一下学习视频有一点小小的体会,权当日记了,若有大佬路过,还望不吝赐教。
1.什么是Object类
在我的理解里面Object类就类似于山顶洞人一样的存在——人类的祖先,把我们不同时期甚至是不同的人都看成是一个个类,而山顶洞人就是我们所有人共同的父类,我们都有他的特征,经过不断地进化及各种因素的影响,成了不同的人,也有了区别于祖先不同的特征(属性与方法)等。
2.常用的几种方法(不全,暂挑相对重要的讲)
Stundent类:(常规操作,可跳过)
class Student {
private String name;
private int age;
public Student() {
super();
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", 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;
}
}
(1) xxx.getclass( )
getclass( )方法是获取该对象所对应类型,是一个本地方法(native,可以查看源码),控制台中输出的是完全限定名,也就是(包路径+类名),也是后面会学的反射获取对象的其中一种方法。示例如下:
public static void main(String[] args) {
Student stu1 =new Student("小叶",22);
System.out.println(stu1.getClass());
}
控制台输出如下:
(2)xxx.hashcode( )
hashcode()方法也就是获取改对象的散列码,是根据物理地址的值,通过一系列的运算得到的,这是本地的方法,具体的运算细则,小叶也不太清楚,还望大佬点出。在我们new出一个对象时,就会产生一个hash值,hash值不一样,一定不会为同一对象,但是hash值一样,不一定为同一对象。
后半句怎么解释呢,因为我们自定义一个类还未重写本方法时,其对象在调用此方法时,仍是Object本身的方法。定义的类身为它的子类,是可以在类当中重写hashcode方法的,ecplise快捷键(shift+alt+s)就可以找到。同样的类中,给其不同对象赋予同样的值时,会导致hash值一样,这是因为不会像Object中此方法一样根据物理地址的值,而是会给你一个方法,根据其方法计算出hash值(也可以自己编写,这里只是讲重写),Student中的name属性是String类,String类就已经重写过hashcode()方法,在下面实例中可以看到一点,重写前后对比的代码及输出如下:
重写前代码:
public static void main(String[] args) {
Student stu1 =new Student("小叶",22);
Student stu2 =new Student("小叶",22);
System.out.println(stu1.hashCode());
System.out.println(stu2.hashCode());
}
输出为:
重写后的在Student类中的hashcode()方法代码为:
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
输出为:
(3)xxx.equals( )
equals( )方法是用来判断两个对象是否为同一对象的方法,此方法为java提供的方法,并非本地方法,与hashcode( )方法相似的地方则是都需要在类里通过重写Object类方法来达到equals()方法的特定功能。
在未重写之前和 == 的作用是一样的,是判断两个对象的地址是否相同,而equals()方法应该是判断两个对象的内容是否一样,和hashcode()方法一样,自定义的类若要达到功能需求,需要与其他类一样(如:String类),进行方法的重写,重写前后对比的代码及输出如下:
重写前代码:
public static void main(String[] args) {
Student stu1 =new Student("小叶",22);
Student stu2 =new Student("小叶",22);
System.out.println(stu1.equals(stu2));
System.out.println(stu1==stu2);
}
输出:
重写后的equals()方法代码:
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
若有读不懂重写后的方法的小伙伴可以留言喔!这里就不过多注释啦
public static void main(String[] args) {
Student stu1 =new Student("小叶",22);
Student stu2 =new Student("小叶",22);
System.out.println(stu1.equals(stu2));
System.out.println(stu1==stu2);
}
输出:
(4)xxx.clone( )
clone也就是克隆的意思,clone( )方法就是做对象的复制的,并非赋值,对象直接赋值想要完成复制功能的是错误的,若改变被赋值的对象中的属性,赋值对象的属性也会随着改变,代码及输出如下:
public static void main(String[] args) {
Student stu3 =new Student("小叶",22);
//赋值并非复制
Student stu4 =stu3.clone();
stu4.setAge(10);
System.out.println(stu3);
System.out.println(stu4);
}
输出:
原因:赋值是栈里面的赋值,堆里面只有一个对象数据,当改变对象数据时,栈里面同样地址的对象都会随其改变,因为他们共用这一份数据。
复制又分为深复制与浅复制,让我们浅谈一下两种复制的区别以及复制的内容有哪些
A.浅复制(只能复制基本数据类型,引用类型仍然共用)
因为clone方法本身为protected访问修饰符修饰的方法,只能被自身、同包、及其子类访问,所以不能再Test类中的main方法中直接调用,而应该到其子类Student类中去调用,且如果想在类外部也能调用这个方法,只能进行重写,还应该扩大访问范围,也就是将protected重写为public,如下代码所示:
public Student clone() {
Student s =null;
try {
s= (Student)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return s;
}
在重写中返回值类型可以为父类的子类,也就是说可以为Student类,而为什么要调用super是因为Object类中的clone()方法可以实现其功能,不需要进行功能重写,而s对象为Student类,所以要进行一次强转,这样就能将调用对象复制一份,再通过上述代码赋值给新对象,完成复制。
还没完,不仅仅重写方法,还要去实现此方法的标记接口Cloneable,要声明此类中可以被克隆,如图所示
这样就能完成克隆了,输出如下:
B.深复制(将引用类型重新复制一次)
若引进一个引用类型的数据,将会无法复制其数据,因为对于基本数据类型的对象来说又是一个新的对象数据,他们将会共用此对象数据(又是一次浅复制),当此对象数据发生改变时候,对应的所有对象的该数据都会发生改变。如下图所示:
引入一个Address类:
class Address{
String add;
int number;
public Address(String add, int number) {
super();
this.add = add;
this.number = number;
}
@Override
public String toString() {
return "Adress [add=" + add + ", number=" + number + "]";
}
}
代码为:
public static void main(String[] args) {
Student stu3 =new Student("小叶",22,new Address("地球村",001));
//赋值并非复制
Student stu4 =stu3.clone();
stu4.setAge(10);
stu4.address.add=("月球村");
System.out.println(stu3);
System.out.println(stu4);
}
输出为:
如何实现深复制,和浅复制同样的原理,在进行一次,将Address类实现克隆接口(不再展示),再次重写克隆方法即可,如下代码所示:
public Address clone() {
Address a =null;
try {
a=(Address)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return a;
}
输出为: