栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

effective java第二章

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

effective java第二章

用静态工厂替代构造函数

1、关于可以重复使用对象以及命名的优势理解,但是其中可以返回原返回类型的任何类型,而该返回可以是非公有的。
如下面的例子,unmodifiableSet本身对外声明的返回类型是set接口,但是实际返回的是UnmodifiableSet这样一个非共有的类型。
也就是其实对于静态的工厂函数可以返回一个接口,具体的返回可以是该接口的任何子类,甚至是非公有,这样通过返回类型就明确是什么类型,但是又不关系具体到底是哪个实现类,足够灵活。

    public static  Set unmodifiableSet(Set s) {
        return new UnmodifiableSet<>(s);
    }

    
    static class UnmodifiableSet extends UnmodifiableCollection
                                 implements Set, Serializable {
        private static final long serialVersionUID = -9215047833775013803L;

        UnmodifiableSet(Set s)     {super(s);}
        public boolean equals(Object o) {return o == this || c.equals(o);}
        public int hashCode()           {return c.hashCode();}
    }

2、java8中允许接口中存在静态方法以及静态成员,但是不能是private的,直接通过接口实现调用。

//接口
public interface Eat {
    public static void getGirl() {
        System.out.println("111");
    }
}
//接口实现类
public class EatImpl implements Eat{
}

public class Main {
    public static void main(String[] args) {
        Eat.getGirl();//可以——接口调用
        EatImpl.getGirl();//不可以
    }
}

注:
(1)实现类并没用继承该静态的函数或者静态成员
(2)在java8中很多接口也存在静态方法,比如Compator接口中的comparing()
(3)接口中不能存在私有的成员以及私有的方法—接口是约束,实现类无法看到
(4)java9中可以存在私有的静态方法—允许该接口中其他静态方法使用,但还是不能有私有的成员。

3、对于服务提供api用于提供服务的静态方法,可能由于该提供者并没有注册而不能提供服务。
和服务提供框架(SPF)相关,存在四个组件:服务、服务提供者、服务注册、服务提供api:

//服务
public interface Service {
    public void service();
}
//服务提供者
public interface Provider {
    public Service getService();
}
public class ServiceManager {
    static Map map=new HashMap<>();
    //服务注册
    public static void registerProvider(String name,Provider provider){
        map.put(name,provider);
    }

    //服务提供api
    //(1)服务实现类  (2)提供者实现类   (3)提供者注册   (4)提供服务
    public static Service getService(String name){
        Provider provider = map.get(name);
        return provider.getService();
    }
}

当前实现一个服务,并提供服务仅仅需要:
(1)服务实现类
(2)提供者实现类
(3)提供者注册
(4)提供服务

即在没有任何服务提供者注册时候,是无法提供服务的,因此对于提供服务的getService()这个静态方法,可能由于没有相应的服务注册者注册,而无法提供服务。

服务提供者框架实现了服务提供者注册即可提供服务,而获取服务也直接可以通过服务提供者名字实现灵活获取。

4、类如果不含共有的或者受保护的构造器就无法子类化
这个的意思是,其实静态工厂方法的本质是,通过返回这个函数返回值的子类,实现灵活性。但是由于子类继承父类,子类的构造函数会默认调用父类的无参构造函数,如果没有就需要显示调用同参的父类构造函数,因此如果父类的构造函数不是共有的或者protected那么就无法实例化子类,那么静态工厂方法就没有意义。

使用构建器方式

一般当构造对象的时候涉及多个参数,一般情况下会采用“重叠”的方式构建对象,即通过不同个数的构造器,创建不同的对象;或者通过javaBean的方式,先构建没有参数的对象,再通过setter的方式填充参数,但是此种方式会造成不一致,即这边还没有构建完成,那边就使用就会不一致。

通过构造器的方式进行构建,即先构建Buillder,而Builder中的参数和实际需要构建的对象的参数是一一对应的:

(1)首先,通过必要参数使用Builder的构造器构造Builder
(2)通过函数,基于需要,填充参数
(3)build对象

public class Subject {
    int id;
    String name;
    String teacherName;
    int score;
    static class Builder{
        int bId;
        String bName;
        String bTeacherName;
        int bScore;

        public Builder(int id,String name){
            bId=id;
            bName=name;
        }

        public Builder buildTeacherName(String teacherName){
            bTeacherName=teacherName;
            return this;
        }

        public Builder buildScore(int score){
            bScore=score;
            return this;
        }

        public Subject build(){
            return new Subject(this);
        }
    }

    private Subject(Builder builder){
        this.id=builder.bId;
        this.name=builder.bName;
        this.teacherName=builder.bTeacherName;
        this.score=builder.bScore;
    }
}
new Subject.Builder(1,"java").buildScore(100).buildTeacherName("jjw").build();

通过构建器的方式保证了可读性,也保证了一致性,因为当仅当build的时候,该对象才存在。

用私有构造器

1、创建单例都需要将构造函数私有化,通过将域公有化或者通过静态方法返回单例对象。
2、单例的序列化需要实现readResolve()方法保证单例对象的唯一性:

public class Singleton  implements Serializable{
    private  static final Singleton instance=new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
    private Object readResolve(){
        return instance;
    }
}
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        ByteArrayOutputStream byteArrayOs = new ByteArrayOutputStream();
        ObjectOutputStream objectOs = new ObjectOutputStream(byteArrayOs);
// 对象写入流中
        objectOs.writeObject(Singleton.getInstance());

        ObjectInputStream objectIs = new ObjectInputStream(new ByteArrayInputStream(byteArrayOs.toByteArray()));
        System.out.println(objectIs.readObject() == Singleton.getInstance());
    }

上面的例子,当仅仅当readResolve()存在才会是true。

3、也可以通过枚举类返回唯一对象。

避免使用终结方法和清除方法

1、通过cleaner注册对象以及对应的State的run()方法,当对象可以进行垃圾回收时,Cleaner 类的对象会自动得到通知,执行State中的run方法——但是不能保证一定执行以及执行时机。

public class CleanerTest {
   public static void main(String args[]) {
      System.out.println("nhooo");
       //创建Cleaner
      Cleaner cleaner = Cleaner.create();
      if(true) {
         CleanerTest myObject = new CleanerTest();
          //向cleaner注册某个对象以及State,当前面对象进行垃圾回收的时候就会执行state中的run方法
            cleaner.register(myObject, new State());    // register cleaner      }
      for(int i = 1; i <= 10000; i++) {
         String[] largeObject = new String[1000];
         try {
            Thread.sleep(1);
         } catch(InterruptedException e) {
              e.printStackTrace();
         }
      }
   }
   private static class State implements Runnable {
      public void run() {
         System.out.print("Cleaning action");
      }
   }
}
try-with-resource

首先被自动关闭的资源需要实现Closeable或者AutoCloseable接口,因为只有实现了这两个接口才可以自动调用close()方法去自动关闭资源,将要关闭的外部资源在try()中创建,catch()捕获处理异常。

        try(FileInputStream inputStream=new FileInputStream(new File("test"))){
            System.out.println(inputStream.read());
        }catch (IOException e){
            throw new RuntimeException(e.getMessage(),e);
        }

将inputStream在使用完毕后关闭,就放在try中。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/445180.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号