源码及API文档概述及toString和equals知识点总结
1.JDK类库的根类:Object
1.1、这个老祖宗类中的方法我们需要先研究一下,因为这些方法都是所有子类通用的。
任何一个类默认继承Object。就算没有直接继承,最终也会间接继承。
1.2、Object类当中有哪些常用的方法?
我们去哪里找这些方法呢?
第一种方法:去源代码当中。(但是这种方式比较麻烦,源代码也比较难)
第二种方法:去查阅java的类库的帮助文档。
什么是API?
应用程序编程接口。(Application Program Interface)
整个JDK的类库就是一个javase的API。
每一个API都会配置一套API帮助文档。
SUN公司提前写好的这套类库就是API。(一般每一份API都对应一份API帮助文档。)
目前为止我们只需要知道这几个方法即可:
protected Object clone() //负责对象克隆的
int hashCode() //获取对象的哈希值的一个方法
boolean equals(Object obj) //判断两个对象是否相等
String toString() //将对象转换成字符串形式
protected void finalize() //垃圾回收器负责调用的方法
1.3、toString()方法
以后所有类的toString()方法是需要重写的。
重写规则:越简单越明了就好。
System.out.println(引用);这里会自动调用"引用"的toString()方法
String类是SUN写的,toString方法已经重写了。
1.4、equals()方法
以后所有类的equals方法也需要重写,因为Object中的equals方法比较
的是两个对象的内存地址,我们应该比较内容,所以需要重写。
重写规则:自己定,主要看什么和什么相等时表示两个对象相等。
基本数据类型比较时使用:==
对象和对象比较:调用equals方法
String类是SUN编写的,所以String类的equals方法重写了。
以后判断两个字符串是否相等,最好不要使用==,要调用字符串对象的equals方法
Object类中的toString方法及重写toString
package com.bjpowernode.javase.test001;
/**
关于Object中的toString()方法
1、源代码
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
源代码上toString()方法的默认实现是:
类名@对象的内存地址转换为十六进制的形式
2、toString()方法的作用是什么?
toString()方法的设计目的是:通过调用这个方法可以将一个"java对象"转换成“字符串表示形式”
3、其实SUN公司开发java语言的时候,建议所有的子类都去重写toString()方法。
toString()方法应该是一个简洁的、详实的、易阅读的。
*/
public class Test01 {
public static void main(String[] args) {
MyTime t1 = new MyTime(1970,1,1);
String s1 = t1.toString();
//MyTime类重写toString()方法之前
//System.out.println(s1);//com.bjpowernode.javase.test001.MyTime@15db9742
//MyTime类重写toString()方法之后
System.out.println(s1);//1970年1月1日
//注意:输出引用的时候,会自动调用该引用的toString()方法。
System.out.println(t1);
}
}
class MyTime{
int year;
int month;
int day;
public MyTime() {
super();
}
public MyTime(int year, int month, int day) {
super();
this.year = year;
this.month = month;
this.day = day;
}
//重写toString()方法
//方向:简洁的、详实的、易阅读的
public String toString() {
//return this.year + "年" + this.month + "月" + this.day + "日";
return this.year + "/" + this.month + "/" + this.day;
}
}
Object类中的equals方法及重写equal
package com.bjpowernode.javase.test001;
/**
关于Object类中的equals()方法
1、equals方法的源代码
public boolean equals(Object obj) {
return (this == obj);
}
以上这个方法是Object类的默认实现。
2、equals()方法的作用是什么?
以后编程的过程当中,都要通过equals方法来判断两个对象是否相等。
equals方法是判断两个对象是否相等的。
3、我们需要研究一下Object类给的这个默认的equals方法够不够用!!!
在Object类中的equals方法当中,默认采用的是"=="判断两个java对象是否相等。而
"=="判断的是两个java对象的内存地址,我们应该判断两个java对象的内容是否相等。所以
老祖宗的equals方法不够用,需要子类重写equals。
4、判断两个java对象是否相等,不能使用"==",因为"=="比较的是两个对象的内存地址。
*/
public class Test02 {
public static void main(String[] args) {
//判断两个基本数据类型的数据是否相等,直接使用"=="就行。
int a = 100;
int b = 100;
System.out.println(a == b);//true
//判断两个java对象是否相等,我们怎么办?能直接使用"=="吗
//创建了一个日期对象是:2008年8月8日。
MyTime2 t1 = new MyTime2(2008,8,8);
//创建了一个新的日期对象,但表示的日期也是2008年8月8日。
MyTime2 t2 = new MyTime2(2008,8,8);
//测试下,比较两个对象是否相等,能不能使用"=="??
//这里的"=="判断的是t1保存的对象内存地址和t2中保存的对象内存地址是否相等
System.out.println(t1 == t2);//false
//未重写equals()之前(比较的是对象的内存地址)
boolean flag = t1.equals(t2);
//System.out.println(flag);//false
//重写equals()之后(比较的是对象的内容)
System.out.println(flag);//true
//再创建一个新的日期
MyTime2 t3 = new MyTime2(2008,8,9);
System.out.println(t1.equals(t3));//false
//我们这个程序有bug吗?可以运行,但是效率怎么样?低(怎么改造。)
MyTime2 t4 = null;
System.out.println(t1.equals(t4));//false
}
}
class MyTime2{
int year;
int month;
int day;
public MyTime2() {
super();
}
public MyTime2(int year, int month, int day) {
super();
this.year = year;
this.month = month;
this.day = day;
}
// public boolean equals(Object obj) {
// return (this == obj);
// }
/*
//重写equals()
//需要自己定,看具体的业务。
public boolean equals(Object obj) {
//当年、月、日都相等的时候,日期就相等,两个对象就相等
//获取第一个日期的年月日
int year1 = this.year;
int month1 = this.month;
int day1 = this.day;
//获取第二个日期的年月日
//Object类中没有year、month、day属性
//int year1 = obj.year;
//int month1 = obj.month;
//int day1 = obj.day;
//当调用的属性是子类中特有的,父类中没有,需要进行向下转型。
if(obj instanceof MyTime2) {
MyTime2 t = (MyTime2)obj;
int year2 = t.year;
int month2 = t.month;
int day2 = t.day;
if(year1 == year2 && month1 == month2 && day1 == day2) {
return true;
}
}
return false;
}
*/
//改良
/*
public boolean equals(Object obj) {
//如果obj是空,直接返回false
if(obj == null) {
return false;
}
//如果obj不是一个MyTime2,没必要比较了,直接返回false
if(!(obj instanceof MyTime2)) {
return false;
}
//如果this和obj保存的内存地址相同,没必要比较了,直接返回true。
if(this == obj) {
return true;
}
//程序能够致执行到此处说明什么?
//说明obj不是null,obj是MyTime2类型。
MyTime2 t =(MyTime2)obj;
if(this.year == t.year && this.month == t.month && this.day == t.day) {
return true;
}
//程序执行到这里返回false
return false;
}
*/
//再次改良
// public boolean equals(Object obj) {
// if(obj == null || !(obj instanceof MyTime2)) {
// return false;
// }
// if(this == obj) {
// return true;
// }
// MyTime2 t =(MyTime2)obj;
// return this.year == t.year && this.month == t.month && this.day == t.day;
// }
}
String类中的toString方法和equals方法
package com.bjpowernode.javase.test001;
/**
java语言当中的字符串String有没有重写toString方法,有没有重写equals方法
总结:
1、String类已经重写了equals方法,比较两个字符串不能使用==,必须使用equals。equals是通用的。
2、String类已经重写了toString方法。
大结论:
java中什么类型的数据可以使用"=="判断
java中基本数据类型比较是否相等,使用==。
java中什么类型的数据需要使用equals判断
java中所有的引用数据类型统一使用equals方法来判断是否相等。
这是规矩。
*/
public class Test03 {
public static void main(String[] args) {
//大部分情况下,采用这样的方式创建字符串对象
String s1 = "hello";
String s2 = "abs";
//实际上String也是一个类,不属于基本数据类型
//既然String是一个类,那么一定存在构造方法。
String s3 = new String("Test1");
String s4 = new String("Test1");
//new两次,两个对象内存地址,s3保存的内存地址和s4保存的内存地址不同。
//"=="判断的是内存地址。不是内容。
System.out.println(s3 == s4);//false
//比较两个字符串能不能用"=="?
//不能,必须调用equals()
//String类已经重写了equals方法
System.out.println(s3.equals(s4));//true
//String类有没有重写toString方法呢?
String x = new String("动力节点");
//如果String类没有重写toString方法,输出结果:java.lang.String@十六进制的地址
//经过测试:String类已经重写toString()方法
System.out.println(x.toString());//动力节点
System.out.println(x);//动力节点
}
}
练习
package com.bjpowernode.javase.test001;
//String对象比较的时候必须使用equals方法
public class Test04 {
public static void main(String[] args) {
/*
Student s1 = new Student(111,"北京市");
Student s2 = new Student(111,"北京市");
System.out.println(s1 == s2);//false
System.out.println(s1.equals(s2));//true
*/
Student s1 = new Student(111,new String("北京市"));
Student s2 = new Student(111,new String("北京市"));
System.out.println(s1 == s2);//false
System.out.println(s1.equals(s2));//true
}
}
class Student{
int no;//基本数据类型,比较时采用==
String school;//引用数据类型,比较时采用equals
public Student() {
}
public Student(int no, String school) {
this.no = no;
this.school = school;
}
//重写toString方法
public String toString() {
return "学号" + no + ",所在学校名称" + school;
}
//重写equals方法
//equals方法的编写模式都是固定的,架子差不多。
public boolean equals(Object obj) {
if(obj == null || !(obj instanceof Student)) return false;
if(this == obj) return true;
Student s = (Student)obj;
return this.no == s.no && this.school.equals(s.school);
//字符串用双等号比较可以吗?
//不可以
//return this.no == s.no && this.school == s.school;
}
}
equals方法深究
package com.bjpowernode.javase.test001;
//equals方法重写要彻底
public class Test05 {
public static void main(String[] args) {
User u1 = new User("zhangsan",new Address("北京","大兴区","11111"));
User u2 = new User("zhangsan",new Address("北京","大兴区","11111"));
System.out.println(u1.equals(u2));//true
User u3 = new User("zhangsan",new Address("北京","朝阳区","11111"));
System.out.println(u1.equals(u3));//false
}
}
class User{
//用户名
String name;
//用户住址
Address addr;
public User() {
super();
}
public User(String name, Address addr) {
super();
this.name = name;
this.addr = addr;
}
//重写equals方法
//重写规则:当一个用户的用户名和家庭地址都相同,表示同一个用户。
public boolean equals(Object obj) {
if(obj == null || !(obj instanceof User)) return false;
if(this == obj) return true;
User u = (User)obj;
if(this.name.equals(u.name) && this.addr.equals(u.addr)) return true;
return false;
}
}
class Address{
String city;
String street;
String zipcode;
public Address() {
super();
}
public Address(String city, String street, String zipcode) {
super();
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
//重写equals方法
public boolean equals(Object obj) {
if(obj == null || !(obj instanceof Address)) return false;
if(this == obj) return true;
Address a = (Address)obj;
if(this.city.equals(a.city) && this.street.equals(a.street) && this.zipcode.equals(a.zipcode)) return true;
return false;
}
}
finalize()方法
package com.bjpowernode.javase.test001;
/**
关于Object类中的finalize()方法(非重点,了解即可)
1、在Object类中的源代码:
protected void finalize() throws Throwable { }
2、finalize()方法只有一个方法体,里面没有代码,而且这个方法是protected修饰的。
3、这个方法不需要程序员手动调用,JVM的垃圾回收器负责调用这个方法。
4、finalize()方法的执行时机:
当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用
finalize()方法。
5、finalize()方法实际上是SUN公司为java程序员准备的一个时机,垃圾销毁时机。
如果希望在对象销毁时机执行一段代码的话,这段代码要写到finalize()方法当中。
6、静态代码块的作用是什么?
static{
....
}
静态代码块在类加载时刻执行,并且只执行一次。
这是一个SUN准备的类加载时机。
finalize()方法同样也是SUN为程序员准备的一个时机。
这个时机是垃圾回收时机。
7、提示:java中的垃圾回收器不是轻易启动的,
垃圾太少,或者时间没到,种种条件下,有可能启动,
也有可能不启动。
*/
public class Test06 {
public static void main(String[] args) {
/*
Person p = new Person();
//怎么把Person对象变成垃圾?
p = null;
*/
//多造点垃圾
/*
for(int i = 0;i <= 10000000;i ++)
{
Person p = new Person();
p = null;
}
*/
//有一段代码建议启动垃圾回收器
for(int i=0;i<=1000;i++)
{
Person p = new Person();
p = null;
System.gc();//只是建议,可能不启动
}
}
}
//项目开发中有这样的业务需求:所有对象在JVM中被释放的时候,请记录一下释放时间!!!
//记录对象被释放的时间点,这个负责记录的代码写到哪里?
//写到finalize()方法中。
class Person{
//重写finalize()方法
//Person类型的对象被垃圾回收器回收的时候,垃圾回收器负责调用:p.finalize();
protected void finalize() throws Throwable {
//this代表当前对象
System.out.println(this + "即将被销毁!");
}
}
hashCode方法
package com.bjpowernode.javase.test001;
/**
hashCode方法:(非重点,了解即可)
在Object类中hashCode()方法是怎样的?
public native int hashCode();
这个方法不是抽象方法,带有native关键字,底层调用c++程序。
hashCode()方法返回的是哈希码:
实际上就是一个java对象的内存地址,经过哈希算法,得出的一个值。
所以hashCode()方法的执行结果可以等同看做一个java对象的内存地址。
*/
public class Test07 {
public static void main(String[] args) {
Object o = new Object();
//对象内存地址经过哈希算法转换的一个数字,可以等同看做内存地址。
int hashCodeValue = o.hashCode();
System.out.println(hashCodeValue);
MyClass mc = new MyClass();
int hashCodeValue2 = mc.hashCode();
System.out.println(hashCodeValue2);
}
}
class MyClass{
}
匿名内部类
package com.bjpowernode.javase.test002;
/**
匿名内部类:
1、什么是内部类?
内部类:在类的内部又定义了一个新的类,被称为内部类。
2、内部类的分类:
静态内部类:类似于静态变量
实例内部类:类似于实例变量
局部内部类:类似于局部变量
3、使用内部类编写的代码,可读性很差,能不用尽量不用。
4、匿名内部类是局部内部类的一种,因为这个类没有名字而得名,叫做匿名内部类。
5、学习匿名内部类主要是让大家以后在阅读别人代码的时候,能够理解。
并不代表以后都要这样写。因为匿名内部类有两个缺点:
缺点1:太复杂,太乱,可读性差。
缺点2:类没有名字,以后想重复使用,不能用。
6、记忆即可
*/
public class Test01 {
//静态变量
static String country;
//该类在类的内部,所以称为内部类
//由于前面有static,所以称为"静态内部类"
static class Inner1{
}
//实例变量
int age;
//该类在类的内部,所以称为内部类
//没有static叫做实例内部类
class Inner2{
}
public void doSome(){
//局部变量
String name;
//该类在类的内部,所以称为内部类
//局部内部类
class Inner3{
}
}
public void doOther() {
//doSome()方法中的局部内部类Inner3,在doOther()中不能用。
}
//main方法,入口
public static void main(String[] args) {
// 调用MyMath中的mySum方法。
MyMath mm = new MyMath();
/*
Compute c = new ComputeImpl();
mm.mySum(c, 100, 200);*/
//合并(这样写代码,表示这个类名是有的。类名是:ComputeImpl)
//mm.mySum(new ComputeImpl(), 100, 200);
// 使用匿名内部类,表示这个ComputeImpl类没名字了。
// 这里表明看上去好像是接口可以直接new了,实际上并不是接口可以new了。
// 后面的{}代表了对接口的实现。
// 不建议使用匿名内部类,为什么?
// 因为一个类没有名字,没有办法重复使用。另外代码太乱,可读性太差。
mm.mySum(new Compute() {
public int sum(int a, int b) {
return a + b;
}
}, 200, 300);
}
}
//负责计算接口
interface Compute{
//抽象方法
int sum(int a,int b);
}
//你自动会在这里编写一个Compute接口的实现类
/*
//使用匿名内部类以后,可以省略ComputeImpl类的编写
class ComputeImpl implements Compute{
//对方法的实现
public int sum(int a, int b) {
return a + b;
}
}
*/
//数学类
class MyMath{
//数学求和方法
public void mySum(Compute c,int x,int y) {
int retValue = c.sum(x,y);
System.out.println(x + "+" + y + "=" + retValue);
}
}
版权声明:本文为weixin_43636084原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。