# 泛型基础

### 泛型类

```public class Box {
private String object;
public void set(String object) { this.object = object; }
public String get() { return object; }
}```

```public class Box<T> {
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}```

```Box<Integer> integerBox = new Box<Integer>();
Box<Double> doubleBox = new Box<Double>();
Box<String> stringBox = new Box<String>();```

## 泛型方法

```public class Util {
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
public class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public void setKey(K key) { this.key = key; }
public void setValue(V value) { this.value = value; }
public K getKey()   { return key; }
public V getValue() { return value; }
}```

```Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.<Integer, String>compare(p1, p2);```

```Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.compare(p1, p2);```

```public static <T> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e > elem)
++count;
return count;
}```

```public interface Comparable<T> {
public int compareTo(T o);
}```

```public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}```

# 通配符

`public void boxTest(Box<Number> n) { }`

```class Fruit {}
public class GenericReading {
static List<Apple> apples = Arrays.asList(new Apple());
static List<Fruit> fruit = Arrays.asList(new Fruit());
static class Reader<T> {
T readExact(List<T> list) {
return list.get(0);
}
}
static void f1() {
static class CovariantReader<T> {
T readCovariant(List<? extends T> list) {
return list.get(0);
}
}
static void f2() {
CovariantReader<Fruit> fruitReader = new CovariantReader<Fruit>();
Fruit f = fruitReader.readCovariant(fruit);
Fruit a = fruitReader.readCovariant(apples);
}
public static void main(String[] args) {
f2();
}```

# PECS原则

```public class GenericsAndCovariance {
public static void main(String[] args) {
List<? extends Fruit> flist = new ArrayList<Apple>();
flist.add(null);
Fruit f = flist.get(0);
}
}```

```List<? extends Fruit> flist = new ArrayList<Fruit>();
List<? extends Fruit> flist = new ArrayList<Apple>();
List<? extends Fruit> flist = new ArrayList<Orange>();```

```public class GenericWriting {
static List<Apple> apples = new ArrayList<Apple>();
static List<Fruit> fruit = new ArrayList<Fruit>();
static <T> void writeExact(List<T> list, T item) {
list.add(item);
}
static void f1() {
writeExact(apples, new Apple());
writeExact(fruit, new Apple());
}
static <T> void writeWithWildcard(List<? super T> list, T item) {
list.add(item)
}
static void f2() {
writeWithWildcard(apples, new Apple());
writeWithWildcard(fruit, new Apple());
}
public static void main(String[] args) {
f1(); f2();
}
}```

```List<? super Apple> list = new ArrayList<Apple>();
List<? super Apple> list = new ArrayList<Fruit>();
List<? super Apple> list = new ArrayList<Object>();```

“Producer Extends” – 如果你需要一个只读List，用它来produce T，那么使用? extends T。

“Consumer Super” – 如果你需要一个只写List，用它来consume T，那么使用? super T。

```public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i=0; i<src.size(); i++)
dest.set(i, src.get(i));
}
}```

# 类型擦除

Java泛型中最令人苦恼的地方或许就是类型擦除了，特别是对于有C++经验的程序员。类型擦除就是说Java泛型只能用于在编译期间的静态类型检查，然后编译器生成的代码会擦除相应的类型信息，这样到了运行期间实际上JVM根本就知道泛型所代表的具体类型。这样做的目的是因为Java泛型是1.5之后才被引入的，为了保持向下的兼容性，所以只能做类型擦除来兼容以前的非泛型代码。对于这一点，如果阅读Java集合框架的源码，可以发现有些类其实并不支持泛型。

```public class Node<T> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
public T getData() { return data; }
}```

```public class Node {
private Object data;
private Node next;
public Node(Object data, Node next) {
this.data = data;
this.next = next;
}
public Object getData() { return data; }
}```

```public class Node<T extends Comparable<T>> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
public T getData() { return data; }
}```

```public class Node {
private Comparable data;
private Node next;
public Node(Comparable data, Node next) {
this.data = data;
this.next = next;
}
public Comparable getData() { return data; }
}```

`List<Integer>[] arrayOfLists = new List<Integer>[2]; `

```Object[] strings = new String[2];
strings[0] = "hi";
strings[1] = 100;   ```

```Object[] stringLists = new List<String>[];
stringLists[0] = new ArrayList<String>();
stringLists[1] = new ArrayList<Integer>();```

```public class ErasedTypeEquivalence {
public static void main(String[] args) {
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
}
}```

```public class Node<T> {
public T data;
public Node(T data) { this.data = data; }
public void setData(T data) {
System.out.println("Node.setData");
this.data = data;
}
}
public class MyNode extends Node<Integer> {
public MyNode(Integer data) { super(data); }
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}```

```public class Node {
public Object data;
public Node(Object data) { this.data = data; }
public void setData(Object data) {
System.out.println("Node.setData");
this.data = data;
}
}
public class MyNode extends Node {
public MyNode(Integer data) { super(data); }
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}```

```MyNode mn = new MyNode(5);
Node n = mn;
n.setData("Hello");```

```class MyNode extends Node {
public void setData(Object data) {
setData((Integer) data);
}
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}```

```public static <E> void append(List<E> list) {
E elem = new E();
list.add(elem);
}```

```public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance();
list.add(elem);
}```

```List<String> ls = new ArrayList<>();
append(ls, String.class);```

```public static <E> void rtti(List<E> list) {
if (list instanceof ArrayList<Integer>) {
}
}
=> { ArrayList<Integer>, ArrayList<String>, LinkedList<Character>, ... }```

```public static void rtti(List<?> list) {
if (list instanceof ArrayList<?>) {
}
}```

```package typeinfo.factory;
public interface Factory<T> {
T create();
}```

```class Filter extends Part {}
class FuelFilter extends Filter {
public static class Factory implements typeinfo.factory.Factory<FuelFilter> {
public FuelFilter create() {
return new FuelFilter();
}
}
}
class AirFilter extends Filter {
public static class Factory implements typeinfo.factory.Factory<AirFilter> {
public AirFilter create() {
return new AirFilter();
}
}
}```
```class Belt extends Part {}
class FanBelt extends Belt {
public static class Factory implements typeinfo.factory.Factory<FanBelt> {
public FanBelt create() {
return new FanBelt();
}
}
}
class GeneratorBelt extends Belt {
public static class Factory implements typeinfo.factory.Factory<GeneratorBelt> {
public GeneratorBelt create() {
return new GeneratorBelt();
}
}
}```

Part类的实现如下，注意我们上面的实体类都是Part类的间接子类。在Part类我们注册了我们上面的声明的实体类。所以以后我们如果要创建相关的实体类的话，只需要在调用Part类的相关方法了。这么做的一个好处就是如果的业务中出现了CabinAirFilter或者PowerSteeringBelt的话，我们不需要修改太多的代码，只需要在Part类中将它们注册即可。

```class Part {
static List<Factory<? extends Part>> partFactories =
new ArrayList<Factory<? extends Part>>();
static {
partFactories.add(new FuelFilter.Factory());
partFactories.add(new AirFilter.Factory());
partFactories.add(new FanBelt.Factory());
partFactories.add(new PowerSteeringBelt.Factory());
}
private static Random rand = new Random(47);
public static Part createRandom() {
int n = rand.nextInt(partFactories.size());
return partFactories.get(n).create();
}
public String toString() {
return getClass().getSimpleName();
}
}```

```public class RegisteredFactories {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(Part.createRandom());
}
}
}```

# References

• ORACLE-DOCUMENTATION
• THINKING IN JAVA
• EFFECTIVE JAVA

0 条评论

• ### Spring的BeanUtils有坑？可能是你用错了！

在这里，我们今天重点说的是第二点，第一点是因为用反射拿到set和get方法再去拿属性值和设置属性值的，不懂反射的人可以自行百度下。第三和第四点很简单了应该是不需...

• ### 面试必问：Spring 循环依赖的三种方式

引言：循环依赖就是N个类中循环嵌套引用，如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用，直至内存溢出报错。下面说一下Sp...

• ### 为什么阿里代码规约要求避免使用 Apache BeanUtils 进行属性复制

有一次开发过程中，刚好看到小伙伴在调用 set 方法，将数据库中查询出来的 Po 对象的属性拷贝到 Vo 对象中，类似这样：

• ### Java泛型详解

Java泛型是jdk1.5中引入的一个新特性，泛型提供了编译时的类型检测机制，该机制允许程序员在编译时检测到非法的类型。 泛型是Java中一个非常重要的知识点，...

• ### Java 泛型详解

泛型是Java中一个非常重要的知识点，在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java泛型的设计，将会涉及到通配符处理，以及让人苦恼的类...

• ### Spring中老生常谈的FactoryBean

FactoryBean和BeanFactory由于在命名上极其相似，一直以来困扰了不少的开发者。

• ### Java基础（四）线程快速了解

其实可以理解是java的压缩包 方便使用，只要在classpath设置jar路径即可 数据库驱动，ssh框架等都是以jar包体现的

• ### java应用CAS

CAS（Compare and Swap），即比较并替换。jdk里的大量源码通过CAS来提供线程安全操作，比如AtomicInteger类。下面我们来分析一...