实习日记 09/02 day41高效Java -- 创建和销毁对象

概览

在这里插入图片描述

静态工厂代替构造器

优点:
静态工厂方法与构造器不同的第一大优势是,静态工厂拥有自己的名称。
静态工厂的第二大优势是,不必在每次调用它们的时候都创建一个新的对象。
静态工厂方法与构造器第三大优势是,可以返回原返回类型任何子类型的对象。
静态工厂的第四大优势是,在创建参数化实例时,他们可以使代码变得更简洁。
缺点:
类如何不含有公有的或者受保护的构造器,就不能被子类化
它们与其他的静态方法实际上没有任何区别。
举个栗子:

public class StaticFoodFactory {

//    public StaticFoodFactory(String name){
//        在静态工厂中,由于不用实例化工厂类所以不需要
//    }

    public static Food createFood(String foodName){
        if("香肠".equals(foodName)){
            return new WangzhongWang();
        }else if("胡辣汤".equals(foodName)){
            return new hulatang();
        }
        return null;
    }

}

当需要使用某一个类的时候采用:

Food hulatang=StaticFoodFactory.createFood(“胡辣汤”);

多个构造器参数是要考虑使用build

当某一个类的构造器拥有超级多的入参时,每次新建一个对象就要往里面传入多多多个根本不用设着的参数,或是为这些入参排列组合成一个新的构造器,这显然是很麻烦的。又或者采用javabean模式,采用Setter和getter方法实现,但由于JavaBean模式的构造过程是分散的,你可以在任何时候去set,这样这份Bean不是确定的,你怎么能确保这个对象是安全的.所以要采用build模式。
Build模式非常的灵活,但也有自身的不足,为了创建对象必须穿件它的build器,可以是内部类,也可以是外部类。会有性能的损耗,简而言之,如果类的构造器或者静态工厂中有多个参数,在设计这种类的时候,Build模式应该是首选的

         //创建Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fanyi.youdao.com/") 
                // 设置 网络请求 Url
                .addConverterFactory(GsonConverterFactory.create()) 
                //设置使用Gson解析(记得加入依赖)
                .build();

Retrofit中的build是采用的内部类

 /**
   * Build a new {@link Retrofit}.
   * <p>
   * Calling {@link #baseUrl} is required before calling {@link #build()}. All other methods
   * are optional.
   */
  public static final class Builder {
    private Platform platform;
    private okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private List<Converter.Factory> converterFactories = new ArrayList<>();
    private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    private Executor callbackExecutor;
    private boolean validateEagerly;

    Builder(Platform platform) {
      this.platform = platform;
      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
    }

    public Builder() {
      this(Platform.get());
    }

利用私有构造器或者枚举类型强化Singleton属性

Singleton指的是仅仅被实例化一次的类,优势也通常被用来表示那些本质上唯一的系统组件,比如文件系统和窗口管理器。
例如android的四种启动模式之一的SingleTask,以"singleTask"方式启动的Activity,全局只有唯一一个此Activity实例存在,当且仅当第一次启动这个Activity时,系统便会创建一个新的任务,并且初始化一个这样的Activity的实例。
对于Java实现单例模式:

public static final StaticFoodFactory Instance=new StaticFoodFactory();
private StaticFoodFactory(){
    
}
public static final StaticFoodFactory Instance=new StaticFoodFactory();
private StaticFoodFactory(){
}
public static StaticFoodFactory getInstance(){
    return Instance;
} 

使用构造器强化不可实例化的能力

再开发过程中会遇到共有变量类,他只包含静态方法和静态变量,他们作为工具类不需要被实例化就可以被使用,在缺少显示构造器的情况,编译器会提供一个共有的、无参的缺省构造器,需要保证其他开发人员不会错误的实例化此种工具类,采用私有的构造器。

class PubMessagerUtils{
public static String message="失效数据";
public static String Code="-999";
private PubMessagerUtils(){}

}

由于显示的构造器是私有的,所以不能在该类的外部访问它

避免创建不必要的对象

在开发过程中,如果经常操作字符串

 public static void main(String[] args) {
        String x=new String("dasdlakd");
        String y=x+"sdahkd";
        String z=new String(x+y+"djasdhaj");
        StringBuilder t=new StringBuilder("hdkjasjhdka");
        StringBuffer k=new StringBuffer("dakkdsa");
    }

不要错误的使用并产生成千上万个String类型的对象,可以直接String str=”sas“;
但不要错误的理解“创建对象的代价非常高,所以不要创建对象”,每一个对象都是不同的,对于小对象来说创建和回收动作是非常廉价的。
注意:StirngBuilder线程不安全,高并发情况下考虑采用Stringbuffer。

消除过期的对象引用

在数据结构与算法一书中,经常出现这样Stack.clear和Queue.clear这些操作,因为这些数据结构会出现内存泄漏问题,随着垃圾回收器活动的增加,或者由于内存占用的不断增加,程序的性能降低会逐渐表现出来,在极端情况下,这种内存泄漏会导致磁盘交换设置导致OOM错误。
比如一个栈先增长在收缩,那么从栈中弹出来的对象不会被当作垃圾回收,即使使用的栈的程序不在引用这些对象,他们也不会被回收,因为栈中还维护对这些对象的过期引用。所谓过期引用就是再也不会被解除的引用

public class StackTest {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITAL_CAPACITY=16;
    public StackTest(){
        elements = new Object[DEFAULT_INITAL_CAPACITY];
    }
    public void push(Object e){
        ensureCapacity();
        elements[size++] = e;
    }
    public Object pop() throws Exception {
        if(size==0){
            throw new Exception();
        }
        return elements[size--];
    }

    /***
     * 确保容量保持正常
     */
    private void ensureCapacity(){
        if(elements.length == size){
            elements= Arrays.copyOf(elements,2*size+1);
        }
    }
}

如果想消除过期引用,则需改进

   public Object pop() throws Exception {
        if(size==0){
            throw new Exception();
        }
        Object result = elements[--size];
        elements[size] = null;
        return result;
    }

清除栈中的过期引用。
当然内存泄漏还有可能来自于缓存,一旦把对象引用放到缓存中,就很容易被遗忘,从而是的它不再有用之后很长一段时间仍然留在缓存之中
内存泄漏第三个来源是监听器和其他回调。如果实现了一个API,客户端就会在API中注册回调,却没有显示的取消注册,除非采取某些动作,否则他们就会聚集,确保回调立即被处理的方法就是只保存他们的弱引用,这样可以减少垃圾清理的次数。

避免使用终结方法

终结方法finalizer通常是不可预测的,一般情况下是不必要的,也是很危险的

   public static void main(String[] args) throws Throwable {
        StackTest stackTest=new StackTest();
        stackTest.finalize();
    }

使用终结方法会导致行为不稳定,降低性能,以及可移植的问题。,终结方法的缺点是不能保证它会被及时的执行,从一个对象变得不可达开始,到他的终结方法被执行,所花费的这段时间是任意的,同时使用终结方法会导致严重的Server的性能损失。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值