java 泛型,
java 泛型,
1.什么是泛型
泛型就是参数化类型,使用该特性创建的接口、类、方法。可以作为参数指定操作的数据类型
泛型解决了以前的类型安全及显示的在Object及实际类型之间的转换。
public class Gen <T> {
private T ob;
public Gen (T go) {
this.ob = go;
}
}
其中:T是类型参数的名称。因此,Gen是泛型类,也称为参数化类型。
1.2带两个类型参数的泛型类
public class Gen <T,V> {
private T ob;
public Gen (T go) {
this.ob = go;
}
}
1.3 泛型有界类型
假设希望创建一个泛型类,类中包含一个求数组中平均值的方法。包括整数、浮点数以及双精度浮点数。
public class Stats<T extends Number> {
T[] nums;
public Stats(T[] nums) {
this.nums = nums;
}
public double average() {
double sum = 0.0;
for (T t:nums) {
sum = t.doubleValue() + sum;
}
return sum / nums.length;
}
}
public class StatsDemo {
public static void main(String[] args) {
Integer[] nums = {1,2,3,4,5};
Stats<Integer> stats = new Stats<>(nums);
System.out.println(stats.average());
Double[] dnums = {1.0,1.2,1.3,1.4};
Stats<Double> doubleStats = new Stats<>(dnums);
System.out.println(doubleStats.average());
//编译错误
// String[] strStats = {"1","2"};
// Stats<String> stringStatus = new Stats<String>(strStats);
}
}
可以指定多个接口作为边界
指定多个接口作为边界时使用&链接。一个类可以实现多个接口,但是只能继承一个类
public class Stats<T extends Number & Comparable> {
}
1.4泛型通配符参数
假如对于上面的Stats类要添加一个判断两个对象平均值相同的方法。而不考虑每个对象的具体的数据类型。
实现sameAge方法的一种方式是传递Stats参数。然后根据调用对象比较参数的平均值。
错误的实现方式
public class Stats<T extends Number & Comparable> {
public boolean sameAve(Stats<T> stats){
if (average() == stats.average()) {
return true;
}
return false;
}
}
public class StatsDemo {
public static void main(String[] args) {
Integer[] nums = {1,2,3,4,5};
Stats<Integer> stats = new Stats<>(nums);
Double[] dnums = {1.0,1.2,1.3,1.4};
Stats<Double> doubleStats = new Stats<>(dnums);
//编译错误。因为数据类型不相同
System.out.println(stats.sameAve(doubleStats));
}
}
这种尝试存在的问题是 只有当Stats的类型和调用对象的类型相同时才能工作。
正确的做法:
使用通配符参数,由”?”指定,表示未知的类型。
public class Stats<T extends Number & Comparable> {
public boolean sameAve(Stats<?> stats){
if (average() == stats.average()) {
return true;
}
return false;
}
}
1.5 有界通配符
为了理解为什么需要有界通配符,从以下例子开始:
//两维数组类
public class TwoD {
int x;
int y;
TwoD(int x,int y) {
this.x = x;
this.y = y;
}
}
//三维数组类
public class ThreeD extends TwoD {
int z;
ThreeD(int x, int y,int z) {
super(x, y);
this.z = z;
}
}
//四维数组类
public class FourD extends ThreeD {
int t;
FourD(int x, int y, int z,int t) {
super(x, y, z);
this.t = t;
}
}
上面几个类的顶部类都是TwoD,因此可以搞一个泛型类:
public class Coords<T extends TwoD> {
T[] coords;
public Coords(T[] coords) {
this.coords = coords;
}
}
//Coords制定了一个由TwoD界定的类型参数。这意味着在Coords对象中存储的所有数组将包含TwoD类或其子类的对象。
假设我们现在要编写一个方法,要显示数组中每个元素的X,Y的坐标。
public void showXY(Coords<?> c) {
for (int i = 0;i < c.coords.length) {
System.out.println(c.coords[i].x + c.coords[i].y);
}
}
假设我们现在要编写一个方法,要显示数组中每个元素的X,Y,Z的坐标。
这时不能直接使用通配符,因为TwoD没有Z
此时需要使用有界通配符。对传入的参数类型做限制。
public void showXYZ(Coords<? extends ThreeD> c) {
for (int i = 0;i < c.coords.length;i++) {
System.out.println(c.coords[i].x + c.coords[i].y + c.coords[i].z);
}
}
// ?表示任意类型,只要这些类型为ThreeD或者ThreeD的派生类。
有界通配符为类型参数可以指定上界或下界,从而限制方法可以操作的对象类型。最常用的有界统配符是上界,使用extends子句创建。
上界语法:
public void showXYZ(Coords<? super FourD> c) {
for (int i = 0;i < c.coords.length;i++) {
System.out.println(c.coords[i].x + c.coords[i].y );
}
}
//注意 此时的方法类型参数是FourD的超类,如果FourD本身的超类是Object,那么参数类型就是他本身。
2.泛型方法
语法:
ret-type meth-name(param-list) {…}
举例:
public class GenMathDemo {
//静态方法
static <T extends Comparable<T>,V extends T> boolean isIn(T[] ts,V v) {
for (T t:ts) {
if (v.equals(t)) {
return true;
}
}
return false;
}
//实例方法
<T extends Comparable<T>,V extends T> boolean isInTest(T[] ts,V v) {
for (T t:ts) {
if (v.equals(t)) {
return true;
}
}
return false;
}
}
static
3.泛型构造参数
可以将构造参数泛型化,即使他们的类不是泛型类。
public class GenCons {
private double val;
public <T extends Number> GenCons(T args) {
val = args.doubleValue();
}
public void showVal() {
System.out.println("arg val:" + val);
}
public static void main(String[] args) {
GenCons genCons = new GenCons(123);
GenCons test2 = new GenCons(125.4F);
genCons.showVal();
test2.showVal();
}
}
4.泛型接口
除了可以定义泛型类和泛型方法外,还可以定义泛型接口。泛型接口的定义和泛型类相似。
泛型接口的通用语法:
interface interface-name {..//}
泛型接口的实现:
class class-name implements interface-name
泛型接口定义:
public interface MinMax<T extends Comparable<T>> {
T min();
T max();
}
泛型接口实现:
public class MyClass<T extends Comparable<T>> implements MinMax<T> {
@Override
public T min() {
return null;
}
@Override
public T max() {
return null;
}
}
public class MyClass
1、java反射中的泛型API
Type是所有泛型的接口
1.1 参数化类型接口
public interface ParameterizedType extends Type {
}
如泛型:List 代表参数化类型
java中目前并没有提供直接获取一个类的参数化类型。但是提供了获取父类的泛型化参数:
**
* Represents a generic type {@code T}. Java doesn't yet provide a way to
* represent generic types, so this class does. Forces clients to create a
* subclass of this class which enables retrieval the type information even at
* runtime.
*
* <pre>
* TypeReference<List<String>>; list = new TypeReference<List<String>>() {};
* </pre>
*/
public class TypeReference<T> {
/**
* Constructs a new type literal. Derives represented class from type
* parameter.
*
* <p>Clients create an empty anonymous subclass. Doing so embeds the type
* parameter in the anonymous class's type hierarchy so we can reconstitute it
* at runtime despite erasure.
*/
protected TypeReference(){
/*获取泛型化父类*/
Type superClass = getClass().getGenericSuperclass();
/*获取泛型化参数的实际类型*/
Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
Type cachedType = classTypeCache.get(type);
if (cachedType == null) {
classTypeCache.putIfAbsent(type, type);
cachedType = classTypeCache.get(type);
}
this.type = cachedType;
}
1.2 通配符类型
public class GenDemo {
public static void main(String[] args) throws NoSuchMethodException {
ThreeD[] threeDS = {new ThreeD(1,2,3)};
Coords coords = new Coords<ThreeD>(threeDS);
Method method = coords.getClass().getMethod("showXY",Coords.class);
ParameterizedType type1 = (ParameterizedType) method.getGenericParameterTypes()[0];
Type type = type1.getActualTypeArguments()[0];
if (type instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) type;
System.out.println(wildcardType.getTypeName());
}
}
}
相关文章
- 暂无相关文章
用户点评