private static int add(int a, int b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}
private static float add(float a, float b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}
private static double add(double a, double b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}
List list = new ArrayList();
// list中只能放String, 不能放其它类型的元素
泛型的基本使用
泛型类
从一个简单的泛型类看起:
class Point{ // 此处可以随便写标识符号,T是type的简称
private T var ; // var的类型由T指定,即:由外部指定
public T getVar(){ // 返回值的类型由外部决定
return var ;
}
public void setVar(T var){ // 设置的类型也由外部决定
this.var = var ;
}
}
public class GenericsDemo06{
public static void main(String args[]){
Point p = new Point() ; // 里面的var类型为String类型
p.setVar("it") ; // 设置字符串
System.out.println(p.getVar().length()) ; // 取得字符串的长度
}
}
多元泛型
class Notepad{ // 此处指定了两个泛型类型
private K key ; // 此变量的类型由外部决定
private V value ; // 此变量的类型由外部决定
public K getKey(){
return this.key ;
}
public V getValue(){
return this.value ;
}
public void setKey(K key){
this.key = key ;
}
public void setValue(V value){
this.value = value ;
}
}
public class GenericsDemo09{
public static void main(String args[]){
Notepad t = null ; // 定义两个泛型类型的对象
t = new Notepad() ; // 里面的key为String,value为Integer
t.setKey("汤姆") ; // 设置第一个内容
t.setValue(20) ; // 设置第二个内容
System.out.print("姓名;" + t.getKey()) ; // 取得信息
System.out.print(",年龄;" + t.getValue()) ; // 取得信息
}
}
泛型接口
简单的泛型接口
interface Info{ // 在接口上定义泛型
public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型
}
class InfoImpl implements Info{ // 定义泛型接口的子类
private T var ; // 定义属性
public InfoImpl(T var){ // 通过构造方法设置属性内容
this.setVar(var) ;
}
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
}
public class GenericsDemo24{
public static void main(String arsg[]){
Info i = null; // 声明接口对象
i = new InfoImpl("汤姆") ; // 通过子类实例化对象
System.out.println("内容:" + i.getVar()) ;
}
}
class Info{ // 此处泛型只能是数字类型
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
}
public class demo1{
public static void main(String args[]){
Info i1 = new Info() ; // 声明Integer的泛型对象
}
}
下限
class Info{
private T var ; // 定义泛型变量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){ // 直接打印
return this.var.toString() ;
}
}
public class GenericsDemo21{
public static void main(String args[]){
Info i1 = new Info() ; // 声明String的泛型对象
Info
小结
> 无限制通配符
extends E> extends 关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类
super E> super 关键字声明了类型的下界,表示参数化的类型可能是指定的类型,或者是此类型的父类
// 使用原则《Effictive Java》
// 为了获得最大限度的灵活性,要在表示 生产者或者消费者 的输入参数上使用通配符,使用的规则就是:生产者有上限、消费者有下限
1. 如果参数化类型表示一个 T 的生产者,使用 < ? extends T>;
2. 如果它表示一个 T 的消费者,就使用 < ? super T>;
3. 如果既是生产又是消费,那使用通配符就没什么意义了,因为你需要的是精确的参数类型。
再看一个实际例子,加深印象
private > E max(List extends E> e1) {
if (e1 == null){
return null;
}
//迭代器返回的元素属于 E 的某个子类型
Iterator extends E> iterator = e1.iterator();
E result = iterator.next();
while (iterator.hasNext()){
E next = iterator.next();
if (next.compareTo(result) > 0){
result = next;
}
}
return result;
}
上述代码中的类型参数 E 的范围是>,我们可以分步查看:
要进行比较,所以 E 需要是可比较的类,因此需要 extends Comparable<…>(注意这里不要和继承的 extends 搞混了,不一样)
Comparable< ? super E> 要对 E 进行比较,即 E 的消费者,所以需要用 super
而参数 List< ? extends E> 表示要操作的数据是 E 的子类的列表,指定上限,这样容器才够大
多个限制
使用&符号
public class Client {
//工资低于2500元的上斑族并且站立的乘客车票打8折
public static void discount(T t){
if(t.getSalary()<2500 && t.isStanding()){
System.out.println("恭喜你!您的车票打八折!");
}
}
public static void main(String[] args) {
discount(new Me());
}
}
泛型数组
具体可以参考下文中关于泛型数组的理解。
首先,我们泛型数组相关的申明:
List[] list11 = new ArrayList[10]; //编译错误,非法创建
List[] list12 = new ArrayList>[10]; //编译错误,需要强转类型
List[] list13 = (List[]) new ArrayList>[10]; //OK,但是会有警告
List>[] list14 = new ArrayList[10]; //编译错误,非法创建
List>[] list15 = new ArrayList>[10]; //OK
List[] list6 = new ArrayList[10]; //OK,但是会有警告
那么通常我们如何用呢?
讨巧的使用场景
public class GenericsDemo30{
public static void main(String args[]){
Integer i[] = fun1(1,2,3,4,5,6) ; // 返回泛型数组
fun2(i) ;
}
public static T[] fun1(T...arg){ // 接收可变参数
return arg ; // 返回泛型数组
}
public static void fun2(T param[]){ // 输出
System.out.print("接收泛型数组:") ;
for(T t:param){
System.out.print(t + "、") ;
}
}
}
合理使用
public ArrayWithTypeToken(Class type, int size) {
array = (T[]) Array.newInstance(type, size);
}
public class Test {
public static void main(String[] args) {
ArrayList list1 = new ArrayList();
list1.add("abc");
ArrayList list2 = new ArrayList();
list2.add(123);
System.out.println(list1.getClass() == list2.getClass()); // true
}
}
public class Test {
public static void main(String[] args) throws Exception {
ArrayList list = new ArrayList();
list.add(1); //这样调用 add 方法只能存储整形,因为泛型类型的实例为 Integer
list.getClass().getMethod("add", Object.class).invoke(list, "asd");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
public class Test {
public static void main(String[] args) {
/**不指定泛型的时候*/
int i = Test.add(1, 2); //这两个参数都是Integer,所以T为Integer类型
Number f = Test.add(1, 1.2); //这两个参数一个是Integer,一个是Float,所以取同一父类的最小级,为Number
Object o = Test.add(1, "asd"); //这两个参数一个是Integer,一个是String,所以取同一父类的最小级,为Object
/**指定泛型的时候*/
int a = Test.add(1, 2); //指定了Integer,所以只能为Integer类型或者其子类
int b = Test.add(1, 2.2); //编译错误,指定了Integer,不能为Float
Number c = Test.add(1, 2.2); //指定为Number,所以可以为Integer和Float
}
//这是一个简单的泛型方法
public static T add(T x,T y){
return y;
}
}
因为在 Java 编译期没法确定泛型参数化类型,也就找不到对应的类字节码文件,所以自然就不行了,此外由于T 被擦除为 Object,如果可以 new T() 则就变成了 new Object(),失去了本意。 如果我们确实需要实例化一个泛型,应该如何做呢?可以通过反射实现:
static T newTclass (Class < T > clazz) throws InstantiationException, IllegalAccessException {
T obj = clazz.newInstance();
return obj;
}
泛型数组:能不能采用具体的泛型类型进行初始化?
我们先来看下Oracle官网提供的一个例子:
List[] lsa = new List[10]; // Not really allowed.
Object o = lsa;
Object[] oa = (Object[]) o;
List li = new ArrayList();
li.add(new Integer(3));
oa[1] = li; // Unsound, but passes run time store check
String s = lsa[1].get(0); // Run-time error ClassCastException.
List>[] lsa = new List>[10]; // OK, array of unbounded wildcard type.
Object o = lsa;
Object[] oa = (Object[]) o;
List li = new ArrayList();
li.add(new Integer(3));
oa[1] = li; // Correct.
Integer i = (Integer) lsa[1].get(0); // OK
public class GenericType {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static void main(String[] args) {
GenericType genericType = new GenericType() {};
Type superclass = genericType.getClass().getGenericSuperclass();
//getActualTypeArguments 返回确切的泛型参数, 如Map返回[String, Integer]
Type type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
System.out.println(type);//class java.lang.String
}
}
其中 ParameterizedType:
public interface ParameterizedType extends Type {
// 返回确切的泛型参数, 如Map返回[String, Integer]
Type[] getActualTypeArguments();
//返回当前class或interface声明的类型, 如List>返回List
Type getRawType();
//返回所属类型. 如,当前类型为O.I, 则返回O. 顶级类型将返回null
Type getOwnerType();
}
Create the Google Play Account
Having a Google account, pay 25$, then you get your google developer account.
References:
http://developer.android.com/distribute/googleplay/start.html
https://p