标签:nts 核心 sse 不同 基本 super 好的 erro 原始类型
泛型程序设计:编写的代码可以被很多不同类型的对象所重用。
类型参数:使用<String>
,后者可以省略,因为可以从变量的类型推断得出。类型参数让程序更具更好的可读性和安全性。
通配符类型:很抽象,让库的构建者编写出尽可能灵活的方法。
泛型类就是具有一个或多个类型变量的类。
//引用类型变量 T ,可以有多个类型变量,public class Pair<T, U>{...}
public class Pair<T> {
//类定义的类型变量制定方法的返回类型以及域和局部变量的类型
private T first;
private T second;
public Pair(){
first = null;
second = null;
}
public Pair(T first, T second){
this.first = first;
this.second = second;
}
public T getFirst(){
return first;
}
public T getSecond(){
return second;
}
public void setFirst(T newValue){
first = newValue;
}
public void setSecond(T newValue){
second = newValue;
}
}
在实例化类时,加上具体的类型替换类型变量就可以实例化类型。
Pair<String> //用具体的类型替换类型变量就可以实例化泛型类型
//此时,构造器和方法的类型都会赋予
Pair<String>()
Pair<String>(String, String)
String getFirst()
String getSecond()
void setFirst(String)
void setSecond(String)
多个类型变量只要这样即可:
public class Pair<T, U>{...}
调用时的结构:
Pair pair = new Pair<String>();
泛型可以看作普通类的工厂。
定义带有类型参数的简单方法
class Arraylg{
public static <T> getMiddle(T... a){
return a[a.length / 2];
}
}
调用泛型方法:
String middle = Arraylg.<String>getMiddle("John","Q","Public");
有时类或方法需要对变量进行约束实现某种功能,对类型变量 T 设置限定实现:
<T extends BoundingType>
多个限定
<T extends Comparable & Serializable>
此时,就可以让类型 T 限制为实现了这些接口。
虚拟机没有泛型类型对象,所有对象都属于普通类。
泛型类型,自动提供了一个相应的原始类型:删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定名的变量用 Object)。
经过编译器之后,泛型在虚拟机不存在。
Pair<Employee> buddies = ...;
Employee buddy = buddies.getFirst();
编译器吧这个方法调用翻译为两条虚拟机指令:
public static <T extends Comparable> T min(T[] a)
public static Comparable min(Comparable[] a)
类型参数 T 擦除,留下限定类型 Compatable 。
类型擦除与多态发生冲突,要在类中生成一个桥方法:
public void setSecong(Object second) { setSecond((Date) second); }
java 泛型转换的事实:
可以用包装器类型,如果包装器类型不能接受替换时,可以使用独立的类和方法处理他们
无论何时对泛型使用 instanceof 会得到一个编译器错误;
泛型类型的强制转换表达式都会看到一个编译警告。
getClass 方法总是返回原始类型。
Pair<String> stringPair = ...;
Pair<Employee> employeePair = ...;
stringPair.getClass() == employeePair.getClass();
if (a instanceof Pair<String>) //Error
Pair<String> p = (Pair<String>) a; //Warning
结果为 true 都将返回 Pair.class
Pair<String>[] table = new Pair<String>[10];//error
可以声明通配符类型的数组,然后进行类型转换:
Pair<String>[] table = (Pair<String>[]) new Pair<?>[10];
但是结果不安全
安全方法:
ArrayList<Pair<String>>
向参数个数可变的方法传递一个泛型类型的实例:
public static <T> void addAll(Collection<T> coll, T... ts){
for (t : ts) coll.add(t);
}
此时需要 ts 数组,但是他违反了规则,会得到一个警告,可以通过注释消除警告:
@SafeVarargs
public static <T> void addAll(Collection<T> coll, T... ts)
此时可以提供泛型类型来调用这个方法了。
非法:public Pair() { first = new T(); second = new T(); } // Error
同样反射调用也非法:fisrt = T.class.newInstance(); // Error
非法:T[] mm = new T[2];
不能在静态域或方法中引用类型变量。
private static T s; // Error
public static T getS(){...}; // Error
非法:public class Problem<T> extends Exception { /*...*/ } // Error
catch 子句中不能使用类型变量。
在异常规范中使用类型变量是允许的:public static <T extends Throwable> void doWork(T t) throws T // OK
异常处理规定,必须为所有受查异常提供一个处理器。不过可以利用泛型消除这个限制。
当泛型类型被擦除时,无法创建引发冲突的条件。
要想支持擦除的转换,就需要强行限制一个类或类型变量不能同时成为两个接口类型的子类,而这两个接口是同一接口的不同参数化。
非法:
class Employee implements Comparable { ... }
class Manager extends Employee implements Comparable<Manager> { ... } //Error
Manager
会实现Comparable<Employee>
和Comparable<Manager>
,这是同一接口的不同参数化。
Pair<Manager>
不是 Pair<Employee>
的子类。可以将参数类型转换为一个原始类型,但是会产生类型错误。
无论 S 与 T 有什么关系,Pair<Manager>
和 Pair<Employee>
基本没什么关系。
通配符类型中,允许类型参数变化。
Pair<? extends Employee>
便是任意泛型 Pair 类型,它的类型参数是 Employee 子类。
Pair<Manager>
和 Pair<Employee>
是Pair<? extends Employee>
的子类型。
超类型限定:
? super Manager
这个通配符限制为 Manager 的所有超类型。
public static <T extends Comparable<T>> T min(T[] a)
public static <T extends Comparable<? super T>> T min(T[] a) //用于处理需要泛型类型超类型的情况
无限定通配符:Pair<?>
这个类有如下方法:
? getFirst()
void setFirst(?)
getFirst 能赋予一个 Object;
setFirst 方法不能被调用,也不能用 Object 调用。但是可以调用setFirst(null)
。
通配符不是类型变量,不能在编写代码中使用?
作为一种类型。
解决方案:
public static <T> void swapHelper(Pair<T> p){
T t = p.getFirst();
p.setFirst(p.getSecond();
p.setSecond(t);
}
public static void swap(Pair<?> p){
swapHelper(p);
}
swapHelper 方法的参数 T 捕获通配符。他不知道是哪种类型的通配符,但是这是一个明确的类型。
Class 类是泛型的,String.class
是一个Class<String>
类的对象(唯一的对象)。
如果给定的类型确实是 T 的一个子类型,cast 方法就会返回一个现在声明为类型 T 的对象,否则,抛出一个 BadCastException 异常。
如果这个类不是 enum 类或类型 T 的枚举值的数组,getEnumConstants
方法将返回 null。
getConstructor
与 getdeclaredConstructor
方法返回一个 Constructor<T>
对象。Constructor
类也已经变成泛型,以便newInstance
方法有一个正确的返回类型。
API:
T newInstance()
T cast(Object obj)
T[] getEnumConstants()
Class<? super T> getSuperclass()
Constructor<T> getConstructor<Class... parameterTypes)
Constructor<T> getDeclaredConstructor<Class... parameterTypes)
//java.lang.reflect.Constructor<T>
T newInstance(Object... parameters)
Class<T>
参数进行类型匹配public static <T> Pair<T> makePair(class<T> c) throws InstantiationException, IllegalAccessException {
return new Pair<>(c.newInstance(), c.newInstance());
}
调用
makePair(Employee.class);
类型参数 T 同 Employee 匹配。
可以使用反射 API 确定:
标签:nts 核心 sse 不同 基本 super 好的 erro 原始类型
原文地址:https://www.cnblogs.com/lovezyu/p/9127467.html