背景
自己编写一个并重写equals,hashCode方法,很容易出错.而使用IDE工具生成的方法又显得十分”臃肿”.于是AutoValue应运而生.AutoValue最低支持Java 8.
官方仓库地址: https://github.com/google/auto/tree/master/value
引入依赖
Maven
引入注解包:
<dependencies> <dependency> <groupId>com.google.auto.value</groupId> <artifactId>auto-value-annotations</artifactId> <version>${auto-value.version}</version> </dependency> </dependencies>
处理注解:
<build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <annotationProcessorPaths> <path> <groupId>com.google.auto.value</groupId> <artifactId>auto-value</artifactId> <version>${auto-value.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>
上面的这个,也可以像下面这样定义(注意: 您可以将处理器本身包含在编译时的类路径中。这样做可能会将不必要的类拉到您的运行时类路径中。):
<dependencies> <dependency> <groupId>com.google.auto.value</groupId> <artifactId>auto-value</artifactId> <version>${auto-value.version}</version> <optional>true</optional> </dependency> </dependencies>
Gradle
dependencies { // Use 'api' rather than 'compile' for Android or java-library projects. compile "com.google.auto.value:auto-value-annotations:${autoValueVersion}" annotationProcessor "com.google.auto.value:auto-value:${autoValueVersion}" }
发生了什么?
AutoValue在javac内作为标准注释处理器运行。它读取您的抽象类并推断实现类的外观。它在您的程序包中生成一个具体实现类的源代码,该类扩展了您的抽象类,具有:
- 包装可见性(非公开)
- 每个抽象访问器方法一个字段
- 设置这些字段的构造函数
- 返回相关字段值的每个访问器方法的具体实现
- 一个以常规方式比较这些值的equals实现
- 适当的对应hashCode
- 返回实例的有用(但未指定)字符串表示形式的toString实现
如上所示,您的手写代码将其工厂方法调用委派给了生成的构造函数和方法!
请注意,您类的调用者不需要了解任何这些。 它们只是调用您提供的工厂方法,并返回行为良好的实例。
警告
注意不要将参数以错误的顺序意外传递给生成的构造函数。 您必须确保测试足以捕获任何现场订购问题。 在大多数情况下,这应该是测试创建此值类别的任何实际目的的自然结果! 在其他情况下,只需执行上面显示的非常简单的测试即可。 考虑切换到使用builder选项来避免此问题。
我们保留随时更改hashCode实现的权利。 永远不要保留hashCode的结果或将其用于任何其他意外目的,也要小心不要依赖于您的值在HashSet之类的无序集合中出现的顺序。
示例
pom.xml
<dependencies> <dependency> <groupId>com.google.auto.value</groupId> <artifactId>auto-value</artifactId> <version>1.7</version> <optional>true</optional> </dependency> <dependency> <groupId>com.google.auto.value</groupId> <artifactId>auto-value-annotations</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>compile</scope> </dependency> </dependencies>
AutoValueTest.java
Animal在IDE中可能会提示错误,忽略即可.
import com.google.auto.value.AutoValue; import static org.junit.Assert.*; @AutoValue abstract class Animal { static Animal create(String name, int numberOfLegs) { return new AutoValue_Animal(name, numberOfLegs); } abstract String name(); abstract int numberOfLegs(); } public class AutoValueTest { public static void main(String[] args) { Animal dog = Animal.create("dog", 4); assertEquals("dog", dog.name()); assertEquals(4, dog.numberOfLegs()); // You probably don't need to write assertions like these; just illustrating. assertTrue(Animal.create("dog", 4).equals(dog)); assertFalse(Animal.create("cat", 4).equals(dog)); assertFalse(Animal.create("dog", 2).equals(dog)); assertEquals("Animal{name=dog, numberOfLegs=4}", dog.toString()); } }
运行AutoValueTest.java,如果没有输出错误,则正常.
Animal抽象类,经过AutoValue生成的代码如下:
import javax.annotation.Generated; @Generated("com.google.auto.value.processor.AutoValueProcessor") final class AutoValue_Animal extends Animal { private final String name; private final int numberOfLegs; AutoValue_Animal(String name, int numberOfLegs) { if (name == null) { throw new NullPointerException("Null name"); } this.name = name; this.numberOfLegs = numberOfLegs; } @Override String name() { return name; } @Override int numberOfLegs() { return numberOfLegs; } @Override public String toString() { return "Animal{" + "name=" + name + ", " + "numberOfLegs=" + numberOfLegs + "}"; } @Override public boolean equals(Object o) { if (o == this) { return true; } if (o instanceof Animal) { Animal that = (Animal) o; return this.name.equals(that.name()) && this.numberOfLegs == that.numberOfLegs(); } return false; } @Override public int hashCode() { int h = 1; h *= 1000003; h ^= this.name.hashCode(); h *= 1000003; h ^= this.numberOfLegs; return h; } }
更多想知道的问题
点: 我怎么?