目录
引出
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:代表本包或者继承
// 继承的时候,可以将子类的访问控制符扩大,但不能缩小;
// 子类不能比父类抛出更多的异常
@Override
public 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:代表本包或者继承
// 继承的时候,可以将子类的访问控制符扩大,但不能缩小;
// 子类不能比父类抛出更多的异常
@Override
public 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.序列化和反序列化的方式;
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/165071.html