zoukankan      html  css  js  c++  java
  • 【Java基础】泛型

    Num1:请不要在新代码中使用原生类型

    泛型类和接口统称为泛型。每种泛型定义一组参数化的类型,构成格式是:类或接口名称,接着用<>把对应于泛型形式类型的参数的实际参数列表括起来。比如:List是一个参数化的类型,表示元素类型为String的列表。最后一点,每个泛型都定义一个原生类型,raw type,即不带任何实际类型参数的泛型名称。

    示例代码:

    public class Raw {
    	// Uses raw type (List) - fails at runtime! - Page 112
    	public static void main(String[] args) {
    		List<String> strings = new ArrayList<String>();
    		unsafeAdd(strings, new Integer(42));
    		String s = strings.get(0); // Compiler-generated cast
    	}
    
    	private static void unsafeAdd(List list, Object o) {
    		list.add(o);
    	}
    
    	// Use of raw type for unknown element type - don't do this! - Page 113
    	static int rawNumElementsInCommon(Set s1, Set s2) {
    		int result = 0;
    		for (Object o1 : s1)
    			if (s2.contains(o1))
    				result++;
    		return result;
    	}
    
    	// Unbounded wildcard type - typesafe and flexible - Page 113
    	static int numElementsInCommon(Set<?> s1, Set<?> s2) {
    		int result = 0;
    		for (Object o1 : s1)
    			if (s2.contains(o1))
    				result++;
    		return result;
    	}
    }
    

    从Java1.5发行版本开始,Java就提供了一种安全的替代方法,称作无限制的通配符类型,如果使用泛型,但不确定或者不关心实际的类型参数,就可以使用一个问号代替。

    那么无限制通配类型Set<?>和原生类型Set之间有什么区别呢?通配符类型是安全的,原生类型则不安全。

    Num2:消除非受检警告

    当使用泛型编程时,会遇到许多编译器警告,那么该如何消除?

    可以用@SuppressWarnings("unchecked")这个注解来禁止警告。需要注意的是,每当使用@SuppressWarnings("unchecked")注解时,都要添加一条注释,说明为什么这么做是安全的,这样可以帮助其他人理解代码,更重要的是,可以尽量减少其他人修改代码后导致计算不安全的概率。

    Num3:列表优先于数组

    数组与泛型相比,有两个重要的不同点。

    首先,数组是协变的,泛型则是不可变的。

    第二大区别:数组是具体化的,因此数组会在运行时才知道并检查它们的元素类型约束。相比之下,泛型则是通过擦除来实现的,因此泛型只在编译时强化它们的类型信息,并在运行时丢弃它们的元素类型信息。

    示例代码:

    public class Reduction {
    	static <E> E reduce(List<E> list, Function<E> f, E initVal) {
    		List<E> snapshot;
    		synchronized (list) {
    			snapshot = new ArrayList<E>(list);
    		}
    		E result = initVal;
    		for (E e : snapshot)
    			result = f.apply(result, e);
    		return result;
    	}
    
    	// A few sample functions
    	private static final Function<Integer> SUM = new Function<Integer>() {
    		public Integer apply(Integer i1, Integer i2) {
    			return i1 + i2;
    		}
    	};
    
    	private static final Function<Integer> PRODUCT = new Function<Integer>() {
    		public Integer apply(Integer i1, Integer i2) {
    			return i1 * i2;
    		}
    	};
    
    	private static final Function<Integer> MAX = new Function<Integer>() {
    		public Integer apply(Integer i1, Integer i2) {
    			return Math.max(i1, i2);
    		}
    	};
    
    	private static final Function<Integer> MIN = new Function<Integer>() {
    		public Integer apply(Integer i1, Integer i2) {
    			return Math.min(i1, i2);
    		}
    	};
    
    	public static void main(String[] args) {
    		List<Integer> intList = Arrays.asList(2, 7, 1, 8, 2, 8, 1, 8, 2, 8);
    
    		// Reduce intList using each of the above reducers
    		System.out.println(reduce(intList, SUM, 0));
    		System.out.println(reduce(intList, PRODUCT, 1));
    		System.out.println(reduce(intList, MAX, Integer.MIN_VALUE));
    		System.out.println(reduce(intList, MIN, Integer.MAX_VALUE));
    	}
    }
    

    Num4:优先考虑泛型类和方法

    示例类代码:

    public class Stack<E> {
    	private E[] elements;
    	private int size = 0;
    	private static final int DEFAULT_INITIAL_CAPACITY = 16;
    
    	// The elements array will contain only E instances from push(E).
    	// This is sufficient to ensure type safety, but the runtime
    	// type of the array won't be E[]; it will always be Object[]!
    	@SuppressWarnings("unchecked")
    	public Stack() {
    		elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
    	}
    
    	public void push(E e) {
    		ensureCapacity();
    		elements[size++] = e;
    	}
    
    	public E pop() {
    		if (size == 0)
    			throw new EmptyStackException();
    		E result = elements[--size];
    		elements[size] = null; // Eliminate obsolete reference
    		return result;
    	}
    
    	public boolean isEmpty() {
    		return size == 0;
    	}
    
    	private void ensureCapacity() {
    		if (elements.length == size)
    			elements = Arrays.copyOf(elements, 2 * size + 1);
    	}
    
    	// Little program to exercise our generic Stack
    	public static void main(String[] args) {
    		Stack<String> stack = new Stack<String>();
    		for (String arg : args)
    			stack.push(arg);
    		while (!stack.isEmpty())
    			System.out.println(stack.pop().toUpperCase());
    	}
    }
    

    如果类可以从泛型中收益一般,方法也一样,静态工具方法尤其适合于泛型化。

    示例方法代码:单例工厂模式

    public interface UnaryFunction<T> {
    	T apply(T arg);
    }
    
    public class GenericSingletonFactory {
    	// Generic singleton factory pattern
    	private static UnaryFunction<Object> IDENTITY_FUNCTION = new UnaryFunction<Object>() {
    		public Object apply(Object arg) {
    			return arg;
    		}
    	};
    
    	// IDENTITY_FUNCTION is stateless and its type parameter is
    	// unbounded so it's safe to share one instance across all types.
    	@SuppressWarnings("unchecked")
    	public static <T> UnaryFunction<T> identityFunction() {
    		return (UnaryFunction<T>) IDENTITY_FUNCTION;
    	}
    
    	// Sample program to exercise generic singleton
    	public static void main(String[] args) {
    		String[] strings = { "jute", "hemp", "nylon" };
    		UnaryFunction<String> sameString = identityFunction();
    		for (String s : strings)
    			System.out.println(sameString.apply(s));
    
    		Number[] numbers = { 1, 2.0, 3L };
    		UnaryFunction<Number> sameNumber = identityFunction();
    		for (Number n : numbers)
    			System.out.println(sameNumber.apply(n));
    	}
    }
    

    示例方法代码:静态方法模式

    public class GenericStaticFactory {
    	// Generic static factory method
    	public static <K, V> HashMap<K, V> newHashMap() {
    		return new HashMap<K, V>();
    	}
    
    	public static void main(String[] args) {
    		// Parameterized type instance creation with static factory
    		Map<String, List<String>> anagrams = newHashMap();
    	}
    }
    

    泛型方法一个显著特征:无需明确指定类型参数的值,不像调用泛型构造器的时候必须指定一个类型。

    简而言之,使用泛型比使用需要在客户端代码中进行转换的类型来的更加安全,也更加容易。

  • 相关阅读:
    List注意点【修改】
    最近遇到的笔试面试题(3)
    关于阅读
    各种语言
    最近遇到的笔试面试题(2)
    最近遇到的笔试面试题(1)
    5自由落体运动
    4 1000以内完数
    3水仙花数
    判断101-200之间的素数
  • 原文地址:https://www.cnblogs.com/cr330326/p/5620368.html
Copyright © 2011-2022 走看看