本文共 11988 字,大约阅读时间需要 39 分钟。
应用程序编程接口(Application Programming Interface)
整个JDK的类库就是一个javase的API
SUN公司提前写好的这套类库就是API(一般每一份API都对应一份帮助文档)注意:每一个API都会配置一套API帮助文档
方法 | 作用 |
---|---|
protected Object clone() | 负责对象克隆的 |
int hashCode() | 获取对象哈希值的一个方法 |
boolean equals(Object obj) | 判断两个对象是否相等 |
String toString() | 将对象转换成字符串形式 |
protected void finalize() | 垃圾回收器负责调用的方法 |
源代码长什么样?
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
源代码上toString()方法的默认实现是:
类名@对象的内存地址转换为十六进制的形式
Sun公司设计toString()方法的目的是什么?
public class Test01 { /* 源代码长什么样? public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } 源代码上toString()方法的默认实现是: 类名@对象的内存地址转换为十六进制的形式 */ public static void main(String[] args) { MyTime t1 = new MyTime(1970,1,1); //一个日期对象转换成字符串形式的话,我可能还是希望能看到具体的日期信息 String s1 = t1.toString(); //MyTime类重写toString()方法之前 System.out.println(s1); //com.Object类.MyTime@4f023edb //MyTime类重写toString()方法之后 System.out.println(s1.toString()); //1970年1月1日 //同理,输出引用的时候会自动调用该引用的toString()方法 System.out.println(s1); //1970年1月1日 }}class MyTime{ int year; int month; int day; public MyTime(){ } public MyTime(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } //重写toString()方法,越简洁越好,可读性越强越好 public String toString(){ return this.year + "年" + this.month + "月" + this.day + "日"; }}
equals方法的源代码
public boolean equals(Object obj) { return (this == obj); }
Sun公司设计equals方法的目的是?
public class Test02 { /* 1. equals方法的源代码 public boolean equals(Object obj) { return (this == obj); } 以上这个方法是Object类的默认实现 2. Sun公司设计equals方法的目的是? 以后编程的过程当中,都要通过equals方法来判断两个对象是否相等 equals方法是判断两个对象是否相等*/ public static void main(String[] args) { //判断两个基本数据类型的数据是否相等,直接使用==就行 int a = 100; int b = 100; System.out.println(a==b); //true //创建一个日期对象是:2020年8月8日 MyTime2 t1 = new MyTime2(2020,8,8); //创建一个新的日期对象,日期也是:2020年8月8日 MyTime2 t2 = new MyTime2(2020,8,8); //判断两个java对象是否相等,我们使用==的话 //表示比较的是:t1中保存的对象内存地址和t2中保存的对象内存地址是否相等 System.out.println(t1 == t2); //false //重写Object对象之前(比较的是对象内存地址) //System.out.println(t1.equals(t2)); //false //重写Object对象之后(比较的是内容) System.out.println(t1.equals(t2)); //true //我们程序有bug,可以运行,但是效率特别低 MyTime2 t3 = null; System.out.println(t1.equals(t3)); //false }}class MyTime2 { //extends Object int year; int month; int day; public MyTime2(){ } public MyTime2(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } /* Object类中默认存在 public boolean equals(Object obj) { return (this == obj); } */ //重写Object类中的equals方法 //至于怎么重写,自己定,认为两个对象什么相等的时候表示相等 /* public boolean equals(Object obj) { if(obj instanceof MyTime2){ MyTime2 t = (MyTime2)obj; if(this.year == t.year && this.month == t.month && this.day == t.day){ return true; } } return false; } */ //改良equals方法 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一定是MyTime2类型 MyTime2 t = (MyTime2)obj; return this.year == t.year && this.month == t.month && this.day == t.day; }}
总结:
public class Test03 { public static void main(String[] args) { //大部分情况下,采用这样的方式创建字符串对象 String s1 = "hello"; String s2 = "hello"; //实际上String也是一个类,不属于基本数据类型 //既然String是一个类,那么一定存在构造方法 String s3 = new String("Test1"); String s4 = new String("Test1"); //new两次,两个对象内存地址,==判断的是内存地址,不是内容 System.out.println(s3 == s4); //false System.out.println(s1 == s2); //true //比较两个字符串必须使用equals,String类已经重写了equals方法了 System.out.println(s3.equals(s4)); //true System.out.println(s1.equals(s2)); //true //String类也重写了toString方法了 String x = new String("pudding"); System.out.println(x.toString()); //pudding System.out.println(x); //pudding }}
public class Test04 { public static void main(String[] args) { //这样写的话以下的两种方式都是true和false,因为这里的字符串 /* Student s1 = new Student(111,"xingzhi"); Student s2 = new Student(111,"xingzhi"); System.out.println(s1.equals(s2)); //true System.out.println(s1 == s2); //false */ Student s1 = new Student(111,new String("xingzhi")); Student s2 = new Student(111,new String("xingzhi")); System.out.println(s1.equals(s2)); //true System.out.println(s1 == s2); //false }}class Student{ //学号 int no; //基本数据类型,比较时使用== //所在学校 String school; //引用数据类型,比较时使用:equals方法 public Student() { } public Student(int no, String school) { this.no = no; this.school = school; } //重写toString方法 public String toSting(){ 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; //方法一: /* //这样写的话,上面通过equals比较就会出现错误 if (s.no == this.no && s.school == this.school){ return true; } */ //方法二: if (s.no == this.no && s.school.equals(this.school)){ return true; } return false; }}
由于只是重写了User类里面的equals()方法,没有将Address类里面的equals()方法重写,会让我们的规则:当一个用户的用户名和家庭住址相同,不能表示同一个用户。因为Address中的equals方法仍然是继承Object类中的equals方法。
所以我们必须也将Address类中的equals方法也重写,重写equals方法彻底。结果如下
public class Test05 { public static void main(String[] args) { Address a1 = new Address("HF","YHQ","1111"); Address a2 = new Address("HF","YHQ","1111"); User u1 = new User("pudding",a1); User u2 = new User("pudding",a2); System.out.println(u1.equals(u2)); //true }}class User{ String name; Address addr; public User() { } public User(String name, Address addr) { this.name = name; this.addr = addr; } //重写equals()方法 //重写规则:当一个用户的用户名和家庭住址相同,表示同一个用户 //这个equals判断的是User对象和User对象是否相等//Object obj = u2[new User("pudding",a2)]; 这是一个多态(父类型引用指向子类型是自动类型转换) public boolean equals(Object obj){ if (obj == null || !(obj instanceof User)) return false; if (this == obj) return true; User u = (User)obj; //this.name.equals表示调用String类型的equals()方法,String类型默认重写了equals方法 //this.addr.equals表示调用Address类型的equals()方法,Address类型没有重写equals方法, //执行默认Object类型的equals方法,比较的仍然是对象的内存地址 //因为主方法中new了两个对象a1和a2所以这个this.addr.equals(u.addr)一定是false //姓名相同,地址相同表示同一个用户 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() { } public Address(String city, String street, String zipcode) { this.city = city; this.street = street; this.zipcode = zipcode; } //注意:这里并没有重写equals方法 //这里的equals方法判断的是:Address对象和Address对象是否相等 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; }}
概述:
这个方法是protected修饰的,在Object类中这个方法源代码是
protected void finalize() throws Throwable { }
finalize()方法只有一个方法体,里面没有代码,而且这个方法是protected修饰的
这个方法不需要程序员手动调用,JVM的垃圾回收器负责调用这个方法。不像equals、toString方法,它们是需要你写代码再调用,而finalize方法只需要重写,重写完成将来GC会自动调用
finalize()方法执行时机:当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用finalize()方法
finalize()方法实际上是Sun公司为java程序员准备的一个时机,垃圾销毁时机。如果希望在对象销毁时机执行一段代码的话,这段代码要写到finalize()方法当中。
类似静态代码作用
static{ ... } 静态代码块在类加载的时刻执行,并且只执行一次 这是一个SUN准备的类加载时机.
注意:
public class Test06 { public static void main(String[] args) { /* //创建对象 Person p = new Person(); //怎么把Person对象变成垃圾? p = null; */ /* //多造点垃圾 for (int i = 0; i < 1000000; i++) { Person p = new Person(); p = null; } */ Person p = new Person(); p = null; //有一段代码可以建议垃圾回收器启动 System.gc(); //建议启动垃圾回收器,(只是建议,可能不启动,也可能不启动) }}//项目开发中有这样的需求:所以对象在JVM中被释放的时候,请记录一下时间//这个记录对象被释放的时间点,这个负责记录的代码就写在finalize方法中class Person{ //重写finalize //Person类型对象被垃圾回收器回收的时候,垃圾回收器负责调用:p.finalize(); @Override protected void finalize() throws Throwable { System.out.println(this + "即将被销毁"); }}
hashCode()在Object中的源码:
public native int hashCode();不是抽象方法,带有native关键字,底层调用了底层的C++
public class Test07 { public static void main(String[] args) { Object o = new Object(); int hashCodeValue = o.hashCode(); //对象内存地址经过哈希算法转换的一个数字,可以等同看做内存地址 System.out.println(hashCodeValue); //1067040082 }}
在一个类的内部又定义了一个新的类,被称为内部类
一开始我们的写法是这样的。
注意:使用内部类编写的代码,可读性很差,能不用尽量不用public class Test01 { //静态变量 static String country; //该类在类的内部,所以称为内部类 //由于前面有static,所以称为"静态内部类" static class Inner1{ } //实例变量 int age; //该类在类的内部,所以称为内部类 //没有static叫做实例内部类 class Inner2{ } public void doSome(){ //局部变量 int i = 100; //该类在类的内部,所以称为内部类 //局部内部类 class Inner3{ } } public void doOther(){ //doSome()方法中的局部内部类Inner3在doOther()中不能用 //因为Inner3在doSome()方法中,方法一旦结束,里面的类也就没有了 }}
类似于实例变量
类似于静态变量
类似于局部变量
转载地址:http://gqxzi.baihongyu.com/