zoukankan      html  css  js  c++  java
  • java7:核心技术与最佳实践读书笔记——对象生命周期

    流程:字节码文件(.class) -> 类加载 -> 类链接 -> 类初始化 -> 对象初始化 -> 对象创建 -> 对象使用 -> 对象回收 。

    1、Java类的链接
    (1)回顾:Java虚拟机刚启动时,内部只包含Java核心类的相关信息,随着程序的运行,不断有新的Java类被加载到虚拟机中,变为可用状态。Java类被加载后还需要经过链接和初始化才可以在虚拟机中使用。
    (2)链接:把加载到Java类的字节代码中包含的信息虚拟机的内部信息进行合并,使Java类的代码可以被执行。链接分为3个子步骤,分别为验证、准备和解析。链接过程中,会对Java类的直接父类或父接口进行验证和准备,但是对类中形式引用的解析是可选的。
    (3)验证:用来确保Java类的字节代码表示在结构上完全正确,且可能使得其他Java类或接口被加载。如果发现字节代码的格式不正确,会抛出java.lang.VerifyError错误。
    (4)准备:创建Java类中的静态域,并将这些域的值设置为默认值,并不执行代码,为了确保类加载时的类型安全。由于可能出现两个不同的类加载器同时加载同一个Java类,导致无法记录下哪个才是该Java类的初始类加载器,所以会抛出java.lang.LinkageError错误。
    (5)解析:处理所加载的Java类中包含的形式引用。如:父类、所实现接口、方法的形式参数和返回值的Java类等。这些形式引用对应的Java类都被正确加载之后,当前Java类才能正常工作。在Java类中可能包含了对其他类中方法的调用,对这些方法调用,在解析过程需要检查所调用的方法确实存在
    (6)解析策略:由于有一些类具有复杂的引用关系图,所以需要使用不同的策略来解决:
    • 提前解析:在链接时递归地对依赖的所有形式引用都进行解析,性能差。
    • 延迟解析:在真正需要一个形式引用才进行解析。
    2、Java类的初始化
    (1)过程:静态域 -> 静态代码块(这个方面教程比较多,不贴代码了)
    (2)可能造成类初始化的操作:
    • 创建一个Java类实例对象,如:Student s  = new Student();
    • 调用一个Java类的静态方法,如:StringUtils.substring();
    • 为类或接口中的静态非final域赋值(常量是在编译时进行初始化,放在常量池中,即运行时与该类并无直接关系了)
    • 调用Class类和反射API中进行反射操作的方法,如:Class.forName("xxx");
    3、对象的初始化与创建
    (1)过程:父类的代码块 -> 父类的构造器 -> 子类的代码块 -> 子类的构造器
    (2)注意:不要在构造方法中调用可以被子类覆盖的方法。
    class Animal {
         public Animal() {
              int average = 30 / getCount();
         }
         protected int getCount() {
              return 4;
         }
    }
    class Dog extends Animal {
         private int count;
         public Dog(int count) {
              this.count = count;
         }
         public int getCount() {
              return count;
         }
     
    }
    public class WrongInit {
         public static void main(String[] args) {
              Dog dog = new Dog(4);  //抛出了除零异常
         }
    }
    
    4、对象终止
    (1)finalize方法:基本没用,由于调用时间无法确定,System.gc()虽然可以提升垃圾回收的几率,进而增加finalize方法被运行的几率,但实际运行时间还是无法确定。
    (2)finalize方法与资源释放:不要在finalize中进行资源释放,回收时间不确定可能导致打开资源过多,导致系统崩溃,使用显式释放(inputStream.close()等)或者使用try-with-resources语句来进行资源释放
    (3)正确使用finalize方法:
    • 必须调用父类的finalize方法进行内存回收
    • finalize方法中过多的语句,可能导致对象复活,可以使用幽灵引用来代替
    5、对象复制
    (1)被复制的类需要实现Cloneable接口,不然调用clone方法,将抛出CloneNotSupportedException异常
    (2)浅克隆:基本类型和不可变对象的域,如果包含引用类型,会导致复制出来的对象与原对象的引用指向了同一个对象
    class Counter {
         private int value = 0;
     
         public void increase() {
              value++;
         }
     
         public int getValue() {
              return value;
         }
    }
     
    class MutableObject implements Cloneable {
         private Counter counter = new Counter();
     
         public void increase() {
              counter.increase();
         }
     
         public int getValue() {
              return counter.getValue();
         }
     
         public Object clone() {
              try {
                  return super.clone();
              } catch (Exception e) {
                  throw new Error(e);
              }
         }
    }
     
    public class MutableObjectClone {
         public static void cloneObject() {
              MutableObject obj = new MutableObject();
              obj.increase();// 1
              MutableObject cloneObj = (MutableObject) obj.clone();
              cloneObj.increase();// 2
              obj.increase();// 3
              System.out.println(cloneObj.getValue());
         }
     
         public static void main(String[] args) {
              cloneObject(); // 3
         }
    }
    (3)深克隆:引用类型也克隆一份,这需要递归克隆。
    class Counter {
         private int value = 0;
     
         public void increase() {
              value++;
         }
     
         public int getValue() {
              return value;
         }
        
         public Object clone() {
              try {
                  return super.clone();
              } catch (CloneNotSupportedException e) {
                  throw new Error(e);
              }
         }
    }
     
    class MutableObject implements Cloneable {
         private Counter counter = new Counter();
        
    public void increase() {
              counter.increase();
         }
     
         public int getValue() {
              return counter.getValue();
         }
     
         public Object clone() {
              MutableObject obj = null;
              try {
                  obj = (MultableObject)super.clone();
                  obj.counter = (Counter)counter.clone();
                  return obj;
              } catch (Exception e) {
                  throw new Error(e);
              }
         }
    }
     
    public class MutableObjectClone {
         public static void cloneObject() {
              MutableObject obj = new MutableObject();
              obj.increase();// 1
              MutableObject cloneObj = (MutableObject) obj.clone();
              cloneObj.increase();// 2
              obj.increase();// 2
              System.out.println(cloneObj.getValue());
         }
     
         public static void main(String[] args) {
              cloneObject(); // 2
         }
    }
    6、对象序列化(实现Serializable,不然抛出 java.io.NotSerializableException)
    (1)序列化:活动对象的内部状态转换成一个字节流;
    public class WriterUser{
         public void write(User user) throws IOException{
              Path path = Paths.get("user.bin");// 相当于项目目录下的user.bin文件
              try(ObjectOutputStream output = new ObjectOutputStream(Files.newOutputStream(path))){
                   output.writeObject(user);               
              }
         }
         
         public static void main(String[] args) throws IOException{
              WriterUser writeUser = new WriterUser();
              User user = new User("Alex","alex@example.org");
              writerUser.write(user)
         }
    }
    (2)反序列化:字节流转换成可以直接使用的Java对象。
    public class ReadUser{
         public User readUser() throws IOException,ClassNotFoundException{
              Path path = Paths.get("user.bin");
              try(ObjectInputStream input = new ObjectInputStream(Files.newInputStream(path))){
                   User user = (User)input.readObject();
                   return user;
              }
         }
         
         public static void main(String[] args) throws ClassNotFoundException,IOException{
              ReadUser readUser = new ReadUser();
              User user = readUser.readUser();
              System.out.println(user.getName());//Alex
         }
    }
    (3)自定义序列化:因为序列化之后的对象可能包含敏感信息,需要去除。
    //在User类中添加如下方法
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
         System.out.println("write object start");
         //out.defaultWriteObject(); //默认形式,注掉可让邮件信息不序列化
         out.writeUTF(getName());
    }
     
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
        System.out.println("read object start");
        //in.defaultReadObject(); 
        this.name = in.readUTF(); //由于没有存入邮件信息,所以获取邮件信息时将得到null值
    }
    //多个String的域,按顺序存入,按顺序取出即可
    //有了这两个方法,可以对存入信息进行加密,取出来时进行解密
    

      

     
     
  • 相关阅读:
    CodeForces 710CMagic Odd Square(经典-奇数个奇数&偶数个偶数)
    CodeForces 710A King Moves(水题-越界问题)
    CodeForces 701C They Are Everywhere (滑动窗口)
    CodeForces 701B Cells Not Under Attack
    [补档]happiness
    [补档]王者之剑
    [补档]士兵占领
    [补档]搭配飞行员
    [补档]暑假集训D6总结
    [补档][Lydsy2017年4月月赛]抵制克苏恩
  • 原文地址:https://www.cnblogs.com/linzhanfly/p/6652238.html
Copyright © 2011-2022 走看看