目录
- 引出
- 类什么时候被加载JVM中
- 创建对象几种方式
- 1.new 看到new : new Book()
- 2.反射 Class.forName(“包名.类名”)
- 如何获取Class对象【反射的基础】
- 案例:连接数据库方法
- 3.克隆(拷贝)clone
- 浅拷贝
- 深拷贝
- 案例
- 序列化和反序列化
- 对象流-把对象存储为dat文件
- 总结
引出
1.类什么时候被加载到JVM中,new,Class.forName: Class.forName(“包名.类名”);
2.创建对象的方式,反射,本质是获得类的类对象Class;
3.克隆clone,深拷贝,浅拷贝的对比;
4.序列化和反序列化的方式;
类什么时候被加载JVM中
Hello h; // 此时没有用Hello,jvm并没有进行类加载
- 看到new : new Book()
- Class.forName: Class.forName(“包名.类名”)
- 类加载器
package com.tianju.auth.reflect;public class HelloTest1 {public static void main(String[] args) throws ClassNotFoundException {Hello h; // 此时没有用Hello,jvm并没有进行类加载System.out.println("**********");new Hello(); // new 的时候会加载到内存中System.out.println("**********");Class.forName("com.tianju.auth.reflect.Hello");}
}
package com.tianju.auth.reflect;public class Hello {static {System.out.println("hello");}public Integer count(Integer a,Integer b){return a+b;}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {int a = 3;Class<?> aClass = Hello.class; // ?泛型的写法Class<?> aClass1 = Class.forName("com.tianju.auth.reflect.Hello");Class<? extends Hello> aClass2 = new Hello().getClass();System.out.println(aClass);System.out.println(aClass1);System.out.println(aClass2);Hello o = (Hello) aClass.newInstance();int count = o.count(1, 2);System.out.println(count);}
}
创建对象几种方式
1.new 看到new : new Book()
2.反射 Class.forName(“包名.类名”)
一个类会产生一个唯一的Class对象,JVM底层原理
Car.java 编译成 Car.clase 类加载到 JVM 中,加载时还没有创建对象;
进入JVM中给类Car创建单独的唯一的对象Class 类,该Class对象中存储了Car类的一些必要信息,没有记录相关的值;
以Class对象生产成多个Car对象,通过Class类映射出多个Car对象
如何获取Class对象【反射的基础】
- 对象.getClass()
- 类.class
- Class.forName(“包名.类名”)
案例:连接数据库方法
类加载采用了反射的方式
采用枚举方式封装JDBC单例
方法程序:
package com.tianju.util;import java.sql.*;
import java.util.Objects;/*** 采用枚举单例封装数据库*/
public enum DbUtilEnum {INSTANCE;private Connection conn;private PreparedStatement pst;private ResultSet rs;private DbUtilEnum() {// 注册驱动-类加载register();}/*** 第一步:注册驱动,类加载*/private void register(){try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}// 建立数据库连接// 192.168.0.134:3306// root,123/*** 第二步:建立数据库连接* @param ipAdress ip地址+端口号* @param user 用户名root* @param password 密码123*/public void connect(String ipAdress,String user,String password){String url = "jdbc:mysql://"+ipAdress+"/emp_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";try {conn = DriverManager.getConnection(url,user,password);System.out.println("成功连接数据库:"+ipAdress);} catch (SQLException e) {throw new RuntimeException(e);}}/*** 第三步:准备SQL语句,* @param sql sql语句*/public void setPreparedStatement(String sql, Object...values){try {pst = conn.prepareStatement(sql);// 逐个填充 ? 处的空缺for (int i=0;i<values.length;i++){pst.setObject(i+1, values[i]);}} catch (SQLException e) {throw new RuntimeException(e);}}/*** 第四步:增加,删除,修改*/public void executeUpdate(){try {pst.executeUpdate();System.out.println("执行增删改操作");} catch (SQLException e) {throw new RuntimeException(e);}}/*** 第四步:查询ResultSet,调用next()方法* @return 返回查询的ResultSet*/public ResultSet executeQuery(){try {rs = pst.executeQuery();System.out.println("执行查询操作,返回结果");return rs;} catch (SQLException e) {throw new RuntimeException(e);}}/*** 第五步:关闭连接*/public void close(){try {if (Objects.nonNull(rs)){rs.close();}if (Objects.nonNull(pst)){pst.close();}if (Objects.nonNull(conn)){conn.close();}System.out.println("操作完成,关闭数据库连接");} catch (SQLException e) {throw new RuntimeException(e);}}
}
3.克隆(拷贝)clone
- 继承的时候,可以将子类的访问控制符扩大,但不能缩小;子类不得比父类抛出更多,更大的异常。
- 浅拷贝、深拷贝问题:
浅拷贝
// protected:代表本包或者继承// 继承的时候,可以将子类的访问控制符扩大,但不能缩小;// 子类不能比父类抛出更多的异常@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}
深拷贝
public Book deepClone(){Book book = new Book();Author au = new Author();au.setName(author.getName());book.setAuthor(au);book.setTitle(this.title);book.setPrice(this.price);return book;}
案例
Author.java实体类
package com.tianju.auth.reflect;import lombok.Data;@Data
public class Author {private String name;
}
Book.java实体类
implements Cloneable{ // 可以克隆的
package com.tianju.auth.reflect;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book implements Cloneable{ // 可以克隆的private String title;private Author author;public double price;static {System.out.println("book的静态代码块");}// protected:代表本包或者继承// 继承的时候,可以将子类的访问控制符扩大,但不能缩小;// 子类不能比父类抛出更多的异常@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}public Book deepClone(){Book book = new Book();Author au = new Author();au.setName(author.getName());book.setAuthor(au);book.setTitle(this.title);book.setPrice(this.price);return book;}
}
进行测试
package com.tianju.auth.reflect;public class TestDemo{public static void main(String[] args) throws CloneNotSupportedException {Author author = new Author();author.setName("吴承恩");Book book = new Book("三国演义", author,12.56);Book book1 = book;System.out.println(book1==book);// == 两个引用是否指向同一个对象// clone创建了一个新的对象,只是值一样Book bookClone = (Book) book.clone();// 深拷贝,创建了新的对象,上面的浅拷贝,只是拷贝了引用Book deepClone = book.deepClone();System.out.println(bookClone==book);System.out.println("克隆前:"+book);System.out.println("克隆后:"+bookClone);author.setName("小柯基");System.out.println("修改后的原对象:"+book);System.out.println("修改后的clone对象:"+bookClone);// 深拷贝System.out.println("***********");System.out.println("深拷贝的方法:"+deepClone);}
}
序列化和反序列化
对象流-把对象存储为dat文件
要点:
(1)实体类需要实现序列化接口 public class Car implements Serializable;【标记接口】
(2)序列化的版本号最好不要写,交给JVM实现,要保证版本号一致;
功能:
ObjectOutputStream—->对象写入文件
serialVersionUID :在序列化的时候指定的编号, 在反序列化时应该保证版本号一致。
案例:把car类存储到dat文件中
1)类需要实现序列化的接口
public class Car implements Serializable { // 需要实现序列化的接口// 序列化的版本号,不要写,交给jvm实现;保证读的和写的对象实体类要一样
// private static final long serialVersionUID = 2L;private Integer id;private String name;public Car() {}
}
2)从内存写入硬盘文件,为out,用write
ObjectOutputStream out =new ObjectOutputStream(new FileOutputStream("D:\\Myprogram\\idea-workspace\\IOStrem\\IOStrem\\src\\com\\woniuxy\\resources\\car.dat"));
// 存多个的解决方法,存到List中
List<Car> list = new ArrayList<>();
list.add(new Car(1, "BMW"));
list.add(new Car(2, "BYD"));
list.add(new Car(3, "BMW"));
out.writeObject(list); // list也实现了Serializable
out.flush();
out.close();
3)从硬盘读入内存,为in,用read
ObjectInputStream in =new ObjectInputStream(new FileInputStream("D:\\Myprogram\\idea-workspace\\IOStrem\\IOStrem\\src\\com\\woniuxy\\resources\\car.dat")
);
// Car car = (Car) in.readObject(); // 读对象,向下转型
// System.out.println(car);
List<Car> list = (List<Car>) in.readObject();
System.out.println(list);
list.forEach(car -> System.out.println(car)); // list的lamda表达式
list.forEach(System.out::println); // 上面的简化写法
in.close(); // 记得关闭
总结
1.类什么时候被加载到JVM中,new,Class.forName: Class.forName(“包名.类名”);
2.创建对象的方式,反射,本质是获得类的类对象Class;
3.克隆clone,深拷贝,浅拷贝的对比;
4.序列化和反序列化的方式;