文章目录
一、Object类
1.Object类的几个要点
Java中的万物之母:Object类
全名称:包名.类名
java.lang.Object
1.Object类是Java中所有类的默认父类,无须使用extends来定义。class声明的类都有一个父类,Object类。
因为Object类是所有类的父类,使用Object引用来接收所有的类型,参数最高统一化。
Java中所有类型都可以向上转型变为Object类型
2.Object类中的所有方法子类全部都继承下来了。
之所以使用System.out.println(任意的引用类型)时,默认都调用该类型的toString()方法,是因为Object类存在toString()方法。
如果想输出当前类的属性值,我们就需要覆写toString方法。
3.Java中引用数据类型之间的相等比较使用equals方法,不能使用“==”。
4.Object不仅是所有类(class)的父类,JDK对Object类做了扩展。
Object类可以接收所有引用数据类型的对象(接口,数组,类)
因此在Java中,若一个方法参数或者返回值是Object类型,说明该参数或者返回值可以是任意引用数据类型(数组,类,接口)
此时除了8大基本类型没法用Object类来接收以外,所有类型都能使用Object来接收。
2.覆写equals方法
这是Object类中自带的equals方法
若不覆写equals方法,则默认的equals就等同于“==”;
此时要比较两个Student类的对象的属性值是否相等,需要覆写equals方法
3.Comparable接口
接口优先原则,当一个场景既可以使用抽象类也可以使用接口定义时,优先考虑使用接口(更灵活)
JDK内置的常用接口:
java.lang.Comparable:当一个类实现了Comparable接口,表示该类具备了可比较的能力。
此时不能直接用Arrays.sort对Person类进行排序,由于Person这个类型是自定义类型,对于编译器来说,不想int这样大小关系一目了然,到底哪个Person对象大,哪个Person对象小,编译器无从得知了,要让Person这个类型具备可比较的能力,也就是要让JDK知道Person对象“谁大谁小”,就需要让Person类实现Comparable接口,覆写抽象方法compareTo。
覆写过后,就可以直接用Arrays.sort对Person类进行排序
4.Cloneable接口
JDK另一个比较重要的接口 - 克隆接口。
java.lang.Cloneable
原对象和新产生对象确实是两个独立的对象,新产生的对象是通过原对象“拷贝”而来的,属性值和原对象完全一致。
要让一个类具备可以复制的能力,实现Cloneable接口,覆写clone方法。
深浅拷贝:
浅拷贝:最外层对象确实是由原对象的clone方法产生的新对象,属性值与原对象保持一致,原对象和新对象的内部若包含其它类的引用,这些引用指向的对象是相同的,并没有产生新对象。
深拷贝:最外层对象确实是由原对象的clone方法产生的新对象,属性值与原对象保持一致,原对象和新对象的内部若包含其它类的引用,这些引用指向的对象也是新对象。
注意:
调用clone方法产生对象不会调用构造方法。
在Java中产生一个新对象有两种方式:
1.最普通最常见的通过构造方法产生对象
new 类(); = > 当有new关键字,就在堆上开辟该类相应属性的空间,给属性赋默认值。
2.通过clone()产生对象,调用clone时,JVM会开辟与原对象内存大小完全相同的新空间,并将对象中属性的值从原对象中复制一份。(不推荐这种方式)
二、String类
JDK中String类的声明:
我们思考一下String类为什么要被final修饰?
被final修饰的类无法被继承,String类不存在子类,这样可以保证使用的String类仅此一个,大家都相同,无法编写自己的String类,只能使用一个统一的String类。
继承和方法覆写在带来灵活性的同时,也会带来很多子类行为不一致导致的问题。
什么时候会用到final修饰类呢?
当我们定义的类不希望有其它版本,所有使用者用的这个类完全相同,没有别的实现。
1.创建字符串的四种方式
a.直接赋值
String str = "hello world";
b.通过构造方法产生对象
String str2 = new String("hello world");
c.通过字符数组产生对象
char[] data = new char[]{'a','b','c'};
String str = new String(data);
d.通过String的静态方法valueOf(任意数据类型) =>转为字符串
String str = String.valueOf(10);
字面量:直接写出来的数值就称之为字面量
10 -> int字面量
10.1 -> double字面量
“abc” -> String字面量(同时也是一个字符串对象)
2.字符串比较
所有引用数据类型在比较是否相等时,使用equals方法比较,JDK常用类,都已经覆写了equals方法,直接使用即可。
引用数据类型使用“==”比较的仍然是地址
3.字符串的常量池
当使用直接赋值法产生字符串对象时,JVM会维护一个字符串的常量池,若该对象在堆中还不存在,则产生一个新的字符串对象加入字符串的常量池中。
当继续使用直接赋值法产生字符串对象时,JVM发现该引用指向的内容在常量池中已经存在了,则此时不再新建字符串对象,而是复用已有对象。
手动入池:String类提供的intern方法
调用intern方法会将当前字符串引用指向的对象保存到字符串常量池中
a.若当前常量池中已经存在了该对象,则不再产生新的对象,返回常量池中的String对象。
b.若当前常量池中不存在该对象,则将该对象入池,返回入池后的地址。
4.字符串的不可变性
所谓的字符串不可变指的是字符串对象的内容不能变,而不是字符串引用不能变
为何字符串的对象无法修改内容,而其它类的对象能修改内容?
字符串其实就是一个字符数组 -> char[],字符串保存的值实际上在数组中保存。
5.修改字符串的内容
a.在运行时通过反射破坏value数组的封装
b.更换使用StringBuilder或者StringBuffer类(StringBuffer使用方法和StringBuilder完全一样,线程安全,性能较差)
若要频繁进行字符串的拼接,使用StringBuilder类的append方法
StringBuilder类可以修改对象的内容。
关于StringBuilder类的具体使用:
StringBuilder类和String类是两个独立的类,StringBuilder就是为了解决字符串拼接问题产生的,因为String的对象无法修改内容,为了方便字符串的拼接操作,产生了StringBuilder类,StringBuilder类的对象是可以修改内容的。
因为StringBuilder类可以修改内容,因此它具备一些String类不具备的修改内容的功能,除了拼接append方法外。
a.字符串反转操作,StringBuilder提供的reverse();
b.删除指定范围的数据:delete(int start,int end);
删除从start索引开始end之前的所有内容[start,end)
c.插入操作:insert(int start,各种数据类型)
将新元素插入当前sb对象,插入后新数值的起始索引为start
6.StringBuilder和StringBuffer的区别
1.String的对象无法修改,StringBuilder和StringBuffer的对象内容可以修改。
2.StringBuffer是线程安全的操作,性能较差;StringBuilder是线程不安全,性能较高。
7.字符串常见操作
1.字符串比较
2.字符和字符串的相互转换
字符串的内部实际上就是使用字符数组来存储的。
字符转字符串:
将字符数组的部分内容转为字符串对象
字符串转字符
1.取出字符串中指定索引的字符
2.将字符串中的内容转为字符数组
此时是产生了一个新的字符数组,将字符串的内容复制过去
如何判断一个字符串的对象是由纯数字组成的?
3.字符串和字节的相互转换
String -> byte[]
byte[] -> String
4.字符串查找操作
5.字符串替换操作
注意:
String类的所有针对字符串的操作方法都不会修改原字符串,而是产生了一个新的字符串!
6.字符串的拆分操作
7.字符串的截取处理
8.其它常用方法
写一个方法判断传入的str为空(要么是null,要么长度为0)
注意语句的顺序:
if(str == null || str.isEmpty())
写一个方法将字符串的首字母大写处理