泛型实现了参数化类型的概念,使代码可以应用于多种类型
在创建参数化类型的一个实例的时候,编译器会自动转型,保证类型的正确性
简单泛型
class Automobile{}
public class Holder1 {
private Automobile a;
public Holder1(Automobile a){
this.a = a;
}
Automobile get(){ //这个类无法持有其他任何类型的对象
return a;
}
}
public class Holder2 {
private Object a;
public Holder2(Object a){
this.a = a;
}
public void set(Object a){
this.a = a;
}
public Object get(){
return a;
}
public static void main(String[] args) {
final Holder2 h2 = new Holder2(new Automobile());
Automobile a = (Automobile) h2.get();
h2.set("Not an Automobile");
String s = (String) h2.get();
System.out.println(s);
h2.set(1);
Integer i = (Integer) h2.get(); //存储了三种不同类型的对象
System.out.println(i);
}
}
泛型的只要目的之一就是用来指定容器要持有什么类型的对象
暂时不指定具体类型,稍后再决定具体使用什么类型
public class Holder3 <T>{
private T a;
public Holder3(T a) {
this.a = a;
}
public void set(T a){
this.a = a;
}
public T get(){
return a;
}
public static void main(String[] args) {
Holder3<Automobile> h3 = new Holder3<Automobile>(new Automobile());
//此时只可以存入Automobile类型的参数
Automobile a = h3.get();
}
}
堆栈类
public class LinkedStack<T> {
private static class Node<U> {
U item;
Node<U> next;
Node() {//没有元素的时候都是空
item = null;
next = null;
}
Node(U item, Node<U> next) {
this.item = item;
this.next = next;
}
boolean end() { //判断栈是否为空
return item == null && next == null;
}
}
private Node<T> top = new Node<>(); // 末端哨兵,判断何时为空
public void push(T item) {// 向栈中压入新的元素时,top会指向新进来的元素
top = new Node<>(item, top);
}
public T pop() {//取出元素时,如果不是最后一个元素,那么这个top会指向本来top元素指向的下一个元素
T result = top.item;
if (!top.end()) {
top = top.next;
}
return result;
}
public static void main(String[] args) {
final LinkedStack<String> lss = new LinkedStack<>();
for (String s : "Phasers or stun".split(" ")) {
lss.push(s);
}
String s;
while ((s = lss.pop()) != null) {
System.out.println(s);
}
}
}
RandomList
假设需要一个持有特定类型的对象列表,每次调用它的select方法的时候,都可以随机选取一个元素
public class RandomList<T> {
private ArrayList<T> storage = new ArrayList<>();
private Random rand = new Random(47);
public void add(T item){ //向容器中添加元素
storage.add(item);
}
public T select(){ //调用这个方法时会从容器容器中随机读取元素
return storage.get(rand.nextInt(storage.size())); //获取边界值
}
public static void main(String[] args) {
RandomList<String> rs = new RandomList<>();
for (String s : ("take the way home").split(" ")) {
rs.add(s); //将字符串添加到集合中
}
for (int i = 0; i < 4; i++) {
System.out.print(rs.select() + " ");
}
}
}
泛型接口
泛型也可以应用于接口(譬如生成器(generator)),这是一个专门负责创建对象的类,这也是工厂设计的一种模式,但是使用生成器创建对象的时候,不需要任何的参数,工厂方法一般是需要参数的。
生成器不需要任何的额外信息就知道如何创建新的对象。
public class CoffeeGenerator implements Generator<Coffee>{
private Class[] types = {Americano.class, Breve.class, Cappuccino.class, Latte.class, Mocha.class};
private Random rand = new Random(47);
public CoffeeGenerator(){}
@Override
public Coffee next() { //用生成器来随机的创建实例
try {
return (Coffee) types[rand.nextInt(types.length)].newInstance();
//必须确定返回值是参数的类型
} catch (Exception e) {
throw new RuntimeException();
}
}
public static void main(String[] args) {
final CoffeeGenerator gen = new CoffeeGenerator();
for (int i = 0; i < 5; i++) {
System.out.println(gen.next());
}
} //并没有知道什么具体的信息,也可以用迭代器来实现
}
使用生成器创建斐波那契数列
public class Fibonacci implements Generator<Integer> {
private int count = 0;
@Override
public Integer next() {
return fib(count++);
}
private int fib(int n){
return (n < 2 ? 1 : (fib(n - 2) + fib(n - 1)));
}
public static void main(String[] args) {
final Fibonacci gen = new Fibonacci();
for (int i = 0; i < 18; i++) {
System.out.print(gen.next() + " ");
}
}
}
Java泛型的局限性:基本类型无法作为类型参数
使用适配器:
public class IterableFibonacci extends Fibonacci implements Iterable<Integer>{
private int n ;
public IterableFibonacci(int count){
n = count;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
@Override
public boolean hasNext() {
return n > 0;
}
@Override
public Integer next() {
n--;
return IterableFibonacci.this.next();
}
};
}
public static void main(String[] args) {
for (Integer integer : new IterableFibonacci(18)) {
System.out.print(integer + " ");
}
}
}
泛型方法
泛型可以用在方法上,并且所在的类可以不是泛型类,是否拥有泛型方法,和是不是泛型类没有关系
对于一个static的方法,无法访问泛型类的类型参数,所以,如果static使用泛型的能力,就必须让他称为泛型方法
定义泛型方法,只需要的方法前面放泛型参数列表
public class GenericMethods {
public <T> void f(T t){ //方法前面加泛型列表
System.out.println(t.getClass().getName());
}
public static void main(String[] args) {
final GenericMethods gen = new GenericMethods();
gen.f("hah");
gen.f(1);
gen.f(1.0);
gen.f('t');
gen.f(1.0F);
}
}
杠杆利用类型参数推断
编写一个工具类,包含各种各样的static方法,专门用来创建各种常用的容器对象
public class New {
public static <K,V> Map<K,V> map(){
return new HashMap<K,V>();
}
public static <T> List<T> list(){
return new ArrayList<>();
}
public static <T> LinkedList<T> lList(){
return new LinkedList<>();
}
public static <T> Set<T> set(){
return new HashSet<>();
}
public static <T> Queue<T> queue(){
return new LinkedList<>();
}
public static void main(String[] args) {
final Map<String, Integer> objectObjectMap = New.map();
final List<String> list = New.list();
LinkedList<String> llist = New.lList();
final Set<String> set = New.set();
final Queue<String> queue = New.queue();
}
}
可变类型参数和泛型
public class GenericVarargs {
public static <T> List<T> makeList(T... args){ //可变参数列表
List<T> result = new ArrayList<>();
for (T arg : args) {
result.add(arg);
}
return result;
}
public static void main(String[] args) {
List<String> ls = makeList("A");
System.out.println(ls);
ls = makeList("A","B","C");
System.out.println(ls);
}
}
用于Generators的泛型方法
利用生成器填充Collection
public class Generators {
public static <T>Collection<T> fill(Collection<T> coll,Generator<T> gen,int n){
//创建一个方法,利用生成器向容器中添加元素
for (int i = 0; i < n; i++) {
coll.add(gen.next());
}
return coll;
}
public static void main(String[] args) {
Collection<Coffee> coffee = fill(new ArrayList<Coffee>(), new CoffeeGenerator(), 4);
for (Coffee c : coffee) {
System.out.print(c + " ");
}
System.out.println();
Collection<Integer> integers = fill(new ArrayList<Integer>(), new Fibonacci(), 18);
for (Integer integer : integers) {
System.out.print(integer + " ");
}
}
}
通用的Generator
public class BasicGenerator<T> implements Generator<T> {
private Class<T> type;
public BasicGenerator(Class<T> type){
this.type = type;
}
@Override
public T next() {
try {
return type.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException();
}
}
public static <T> Generator<T> creat(Class<T> type){
return new BasicGenerator<T>(type);
} //提供了一个基本的实现,用来生成某个类的对象
//只需要调用creatfangfa,传想要生成的类型
}
public class CountedObject {
private static long counter = 0;
private final long id = counter++;
public long id(){
return id;
}
@Override
public String toString() {
return "CountedObject" + id;}
}
public class BasicGeneratorDemo {
public static void main(String[] args) {
final Generator<CountedObject> gen = BasicGenerator.creat(CountedObject.class);
for (int i = 0; i < 5; i++) {
System.out.println(gen.next());
}
}
}
匿名内部类
泛型可以应用于内部类和匿名内部类
class Customer{
private static long counter = 1;
private final long id = counter ++;
private Customer(){}
@Override
public String toString() {
return "Customer " + id + " ";
}
public static Generator<Customer> generator(){
return new Generator<Customer>() { //使用匿名内部类来创建实例
@Override
public Customer next() {
return new Customer();
}
};
}
}
class Teller{
private static long counter = 1;
private final long id = counter++;
public Teller(){}
@Override
public String toString() {
return "Teller " + id + " ";
}
public static Generator<Teller> generator = new Generator<Teller>() {
@Override //使用局部内部类来创建方法
public Teller next() {
return new Teller();
}
};
}
public class BankTeller {
private static void serve(Teller t,Customer c){
System.out.println(t + " serves " + c);
}
public static void main(String[] args) {
final Random rand = new Random(47);
Queue<Customer> line = new LinkedList<>();
Generators.fill(line, Customer.generator(), 15); //利用生成器来创建对象
List<Teller> tellers = new ArrayList<>();
Generators.fill(tellers,Teller.generator,4);
for (Customer customer : line) {
serve(tellers.get(rand.nextInt(tellers.size())), customer);
//在teller中随机产生一个
}
}
}
构建复杂模型
class Product{
private int id;
private String description;
private double price;
public Product(int id, String description, double price) {
this.id = id;
this.description = description;
this.price = price;
System.out.println(toString());
}
@Override
public String toString() {
return id + ": " + description + ", price: $" + price;
}
public void priceChange(double change){
price += change;
}
public static Generator<Product> generator = new Generator<Product>() {
private Random rand = new Random(47);
@Override
public Product next() {
return new Product(rand.nextInt(1000), "Test",Math.round(rand.nextDouble())*1000+0.99);
}
};
}
class Shelf extends ArrayList<Product>{
public Shelf(int nProduct){
Generators.fill(this,Product.generator,nProduct);
}
}
class Aisle extends ArrayList<Shelf>{
public Aisle(int nShelves,int nProduct){
for (int i = 0; i < nShelves; i++) {
add(new Shelf(nProduct));
}
}
}
class CheckoutStand{}
class Office{}
public class Store extends ArrayList<Aisle>{
private ArrayList<CheckoutStand> checkouts = new ArrayList<>();
private Office office = new Office();
public Store(int nAisle, int nShelves, int nProduct) {
for (int i = 0; i < nAisle; i++) {
add(new Aisle(nShelves, nProduct));
}
}
@Override
public String toString() {
final StringBuilder result = new StringBuilder();
for (Aisle shelves : this) {
for (Shelf shelf : shelves) {
for (Product product : shelf) {
result.append(product);
result.append("\n");
}
}
}
return result.toString();
}
public static void main(String[] args) {
final Store aisles = new Store(2, 5, 3);
}
}
擦除的神秘之处
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);
}
}
此时发现输出结果是相等的
class Frob{}
class Fnorkle{}
class Quark<Q>{}
class Particle<POSITION, MOMENTUM>{}
public class LostInformation {
public static void main(String[] args) {
List<Frob> list = new ArrayList<>();
Map<Frob, Fnorkle> map = new HashMap<>();
Quark<Fnorkle> quark = new Quark<>();
Particle<Long, Double> particle = new Particle<>(); //表示由泛型声明所声明的类型参数
System.out.println(Arrays.toString(list.getClass().getTypeParameters()));
System.out.println(Arrays.toString(map.getClass().getTypeParameters()));
System.out.println(Arrays.toString(quark.getClass().getTypeParameters()));
System.out.println(Arrays.toString(particle.getClass().getTypeParameters()));
}
}
发现输出结果中只有用作参数占位符的标识符,说明:
在泛型代码的内部,无法获得任何有关泛型参数类型的信息。无法知道用来创建某个特定实例的实际类型参数
Java的泛型是用擦除实现的,意味着在使用泛型时,任何具体的类型信息都会被擦除,唯一知道的就是正在使用一个对象
public class Manipulation<T> {
private T obj;
public Manipulation(T x){
obj = x;
}
// public void manipulation(){ 此时找不到f方法,必须使用边界符,告诉编译器只能接受遵循
这个边界的类型
// obj.f()
// }
}
class Manipulation2<T extends HasF>{ //使用边界符,此时可以使用具体类型的方法
private T obj;
public Manipulation2(T x){
obj = x ;
}
public void manipulation(){
obj.f();
}
}
当希望代码可以跨多个类工作的时候,使用泛型才有所帮助,
public class RunGenericType<T extends HasF> {
private T obj;
public RunGenericType(T x){
obj = x;
}
public T get(){ //如果有一个返回T类型的方法,之后会返回确切的类型,
//也可以返回它的子类,并且不需要显示的类型转换
return obj;
}
}
迁移兼容性
在基于擦除的实现中,泛型类型都被当做第二类类型处理,就是不能在某些重要的上下文环境中使用。
向List
擦除的核心时他可以使泛化的客户端可以用非泛化的类库来使用,反之亦然,这经常被称为“迁移兼容性”
擦除的问题
泛型不能用于显示的引用运行时类型的操作之中,例如转型,instanceof操作和new表达式,因为所有有关类型的参数信息都丢失了
边界处的动作
public class ArrayMaker<T> {
private Class<T> kind;
public ArrayMaker(Class<T> kind){//泛型T无法获取Class对象,通过构造器传进去一个Class实例
this.kind = kind;
}
T[] create(int size){
return (T[]) Array.newInstance(kind, size); //必须将其转为T类型的数组
}
public static void main(String[] args) {
ArrayMaker<String> stringmaker = new ArrayMaker<>(String.class);
String[] stringArray = stringmaker.create(10);
System.out.println(Arrays.toString(stringArray));
}
}
即使kind被存储为Class
在泛型中创建数组,最好使用Array.newInstance
如果创建的时容器不是数组就不同了
public class ListMaker<T> {
List<T> create(){
return new ArrayList<>();
}
public static void main(String[] args) {
ListMaker<String> stringListMaker = new ListMaker<>();
List<String> stringsList = stringListMaker.create();
//调用方法来创建容器
}
}
public class FilledListMaker<T> {
List<T> create(T t,int n){
List<T> result = new ArrayList<>();
for (int i = 0; i < n; i++) {
result.add(t);
}
return result;
}
public static void main(String[] args) {
FilledListMaker<String> stringFilledListMaker = new FilledListMaker<>();
List<String> list = stringFilledListMaker.create("Hello" , 4);
System.out.println(list);
}
}
擦除的补偿
擦除丢失了泛型代码中执行某些操作的能力,任何在运行时需要知道确切类型信息的操作都没办法正常工作
public class Erased<T> {
private final int SIZE = 100;
public static void f(Object arg){ //需要知道确切类型信息的都不能使用
//if (arg instanceof T);
//T t = new T;
//T[] array = new T[SIZE];
}
}
有时必须引入类型标签Class来对擦除进行补偿,必须显示的传递类型的Class对象
class Building{}
class House extends Building{}
public class ClassTypeCapture<T> {
Class<T> kind;
public ClassTypeCapture(Class<T> kind){ //使用Class标签对擦除进行补偿
this.kind = kind;
}
public boolean f(Object arg){
return kind.isInstance(arg);
}
public static void main(String[] args) {
final ClassTypeCapture<Building> ctt1 = new ClassTypeCapture<>(Building.class);
//传入Class对象
System.out.println(ctt1.f(new Building()));
System.out.println(ctt1.f(new House()));
final ClassTypeCapture<House> ctt2 = new ClassTypeCapture<>(House.class);
System.out.println(ctt2.f(new Building()));
System.out.println(ctt2.f(new House()));
}
}
创建类型实例
传递一个工厂对象,并且用它来创建实例,使用类型标签来使用newInstance方法来创建这个类型的新对象
使用newInstance创建某个类的实例的时候,这个类必须有默认的构造器,并且只能运行时发现这个错误
class ClassAsFactory<T>{
T x;
public ClassAsFactory(Class<T> kind){
try {
x = kind.newInstance();
} catch (Exception e) {
throw new RuntimeException();
}
}
}
class Employee{}
public class InstantiateGenericType {
public static void main(String[] args) {
final ClassAsFactory<Employee> fe = new ClassAsFactory<>(Employee.class);
System.out.println("ClassAsFactory<Employee> succeeded");
try {
final ClassAsFactory<Integer> fi = new ClassAsFactory<>(Integer.class);
//失败的原因时Integer没有默认构造器,并且不是在编译器捕获的
}catch (Exception e){
System.out.println("失败");
}
}
}
interface FactoryI<T>{
T create();
}
class Foo2<T>{
private T x;
public Foo2(FactoryI<T> factoryI){
x = factoryI.create();
}
}
class IntegerFactory implements FactoryI<Integer>{
@Override
public Integer create() {
return new Integer(0);
}
}
class Widget{
public static class Factory implements FactoryI<Widget>{
@Override
public Widget create() {
return new Widget();
}
}
}
public class FactoryConstraint {
public static void main(String[] args) {
new Foo2<Integer>(new IntegerFactory());
new Foo2<Widget>(new Widget.Factory());
}
}
两种方式都创建了工厂对象,第二种时传递Class
还有一种时模板设计模式,在本例中create()是模板方法
abstract class GenericWithCreate<T>{
final T element;
abstract T create(); //create是模板方法,他在子类中定义,产生子类的对象
public GenericWithCreate(){
element = create();
}
}
class X{}
class Creator extends GenericWithCreate<X>{
@Override
X create() {
return new X();
}
void f(){
System.out.println(element.getClass().getSimpleName());
}
}
public class CreatorGeneric {
public static void main(String[] args) {
final Creator creator = new Creator();
creator.f();
}
}
泛型数组
泛型数组不能创建,一般是在创建泛型数组的地方使用ArrayList
public class ListOfGenerics <T>{
private List<T> list = new ArrayList<>();
public void add(T item){
list.add(item);
}
public T get(int index){
return list.get(index);
}
}
成功创建泛型数组的唯一方式就是创建一个被擦除的类型的新数组,然后对其转型。
public class GenericArray<T> {
private T[] array;
public GenericArray(int size){
array = (T[]) new Object[size];
}
public void put(int index,T item){
array[index] = item;
}
public T get(int index){
return array[index];
}
public T[] rep(){ //实际运行时的类型时Object
return array;
}
public static void main(String[] args) {
final GenericArray<Integer> gai = new GenericArray<>(10);
Object[] o = gai.rep();//并不能直接声明T[] array = new T[size],所以要创建一个对象
//数组,然后将他转型
}
因为擦除,所以数组运行时的类型时Object类型的
可以利用反射来创建具体的实例,将Class
public class GenericArrayWithTypeToken<T> {
private T[] array;
public GenericArrayWithTypeToken(Class<T> type , int size){
array = (T[]) Array.newInstance(type, size);//利用反射来创建实例
}
public void put(int index,T item){
array[index] = item;
}
public T get(int index){
return array[index];
}
public T[] rep(){
return array;
}
public static void main(String[] args) {
final GenericArrayWithTypeToken<Integer> gai = new GenericArrayWithTypeToken<Integer>(Integer.class,10);
Integer[] ia = gai.rep();
}
}
边界
边界可以用于泛型的参数类型上设置条件。并且一个更重要的效果使可以按照自己的边界类型来调用方法
class HoldItem<T>{
T item;
HoldItem(T item){
this.item = item;
}
T getItem(){
return item;
}
}
class Colored2 <T extends HasColor> extends HoldItem<T>{
Colored2(T item){
super(item);
}
java.awt.Color color(){
return item.getColor();
}
}
//具体的类要在前面
class ColoredDimension2<T extends Dimension & HasColor > extends Colored2<T>{
//这里继承了Colored2,没有重写,但是仍有这个方法
ColoredDimension2(T item){
super(item);
}
int getX(){
return item.x;
}
int getY(){
return item.y;
}
int getZ(){
return item.z;
}
}
class Solid2 <T extends Dimension & HasColor & Weight> extends ColoredDimension2{
Solid2(T item) {
super(item);
}
}
public class InheritBounds {
public static void main(String[] args) {
final Solid2<Bound> solid2 = new Solid2<>(new Bound());
solid2.getX();
solid2.getY();
solid2.getZ();
solid2.color();
}
}
interface SuperPower{}
interface XRayVision extends SuperPower{
void seeThroughWalls();
}
interface SuperHearing extends SuperPower{
void hearSubtleNoises();
}
interface SuperSmell extends SuperPower{
void trackBySmell();
}
class SuperHero<POWER extends SuperPower>{
POWER power;
SuperHero(POWER power){
this.power = power;
}
POWER getPower(){
return power;
}
}
class SuperSleuth<POWER extends XRayVision> extends SuperHero<POWER>{
SuperSleuth(POWER power){
super(power);
}
}
class CanineHero<POWER extends SuperHearing & SuperSmell> extends SuperHero<POWER>{
//限定了superhear和supersmell
CanineHero(POWER power){
super(power);
}
void hear(){
power.hearSubtleNoises();
}
void smell(){
power.trackBySmell();
}
}
class SuperHearSmell implements SuperHearing,SuperSmell{
//实现了SuperHearing和SuperSmell,建立起了联系
@Override
public void hearSubtleNoises() {}
@Override
public void trackBySmell() {}
}
class DogBoy extends CanineHero<SuperHearSmell>{
DogBoy(){
super(new SuperHearSmell());
}
}
public class EpicBattle {
static <POWER extends SuperHearing> void usrSuperHearing (SuperHero<POWER> hero){
hero.getPower().hearSubtleNoises();
}
static <POWER extends SuperHearing & SuperSmell> void superFind(SuperHero<POWER> hero){
hero.getPower().hearSubtleNoises();
hero.getPower().trackBySmell();
}
public static void main(String[] args) {
final DogBoy dogBoy = new DogBoy();
usrSuperHearing(dogBoy);
superFind(dogBoy);
}
}
通配符
向导出类数组中加入基类类型的引用
class Fruit{}
class Apple extends Fruit{}
class Orange extends Fruit{}
class Jonathan extends Apple{}
public class CovariantArrays {
public static void main(String[] args) {
Fruit[] fruits = new Apple[10];//此时的数组类型是Apple类型的,只可以向里面放入
//Apple类型或者其子类型,如果插入fruits编译器不会报错
//但是运行起来就会报错
fruits[0] = new Apple();
fruits[1] = new Jonathan();
try {
fruits[0] = new Fruit();
}catch (Exception e){
System.out.println(e);
}
try {
fruits[0] = new Orange();
}catch (Exception e){
System.out.println(e);
}
}
}
泛型的目标之一就是将这种错误检测给他弄到编译期
public class GenericAndCovariance {
public static void main(String[] args) {
List<? extends Fruit> flist = new ArrayList<Apple>();
//flist.add(new Apple());
flist.add(null);
System.out.println(flist.get(0));
}
}
使用了<? extands Fruit> 发现不能使用容器的方法,只能使用Object的方法
public class CompilerIntelligence {
public static void main(String[] args) {
List<? extends Fruit> flist = Arrays.asList(new Apple());
Apple a = (Apple) flist.get(0);
flist.contains(new Apple());//允许调用,是因为这两个方法的参数是Object
flist.indexOf(0);
}
}
超类型通配符
<? super MyClass> MyClass的子类
public class SuperTypeWIldCards {
static void writeTo(List<? super Apple> apples){
apples.add(new Apple());
apples.add(new Jonathan());
//apples.add(new Fruit());//Fruit不是Apple的子类
}
}
public class GenericWriting {
static <T> void writeExact(List<T> list , T item){
list.add(item);
}
static List<Apple> apples = new ArrayList<>();
static List<Fruit> fruits = new ArrayList<>();
static void f1(){
writeExact(apples,new Apple());
} //前面的<T>代表了参数类型
static <T> void writeWithWildcard(List<? super T> list , T item){
list.add(item);//超类型通配符可以用泛型方法
}
static void f2(){
//确定了容器的类型后,就只能持有他或这它的子类了
writeWithWildcard(apples, new Jonathan());
writeWithWildcard(fruits, new Fruit());
}
public static void main(String[] args) {
f1();
f2();
}
}
无界通配符
<?> 意味着任何事物
public class UnboundedWildcards {
static List list1;
static List<?> list2;
static List<? extends Object> list3;
static void assign1(List list){
list1 = list;
list2 = list;
//list3 = list;
}
static void assign2(List<?> list){
list1 = list;
list2 = list;
list3 = list;
}
static void assign3(List<? extends Object> list){
list1 = list;
list2 = list;
list3 = list;
}
public static void main(String[] args) {
assign1(new ArrayList<>());
assign2(new ArrayList<>());
assign3(new ArrayList<>());
assign1(new ArrayList<String>());
assign2(new ArrayList<String>());
assign3(new ArrayList<String>());
}
}
public class UnboundedWildcard2 {
static Map map1;
static Map<?,?> map2;
static Map<String,?> map3;
static void assign1(Map map){
map1 = map;
}
static void assign2(Map<?,?> map){
map2 = map;
}
static void assign3(Map<String,?> map){
map3 = map;
}
public static void main(String[] args) {
assign1(new HashMap());
assign2(new HashMap());
assign3(new HashMap());
assign1(new HashMap<String,Integer>());
assign2(new HashMap<String,Integer>());
assign3(new HashMap<String,Integer>());
}
}
List表示“持有任何Object类型的List”,List<?>表示“持有某种特定类型的”List,只是不知道是什么类型
转型和警告
class FixedSizeStack<T>{
private int index =0;
private Object[] storage;
public FixedSizeStack(int size){
storage = new Object[size];//存储是将值都转换成为Object
}
public void push(T item){
storage[index++] = item;
}
public T pop(){
return (T) storage[--index];//取出时转换称为T类型的
}
}
public class GenericCast {
public static final int SIZE = 7;
public static void main(String[] args) {
final FixedSizeStack<String> strings = new FixedSizeStack<>(SIZE);
for (String s : "A B C D E F G".split(" ")) {
strings.push(s);
}
for (int i = 0; i < SIZE; i++) {
String s = strings.pop();
System.out.print(s + " ");
}
}
}
基类劫持接口(基类限定接口中的类型参数)
public class ComparablePet implements Comparable<ComparablePet>{
@Override
public int compareTo(ComparablePet arg) {
return 0;
}
}
class Cat extends ComparablePet implements Comparable<Cat>{
//一旦基类Comparabel确定了ComparablePet,那么其他任何的实现类都不能和他定义的之外的
对象作比较,即使时它的子类也不可以
public int compareTo(Cat cat){
return 0;
}
}
class Hamster extends ComparablePet implements Comparable<ComparablePet>{
@Override
public int compareTo(ComparablePet arg) {
return super.compareTo(arg);
}
}
自限定的类型
循环泛型
不能直接继承一个泛型参数,可以继承在自己的定义中使用这个泛型参数的类
class GenericType<T>{}
public class CuriouslyRecurringGeneric extends GenericType<CuriouslyRecurringGeneric>{
}
java中的泛型关乎参数和返回类型,因此他能产生使用子类作为其参数和返回类型的基类,还能将导出类用作其域类型,甚至是那些被擦除为Object的类型
public class BasicHolder<T> {
T element;
void set(T arg){
element = arg;
}
T get(){
return element;
}
void f(){
System.out.println(element.getClass().getSimpleName());
}
}
class Subtype extends BasicHolder<Subtype>{} //
public class CRGWithBasicHolder {
public static void main(String[] args) {
final Subtype st1 = new Subtype(), st2 = new Subtype();
st1.set(st2);
//新类Subtype接受的参数和返回值具有Subtype类型不仅仅是他的基类的类型
Subtype st3 = st1.get();
st1.f();
}
}
CRG的本质:基类使用其导出类,泛型基类编程了一种所有导出类的公共功能的模板,他的参数和返回值都是导出类类型,在所产生的类中会使用确切的类型,而不是基类类型
自限定
class SelfBounded<T extends SelfBounded>{
T element;
SelfBounded <T> set(T arg){
element = arg;
return this;
}
T get(){
return element;
}
}
class A extends SelfBounded<A>{} //这种定义方式就是自限定
class B extends SelfBounded<A>{} //这样也是可以的
class C extends SelfBounded<C>{
C setAndGet(C arg){
set(arg);
return arg;
}
}
class D{}
class E extends SelfBounded<D>{}//此时这个类是不能编译的
class F extends SelfBounded{};
public class SelfBounding {
public static void main(String[] args) {
A a = new A();
a.set(new A());
a = a.set(new A()).get();
a = a.get();
C c = new C();
c = c.setAndGet(new C());
}
}
自限定参数可以保证类型参数与正在定义的类相同
如果去掉自限定限制也是可以的
class SelfBounded<T>{
T element;
SelfBounded <T> set(T arg){
element = arg;
return this;
}
T get(){
return element;
}
}
class A extends SelfBounded<A>{}
class B extends SelfBounded<A>{}
class C extends SelfBounded<C>{
C setAndGet(C arg){
set(arg);
return arg;
}
}
class D{}
class E extends SelfBounded<D>{}//这个时候这个类是可以编译的
class F extends SelfBounded{};
参数协变
自限定类型的价值是:可以产生协变参数类型(方法中的参数类型会随着子类而变化)
class Base{}
class Derived extends Base{}
interface OrdinaryGetter{
Base get();
}
interface DerivedGetter extends OrdinaryGetter{
//覆盖了从他继承过来的接口中的get方法,返回的也是从Base中导出的类型
Derived get();
}
public class CovariantReturnTypes {
void test(DerivedGetter d){
Derived d2 = d.get();
}
}
在非泛型代码中,参数类型不能随着子类型发生变化
class OrdinarySetter{
void set(Base base){
System.out.println("OrdinarySetter.set");
}
}
class DerivedSetter extends OrdinarySetter{
void set(Derived derived){
System.out.println("DerivedSetter.set");
}
}
public class OrdinaryArguments {
public static void main(String[] args) {
final Base base = new Base();
final Derived derived = new Derived();
final DerivedSetter derivedSetter = new DerivedSetter();
//方法都是子类的方法
derivedSetter.set(derived);
derivedSetter.set(base);//调用的仍然是父类的方法
}
}
混型
最基本的概念是混合多个类的能力,产生一个可以表示混型中所有类型的类
在混型中修改东西,这些东西会应用在混型中所有的类型之上
与接口混合
interface TimeStamped{
long getStamp();
}
class TimeStampedImp implements TimeStamped{
private final long timeStamp;
public TimeStampedImp(){
timeStamp = new Date().getTime();
}
@Override
public long getStamp() {
return timeStamp;
}
}
interface SerialNumbered {
long getSerialNumber();
}
class SerialNumberedImp implements SerialNumbered{
private static long counter = 1;
private final long serialNumber = counter++;
@Override
public long getSerialNumber() {
return serialNumber;
}
}
interface Basic{
public void set(String val);
public String get();
}
class BasicImp implements Basic{
private String value;
@Override
public void set(String val) {
value = val;
}
@Override
public String get() {
return value;
}
}
class Mixin extends BasicImp implements TimeStamped,SerialNumbered{
//继承了一个实现类,并且实现了两个接口,混合了多个类的能力
private TimeStamped timeStamp = new TimeStampedImp();
private SerialNumbered serialNumber = new SerialNumberedImp();
@Override
public long getStamp() {
return timeStamp.getStamp();
//调用的是TimeStampedImp中的getStamp方法
}
@Override
public long getSerialNumber() {
return serialNumber.getSerialNumber();
////调用的是SerialNumberedImp中的getSerialNumber方法
}
}
public class Mixins {
public static void main(String[] args) {
final Mixin mixin1 = new Mixin();
final Mixin mixin2 = new Mixin();
mixin1.set("test String1");
mixin2.set("test String2");
System.out.println(mixin1.get() + " " + mixin1.getStamp() + " " + mixin1.getSerialNumber());
System.out.println(mixin2.get() + " " + mixin2.getStamp() + " " + mixin2.getSerialNumber());
}
}
装饰器模式
装饰器模式使用分层对象来动态的透明的向单个对象中添加责任,装饰器是通过组合和形式化接口实现的,而混型是基于继承的
class Basic1{
private String value;
public void set(String value){
this.value = value;
}
public String get(){
return value;
}
}
class Decorator extends Basic1{
protected Basic1 basic1;
public Decorator(Basic1 basic1){
this.basic1 = basic1;
}
public void set(String val){
basic1.set(val);
}
public String get(){
return basic1.get();
}
}
class TimeStamped1 extends Decorator{
private final long timeStamp;
public TimeStamped1(Basic1 basic1){
super(basic1);
timeStamp = new Date().getTime();
}
public long getStamp(){
return timeStamp;
}
}
class SerialNumbered1 extends Decorator{
private static long counter = 1;
private final long serialNumber = counter++;
public SerialNumbered1(Basic1 basic1) {
super(basic1);
}
public long getSerialNumber(){
return serialNumber;
}
}
public class Decoration {
public static void main(String[] args) {
final TimeStamped1 t = new TimeStamped1(new Basic1());
final TimeStamped1 t2 = new TimeStamped1(new SerialNumbered1(new Basic1()));
SerialNumbered1 s = new SerialNumbered1(new Basic1());
final SerialNumbered1 s2 = new SerialNumbered1(new TimeStamped1(new Basic1()));
}
}
与动态代理混合
class MixinProxy implements InvocationHandler{
Map<String,Object> delegatesByMethod; //方法名和方法所属对象
public MixinProxy(TwoTuple<Object,Class<?>>...pairs) {
delegatesByMethod = new HashMap<String, Object>();
for (TwoTuple<Object, Class<?>> pair : pairs) { //将方法名和Object对应起来
for (Method method : pair.second.getMethods()) { //将参数循环遍历
String methodName = method.getName();
if (! delegatesByMethod.containsKey(methodName)){ //如果没有他的方法名字,就把他加进去
delegatesByMethod.put(methodName,pair.first);
}
}
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName(); //代表外部要去执行的方法的名字
Object delegate = delegatesByMethod.get(methodName); //代表目标方法的代理者或者说执行者
return method.invoke(methodName, args);//根据方法名去调用外部的方法 ,利用反射。
}
public static Object newInstance(TwoTuple... pairs){
Class[] interfaces = new Class[pairs.length]; //产生代理对象
for (int i = 0; i < pairs.length; i++) {
interfaces[i] = (Class) pairs[i].second;
}
ClassLoader cl = pairs[0].first.getClass().getClassLoader();
return Proxy.newProxyInstance(cl,interfaces,new MixinProxy(pairs));
}
}
public class DynamicProxyMixin {
}