一、源码分析前的知识补充
1、Serializable标记型接口
(1)介绍
类的序列化由实现java.io.Serializable接口的类启用,不实现此接口的类将不会使任何状态序列化或反序列化。可序列化的所有子类型都是可序列化的。
- 序列化:将对象的数据写入到文件
- 反序列化:将对象中的数据读取出来。
(2)代码演示
package com.集合.ArrayList;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Demo {
/*
* 4个用户对象,要求将4个人用户对象序列化到当前目录下的stu.txt中
* 序列化成功后,通过反序列化将数据读取出来,打印到控制台
* */
public static void main(String[] args) throws IOException, ClassNotFoundException {
User user1 = new User("张三", 29);
User user2 = new User("李四", 10);
User user3 = new User("王五", 20);
User user4 = new User("赵六", 19);
ArrayList<User> users = new ArrayList<>();
Collections.addAll(users,user1,user2,user3,user4);
//创建对象操作流
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("stu.txt"));
outputStream.writeObject(users);
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("stu.txt"));
ArrayList<User> list = (ArrayList<User>) inputStream.readObject();
for (User user : list) {
System.out.println(user);
}
}
}
class User implements Serializable {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.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;
}
/*
*字符串在拼接时,会产生大量的对象,非常占内存,所以对toString进行优化
*用StringBuilder进行优化 它在创建的过程中只一个对象
**/
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("User【name='").append(this.name).append("',age=").append(this.age).append("】");
return stringBuilder.toString();
/* return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';*/
}
}
2、Cloneable标记型接口
(1)介绍
一个类实现Cloneable接口来指示Object.clone()方法,该方法对于该类的实例进行字段的复制是合法的。不实现Cloneable接口的实例上调用对象的克隆方法会导致异常。
(2)克隆的前提条件
- 被克隆对象所在的类必须实现Cloneable接口
- 必须重写clone方法
(3)浅克隆
浅克隆:复制对象时仅仅复制对象本身,包括基本属性,但该对象的属性引用其他对象时,该引用对象不会被复制,即拷贝出来的对象与被拷贝出来的对象中的属性引用的对象是同一个。
package com.集合.ArrayList;
public class Demo2 {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher("张三的老师");
Student student1 = new Student("张三", 23,teacher);
Object student2 = student1.clone();
System.out.println(student1 == student2);
//浅克隆 更改student1的内容,student2不会受到影响
teacher.setName("李四的老师");
System.out.println(student1);
System.out.println(student2);
}
}
class Student implements Cloneable{
private String name;
private int age;
private Teacher teacher;
public Student(String name, int age, Teacher teacher) {
this.name = name;
this.age = age;
this.teacher = teacher;
}
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;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
protected Object clone() throws CloneNotSupportedException {
//调用Object类的本地方法
return super.clone();
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", teacher=" + teacher +
'}';
}
}
class Teacher{
private String name;
public Teacher(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
'}';
}
}
输出是
false
Student{name='张三', age=23, teacher=Teacher{name='李四的老师'}}
Student{name='张三', age=23, teacher=Teacher{name='李四的老师'}}
我们发现修改原来的值,拷贝后的值也发生了修改。
(4)深克隆
深克隆:**复制对象本身的同时,也复制对象包含的引用指向的对象,**即修改被克隆对象的任何属性都不会影响到克隆出来的对象。
package com.集合.ArrayList;
public class Demo2 {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher("张三的老师");
Student student1 = new Student("张三", 23,teacher);
Object student2 = student1.clone();
System.out.println(student1 == student2);
//浅克隆 更改student1的内容,student2不会受到影响
teacher.setName("李四的老师");
System.out.println(student1);
System.out.println(student2);
}
}
class Student implements Cloneable{
private String name;
private int age;
private Teacher teacher;
public Student(String name, int age, Teacher teacher) {
this.name = name;
this.age = age;
this.teacher = teacher;
}
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;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
protected Object clone() throws CloneNotSupportedException {
//深拷贝需要先克隆出一个学生对象
Student student= (Student) super.clone();
//调用Teacher类中的克隆方法,克隆一个Teacher对象
Teacher teacher = (Teacher) this.teacher.clone();
//把克隆出来的teacher赋给student对象的成员变量
student.setTeacher(teacher);
return student;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", teacher=" + teacher +
'}';
}
}
class Teacher implements Cloneable{
private String name;
public Teacher(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
输出结果
false
Student{name='张三', age=23, teacher=Teacher{name='李四的老师'}}
Student{name='张三', age=23, teacher=Teacher{name='张三的老师'}}
3、RandomAccess标记型接口
(1)介绍
由List实现使用,以表明它们支持快捷随机访问,此接口的主要目的是允许通过算法更改其行为,以便在应用于随机访问列表或顺序访问列表时提供良好的性能。
(2)ArrayList随机和顺序访问效率对比
package com.集合.ArrayList;
import java.util.ArrayList;
import java.util.Iterator;
public class Demo3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
list.add(i+"");
}
//随机访问
long start = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
long end = System.currentTimeMillis();//1
System.out.println(end - start);
//顺序访问
long start1 = System.currentTimeMillis();
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
iterator.next();
}
long end1 = System.currentTimeMillis();//2
System.out.println(end1 - start1);
}
}
//源码
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
//可以看出ArrayList实现了RandomAccess接口,
(3)LinkedList随机和顺序访问效率对比
package com.集合.ArrayList
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
public class Demo4 {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
for (int i = 0; i < 10000; i++) {
list.add(i+"");
}
//随机访问
long start = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
long end = System.currentTimeMillis();//118
System.out.println(end - start);
//顺序访问
long start1 = System.currentTimeMillis();
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
iterator.next();
}
long end1 = System.currentTimeMillis();//22
System.out.println(end1 - start1);
}
}
//源码分析
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
//发现LinkedList并没有实现RandomAccess这个接口
{
(4)实际开发应用场景
package com.DBUtils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.RandomAccess;
public class dbutils {
public static void main(String[] args) throws Exception {
//我们使用Druid的连接池和DBUtils的工具类
Properties properties = new Properties();
properties.load(new FileInputStream("src/druid.properties"));
DataSource dataSource = new DruidDataSourceFactory().createDataSource(properties);
QueryRunner queryRunner = new QueryRunner(dataSource);
String sql="select *from demo2 where money=?";
List<User> list = queryRunner.query(sql, new BeanListHandler<User>(User.class), 1000);
//我们可以看到数据库查询的结果封装成一个集合,那么该如何遍历这个集合?随机访问还是顺序访问 要保证效率高
if(list instanceof RandomAccess){
//随机遍历
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}else{
//顺序遍历
Iterator<User> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
}