从制造工具到使用工具
在初学面向对象时,我们知道了如何制造工具(创建类并定义属性和方法)去解决问题,类与类之间有什么关系,如何运用封装继承多态和函数重写。但是,Java本身就有庞大的工具类库了,我们为何还要自己非要造一个类呢?原因有两种:
1. 可能Java类库中没有适合解决问题的工具类
2. 只有学会创建类才能知道工具类的结构,便于我们更好地理解和使用类
使用工具类时往往会需要在开头写入导包语句[import 包名],就像C/C++需要包含头文件,唯独java.lang包无需导包语句,编写Java程序时自动导入,今天本Reno就介绍lang包下的两个工具类——Object和String
Object类
Java的世界中,万物皆为object(对象),对象又是由类创建的,类之间还有继承关系,在java.lang包中有一个万物始祖——Object类,它是继承关系的树形结构中是根节点,所有的类如果没写继承关系的话,默认直接作为Object的派生类。Object类还有一些特殊点:
1. 无成员变量
2. 构造函数只有无参的
3. 绝大多数的函数在其派生类中可以直接用,甚至可以重写。
在JDK1.8版本中Object有11个可用的函数,在这只讲两个
1. boolean equals(Object obj)
public boolean equals(Object obj) {
return (this == obj);
}
默认情况下,它的作用和双等号相同,正因为对象都是引用类型,比的是两个对象指向的内存地址是否相同。如果你仅仅想比较两个对象某些属性是否相等,重写equals()函数即可。但是idea里面有更快捷的方法,按Alt + Insert后选择
2. String toString()
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
这个函数是以字符串形式表示对象或对象的某些信息,返回值是一个字符串。当对象指针直接作为输出数据时会自动调用toString()函数,此时会以包名.类名.@16进制来输出对象指向的内存地址。But,toString的函数几乎在所有使用类的情况下都重写,方便展示对象的属性
Notice:只有引用数据类型的类或变量才能用Object里面的属性和函数,基本数据类型不能用。
String类
String是lang包里面的字符串类,相当于C++的std::string,所有带英文双引号的都是String的对象。String类是不可继承的,并且自带了一些属性和函数
核心属性
1. private final char value[]
字符串内容会存储在这里,该属性具有以下特点:
1. 正因为这里定义的字符数组是被final修饰的,字符串的值不可被改变,要想使用可变字符串,应该使用StringBuffer类(将在后续学习中介绍)。
2. 长度由字符串包含的字符数量决定,也就是说,该属性与字符串等长
构造函数
1. public String()
生成一个空字符串对象"",但不代表它没被分配内存空间,一般不会使用
2. public String(@NotNull String original)
按照参数中的字符串形式新建字符串对象,但本Reno更推荐使用String 字符串名 = "<字符串内容>"的格式,这样可以不用通过new创建对象来节省堆内存,让字符串指针指向常量池。
3. public String(@NotNull char value[])
新建字符串对象并将已知的字符数组存放到这个对象中。不过String类里面还有与之相反的函数,就是能将字符串转换为字符数组的public char[] toCharArray()。
其它函数
1. public boolean equals(Object anObject)
此函数重写了基类Object中的equals函数,返回true的条件除了两个对象指向的内存地址完全一致,还有当字符串内容完全一致时也会返回true,在equals()函数体中,有较多的if判断,第一个条件是当传入的参数与调用者(即调用equals()的对象)的内存地址一致时,返回true;还有当参数属于String类时会设法把参数强转为String类型,再比较存放两者内容的字符数组中元素是否都一致。这和双等号的意义不一样的,先验证一下
public class E {
public static void main(String[] args) {
String s1 = new String("abc123");
String s2 = new String("abc123");
String s3 = "abc123";
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));
}
}
跑了一遍程序,结果如下
前两行输出false是因为对象都属于引用类型,存放的是内存地址,所以双等号只能用于比较等号两边的内存地址是否一致,而单次程序运行中每次new出来的对象都会分配到不同的内存地址;而第二行的false是因为直接引用字符串对象的话,这个引用指向的是常量池,常量池和堆内存的位置肯定不同的;最后一行输出true就是因为调用了String类已重写的equals()函数,仅仅比较字符串内容是否一致。
总结:
1. Object类是所有类的祖先,任何对象都是它的直接或间接派生类,没有属性,其中包含的equals()和toString()函数多数被Java类库中的其他类默认重写。
2. String类属于不可继承类,字符串内容存放在字符数组中且只能被初始化一次不能改变。
3. String类属于引用类型(类类型和数组类型都算引用类型),接收字符串类型的变量存放的是内存地址,所以里面默认重写了equals()函数用于判断字符串内容是否相等。
4. toString()函数用来以字符串形式表示对象,自己定义类时可以结合实际情况灵活重写。
5.[关于自身]由于本Reno重修过Java,编写过C++程序,也有探索过Cocos2d的C++版,学Java面向对象时会将Java知识尝试与UML和C++关联起来,也会把Java引用类型定义的变量全部理解为C++的指针。对于Java类库中还有哪些工具类,其中哪些需要熟练掌握,这还要靠API和自身学习能力。