AutoValue介紹

什么是AutoValue?

AutoValue是一個(gè)可以自動(dòng)為值類(value type)生成諸如equals,hashCode,toString等模板方法的工具。這樣就使得程序更加短小,簡潔,以及更少的bug。

為什么要使用AutoValue

什么是值類(value type)
這里指的是具有值語義的類型,只要兩個(gè)實(shí)例具有相同的字段值,他們就可以互換。比如DateTime,Money,Uri... 這必須實(shí)現(xiàn)equals方法和hashCode方法,通常還會(huì)實(shí)現(xiàn)toString方法。
看一下實(shí)現(xiàn)這樣一個(gè)值類的基本框架

public final class Foo {
    private final String text;
    private final int number;


    public Foo(String text, int number) {
        this.text = text;
        this.number = number;
    }

    public String text() {
        return text;
    }

    public int number() {
        return number;
    }

    @Override
    public boolean equals(@Nullable Object o) {
        if (o instanceof Foo) {
            Foo that = (Foo) o;
            return text.equals(that.text)
                    && number == that.number;
        }
        return false;
    }

    @Override
    public int hashCode() {
        int h$ = 1;
        h$ *= 1000003;
        h$ ^= text.hashCode();
        h$ *= 1000003;
        h$ ^=  number;
        return h$;
    }

    @Override
    public String toString() {
        return "Foo{"
                + "text=" + text + ", "
                + "number=" + number
                + "}";
    }

}

簡單的一個(gè)類,添加了equals,hashCode,toString方法之后一下子暴增了,并且添加一個(gè)字段之后,你不得不修改這幾個(gè)非常公式化的方法。最壞的情況,添加類似一個(gè)值類,你又得重復(fù)這些煩人的工作。
為什么會(huì)出現(xiàn)這么多的代碼?
1,固有的字段構(gòu)造函數(shù)和訪問函數(shù)
2,hashCode方法的主要作用是為了配合基于散列的集合一起正常運(yùn)行,這樣的散列集合包括HashSet、HashMap以及HashTable。當(dāng)向散列集合中插入對象時(shí),先調(diào)用這個(gè)對象的hashCode方法,得到對應(yīng)的hashcode值,實(shí)際上在HashMap的具體實(shí)現(xiàn)中會(huì)用一個(gè)table保存已經(jīng)存進(jìn)去的對象的hashcode值,如果table中沒有該hashcode值,它就可以直接存進(jìn)去,不用再進(jìn)行任何比較了;如果存在該hashcode值, 就調(diào)用它的equals方法與新元素進(jìn)行比較,相同的話就不存了,不相同就散列其它的地址,所以這里存在一個(gè)沖突解決的問題,這樣一來實(shí)際調(diào)用equals方法的次數(shù)就大大降低了。
看一個(gè)例子

class People{
    private String name;
    private int age;
     
    public People(String name,int age) {
        this.name = name;
        this.age = age;
    }  
     
    public void setAge(int age){
        this.age = age;
    }
         
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        return this.name.equals(((People)obj).name) && this.age== ((People)obj).age;
    }
}
        People p = new People("Jack", 12);
        System.out.println(p.hashCode());
             
        HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
        hashMap.put(p, 1);
         
        System.out.println(hashMap.get(new People("Jack", 12)));

你覺得會(huì)輸出1嗎?答案是輸出null,因?yàn)镻eople類沒有覆寫hashCode方法,導(dǎo)致new 的People與hashMap中的people的hashCode值不一樣。所以正確的做法是覆寫hashCode方法。
3,equals方法比較兩個(gè)對象是否相同。
4,toString可以使日志,調(diào)式更方便。

怎樣使用AutoValue

編寫一個(gè)類
1,這個(gè)類是抽象的
2,抽象的字段訪問函數(shù),沒有字段。
3,提供一個(gè)靜態(tài)的創(chuàng)建函數(shù)返回該類對象
4,類上標(biāo)記@AutoValue注解

@AutoValue
public abstract class Foo {//1,這個(gè)類是抽象的
  //3,提供一個(gè)靜態(tài)的創(chuàng)建函數(shù)返回該類對象
  public static Foo create(String text, int number) {
    return new AutoValue_Foo(text, number);//autovalue生成的類名為AutoValue_Foo
  }

  /** Documentation here. */
  public abstract String text(); //2,抽象的字段訪問函數(shù),沒有字段。

  /** Documentation here. */
  public abstract int number();
}

AutoValue替我們生成的類

final class AutoValue_Foo extends Foo { //注意:該類不是public
  private final String text;
  private final int number;

  AutoValue_Foo(String text, int number) {
    if (text == null) {
      throw new NullPointerException("text");
    }
    this.text = text;
    this.number = number;
  }

  @Override public String text() {
    return text;
  }

  @Override public int number() {
    return number;
  }

   @Override
    public boolean equals(@Nullable Object o) {
        if (o instanceof Foo) {
            Foo that = (Foo) o;
            return text.equals(that.text)
                    && number == that.number;
        }
        return false;
    }

    @Override
    public int hashCode() {
        int h$ = 1;
        h$ *= 1000003;
        h$ ^= text.hashCode();
        h$ *= 1000003;
        h$ ^=  number;
        return h$;
    }

    @Override
    public String toString() {
        return "Foo{"
                + "text=" + text + ", "
                + "number=" + number
                + "}";
    }
}

如果你想使用Builder模式,那么也可以
編寫一個(gè)類
1,這個(gè)類是抽象的
2,抽象的字段訪問函數(shù),沒有字段。
3,提供一個(gè)靜態(tài)抽象內(nèi)嵌類Builder,打上@ @AutoValue.Builder注解
4,靜態(tài)抽象內(nèi)嵌類Builder提供抽象字段設(shè)置方法
5,靜態(tài)抽象內(nèi)嵌類Builder提供抽象build方法,返回值是外部類
6,提供一個(gè)靜態(tài)的builder方法返回內(nèi)嵌類Builder
7,類上標(biāo)記@AutoValue注解

@AutoValue
public abstract class Foo {

    abstract  String text();
    abstract int number();

    public static Builder builder(){
        return new AutoValue_Foo.Builder();
    }


    @AutoValue.Builder
    abstract static class Builder{

        abstract Builder setText(String text);
        abstract Builder setNumber(int number);
        abstract Foo build();
    }

}

AutoValue替我們生成的類

@Generated("com.google.auto.value.processor.AutoValueProcessor")
 final class AutoValue_Foo extends Foo {

  private final String text;
  private final int number;

  private AutoValue_Foo(
      String text,
      int number) {
    this.text = text;
    this.number = number;
  }

  @Override
  String text() {
    return text;
  }

  @Override
  int number() {
    return number;
  }

  @Override
  public String toString() {
    return "Foo{"
         + "text=" + text + ", "
         + "number=" + number
        + "}";
  }

  @Override
  public boolean equals(Object o) {
    if (o == this) {
      return true;
    }
    if (o instanceof Foo) {
      Foo that = (Foo) o;
      return (this.text.equals(that.text()))
           && (this.number == that.number());
    }
    return false;
  }

  @Override
  public int hashCode() {
    int h$ = 1;
    h$ *= 1000003;
    h$ ^= text.hashCode();
    h$ *= 1000003;
    h$ ^= number;
    return h$;
  }

  static final class Builder extends Foo.Builder {
    private String text;
    private Integer number;
    Builder() {
    }
    @Override
    Foo.Builder setText(String text) {
      if (text == null) {
        throw new NullPointerException("Null text");
      }
      this.text = text;
      return this;
    }
    @Override
    Foo.Builder setNumber(int number) {
      this.number = number;
      return this;
    }
    @Override
    Foo build() {
      String missing = "";
      if (this.text == null) {
        missing += " text";
      }
      if (this.number == null) {
        missing += " number";
      }
      if (!missing.isEmpty()) {
        throw new IllegalStateException("Missing required properties:" + missing);
      }
      return new AutoValue_Foo(
          this.text,
          this.number);
    }
  }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,754評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,868評論 18 139
  • 轉(zhuǎn)自:http://blog.csdn.net/jackfrued/article/details/4492194...
    王帥199207閱讀 8,588評論 3 93
  • 苦雨暗霄漢, 濁酒對愁心。 屋檐滴白清冷, 燈影兩昏沉。 小徑蜿蜒霧影, 江水濤濤飛鷺, 空自伴繁音, 空自送歸客...
    漸醉墨韻閱讀 468評論 8 15
  • 這是一些無聊的東西。 1.每個(gè)人都想要窺視別人的內(nèi)心,但卻看到了自己,如果什么也沒看見,那就放棄,你發(fā)現(xiàn)不了它。 ...
    翠綠蘆薈閱讀 227評論 0 0