泛型

1、

/*
 * 在JDK1.5之前(泛型之前之前),我们通过集合存取元素会具有
 * 两个缺陷:
 * 1 繁琐性
 * 2 不安全性
 */
package day13;

import java.util.ArrayList;
import java.util.List;

/*
 * 非泛型的繁琐性
 */
public class NoGeneric {

	public static void main(String[] args) {
		List list = new ArrayList();
		// 通过调用add方法向集合类中加入元素。
		list.add("aaa");
		list.add("bbb");
		list.add("ccc");
		// 通过get方法获取元素,参数指定索引值。(从0开始)
		// 我们往往只操作同一类型的元素,虽然我们明知道加入
		// 的就是String类型,但是,获取元素时,也只能获取
		// Object类型,我们还需要显示的执行类型转换。(非
		// 泛型的繁琐性。)
		String s = (String) list.get(1);
	}

}

 

package day13;

import java.util.ArrayList;
import java.util.List;

public class NoGeneric2 {
	/*
	 * 非泛型的不安全性
	 */
	public static void main(String[] args) {
		List list = new ArrayList();
		list.add("one");
		list.add("two");
		list.add("three");
		// 我们原意只是用集合来存储String类型的元素,
		// 但是由于程序员的疏忽,我们加入了一个非String
		// 类型的元素,编译器也不会产生编译错误。
		list.add(new Integer(1));
		// 我们获取元素时,还以为元素都是String类型。
		// 编译时没有错误,但在运行时会产生
		// ClassCastException异常。(非泛型的不安全性)
		String s = (String) list.get(3);
	}

}

  2、泛型设计

/*
 * 泛型设计
 * 泛型就是在类型(类,接口)或方法(构造器)后加上一个<类型参数>。
 * 一个类型加上具体的类型参数,我们称之为参数化类型。
 * 泛型就是含有一个类型参数(泛型声明时,指定的类型参数
 * 称为形式类型参数),在使用类型时,传递一个具体的类型
 * (使用泛型时,传递的参数称为实际类型参数)。这类似于方法
 * 调用过程中的参数传递,只是方法参数传递,传递的是一个具体
 * 的值,而泛型中参数传递,传递的是一个具体的类型。
 * 
 * 按照惯例,泛型声明处的类型参数使用一个大写字母表示。
 * E	元素element
 * T	类型Type
 * K	键key
 * V	值value
 * 
 * 泛型的类型参数可以是任意的引用类型。(不能是基本数据类型。)
 */
package day13;

import java.util.ArrayList;
import java.util.List;

public class Generic {

	public static void main(String[] args) {
		// 使用泛型,表示当前集合仅能存储实际类型参数指定的类型。
		List<String> list = new ArrayList<String>();
		list.add("aaa");
		list.add("bbb");
		// 无需再进行类型转换,消除了繁琐性。
		String s = list.get(0);
		// 错误,编译器会进行严格的类型检查,消除了不安全性。
		// list.add(new Integer(5));
		List<Integer> list2 = new ArrayList<Integer>();
		list2.add(new Integer(5));
		list2.add(5); // list2.add(Integer.valueOf(5));
		int x = list2.get(0).intValue();
		x = list2.get(0);
		// 错误的。
		// List<int> list3;
		// 可以是数组类型,因为数组类型也是引用类型。
		List<int[]> list3;
	}
}

  3、原生类型

/*
 * 在使用泛型类时,没有给出具体的实际类型参数,这种类型
 * 称为原生类型。例如:
 * List list = new ArrayList();
 * List与ArrayList就是原生类型。
 * 原生类型仅仅作为历史遗留的产物,之所以还能使用,那是因为
 * 是对以前程序的兼容与让步。我们在以后使用泛型类时,不要在
 * 使用原生类型,应该总是使用参数化类型来代替原生类型。
 */
package day13;

public class RawType {

	public static void main(String[] args) {

	}

}

  4、类型推断

/*
 * 类型推断
 */
package day13;

import java.util.ArrayList;
import java.util.List;

public class Inference {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		// 从JDK1.7起,编译器可以自动进行类型推断
		// 从不规范的角度说,把这种类型称为"菱形语法"。
		List<String> list2 = new ArrayList<>();
		List<List<String>> list3;
	}
}

  5、参数化类型的继承

/*
 * 参数化类型的“继承”
 * 存在一种类型,就会存在对应的数组类型。
 * 如果A是B的子类型,则A[]也是B[]子类型。
 * 
 * 参数化类型不具有可继承性。
 * 如果A是B的子类型,则T<A>不是T<B>的子类型。
 * T是某泛型类型。
 */
package day13;

import java.util.ArrayList;
import java.util.List;

public class GenericInherit {
	public static void main(String[] args) {
		// String是Object的子类型,因此,String[]
		// 也是Object[]的子类型。
		String[] s = new String[5];
		Object[] o = s;
		// o[0] = new Integer(5);
		// 错误,在编译时没有问题,但是,在运行时会产生
		// ArrayStoreException异常。
		o[0] = 5;

		List<String> list = new ArrayList<>();
		List<Object> list2 = new ArrayList<>();
		// 错误,参数化类型不具有可继承性
		// list2 = list;
		// list2.add(new Object());
		// list2.add(new Integer(5));

		print(list2);
		// print(list);

	}

	public static void print(List<Object> list) {
		// 对任意的List进行操作
	}
}

  6、类型通配符?

/*
 * 类型通配符?
 * ?表示某种类型,是一种不确定的类型。
 * 含有通配符的参数化类型就是含有具体类型参数的参数化
 * 类型的父类型。
 * 
 * 类型通配符有三种:(X表示某种类型,也可以是接口类型)
 * ?  无界通配符。可以是任意的引用类型。
 * ? extends X 含有上界的通配符,可以是X类型或X类型的子类型。
 * ? super X 含有下界的通配符,可以是X类型或X类型的父类型。
 * 
 */
package day13;

import java.util.ArrayList;
import java.util.List;

public class Wildcard {

	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		List<Integer> list2 = new ArrayList<>();
		List<Object> list3 = new ArrayList<>();
		print(list);
		print(list2);
		print(list3);

	}

	// 通过类型通配符,就可以接收类型参数是任意类型的参数化类型。
	public static void print(List<?> list) {
		// 当使用类型通配符时,向集合中加入元素会受到一定的限制。
		// 但是可以加入null值,因为null可以赋值给任意的引用
		// 类型。
		// list.add("");
		// list.add(5);
		// list.add(new Object());
		// 可以加入null。
		list.add(null);
	}
}

  

package day13;

import java.util.ArrayList;
import java.util.List;

public class Wildcard2 {

	public static void main(String[] args) {
		List<Rectangle> list = new ArrayList<>();
		List<Shape> list2 = new ArrayList<>();
		eva(list);
		eva(list2);
	}

	public static void eva(List<? extends Shape> list) {
		// 循环取出每一个图形,然后计算周长与面积
		Shape s = list.get(0);
		System.out.println(s.per());
		System.out.println(s.area());
		// list.add(new Rectangle());
	}
}

abstract class Shape {
	public abstract double per();

	public abstract double area();
}

class Rectangle extends Shape {
	@Override
	public double per() {
		return 1;
	}

	@Override
	public double area() {
		return 1;
	}
}

 

package day13;

import java.util.ArrayList;
import java.util.List;

public class Wildcard3 {

	public static void main(String[] args) {
		List<Rectangle> list = new ArrayList<>();
		List<Shape> list2 = new ArrayList<>();
		List<Object> list3 = new ArrayList<>();
		Rectangle r = new Rectangle();
		add(list, r);
		add(list2, r);
		add(list3, r);
	}

	public static void add(List<? super Rectangle> list, Rectangle s) {
		// 加入的操作
		list.add(null);
		list.add(s);
	}
}

  7、自定义泛型类

/*
 * 自定义泛型类
 * 
 * 在声明类后,再声明一个(或多个)形式类型参数,
 * 这样的类就是泛型类。多个形式类型参数使用","进行分隔。
 * 按照惯例,形式类型参数使用一个大写字母表示。
 * 
 * 在使用泛型类(参数化类型)时,泛型类的类体可以看成是
 * 实际类型参数替换掉形式类型参数后的结果。(但实际上,
 * 泛型类只有一个,不会因为实际类型参数的不同而不同。)
 */
package day13;

public class GenericClass {
	public static void main(String[] args) {
		Box<String> box = new Box<>();
		Box<Integer> box2 = new Box<>();
		box.setT("abc");
		// box.setT(5);
		String s = box.getT();
		box2.setT(10);
		//box2.setT("23");
		int x = box2.getT();
	}
}

class Box<T> {
	private T t;

	public void setT(T t) {
		this.t = t;
	}

	public T getT() {
		return t;
	}
}

/*
	class Box<String> {
		private String t;
		
		public void setT(String t) {
			this.t = t;
		}
	
		public String getT() {
			return t;
		}
	}
	
	class Box<Integer> {
		private Integer t;
		
		public void setT(Integer t) {
			this.t = t;
		}
	
		public Integer getT() {
			return t;
		}
	}
*/

  8、

/*
 * 泛型类的类型参数(形式类型参数)也可以指定界限。
 * 
 * 类型参数与通配符:
 * 1 类型参数只能用extends指定上界,不能使用super指定下界。
 * (通配符既可以指定上界,也可以指定下界)
 * 2 类型参数可以作为一种类型而存在,但是通配符不能。
 * 3 类型参数可以指定一个以上(多个)上界,但是通配符不行。
 * 
 * 多个上界:
 * 1 多个上界既可以是类类型,也可以是接口类型。
 * 2 如果两个(多个)上界同时是接口类型,顺序没有要求。
 * 3 如果两个(多个)上界有一个是类类型,则类必须放在前面。
 */
package day13;

public class GenericClass2 {
	public static void main(String[] args) {
		Box2<Shape> box;
		Box2<Rectangle> box2;
		// Box2<String> box3;
		// Box3<Shape> box4;
		// Box3<Rectangle> box3;
		Box3<Circle> box4;
	}
}

class Box2<T extends Shape> {
	// 在类中使用类型参数所代表的类型。
	T t;
	// 通配符不能作为一种类型。
	// ? t;
	//List<?>与List<? extends Object> 等价
}

interface Inter {

}

// 类型参数指定多个上界
class Box3<T extends Shape & Inter> {

}
//错误,对于多个上界,类必须声明在接口前。
//class Box3<T extends Inter & Shape> { }

class Circle extends Shape implements Inter {
	@Override
	public double per() {
		return 0;
	}

	@Override
	public double area() {
		return 0;
	}
}

  9、泛型方法

/*
 * 泛型方法。
 * 方法也可以声明为泛型方法。就是在方法的返回类型前
 * 声明一个或多个类型参数。泛型方法声明的类型参数在
 * 方法中是有效的。
 * 
 * 对泛型方法调用时,可以在.后面显示指定实际类型参数。
 * gm.<String>g("abc");
 * 但是,通常情况下,我们不需要这样做,编译器可以自动
 * 推断泛型方法的类型参数。
 * gm.g("abc");
 * 如果需要显示指定类型参数,则引用不能丢失。
 */
package day13;

import java.util.List;

public class GenericMethod {
	public static void main(String[] args) {
		GenericMethod gm = new GenericMethod();
		// 泛型方法的调用
		// gm.<String>g("abc");
		// List<Integer> list = null;
		// gm.g("abc", list);
		gm.g("a", 10);
	}

	public <T> void g(T t, T t2) {
		// 方法体
		//如果需要显示指定类型参数,则引用不能丢失。
		//<Integer>k(20);  错误
		this.<Integer>k(20);
	}

	public <E> void k(E t) {

	}
}

/*
 * public class GenericMethod<T> { public static void main(String[] args) {
 * 
 * }
 * 
 * public void g(T t) { List<T> list; }
 * 
 * public void k(T t) {
 * 
 * } }
 */

  10、泛型构造器

/*
 * 泛型构造器
 * 可以声明泛型构造器,就是在声明构造器名的前面
 * 指定一个或多个类型参数。
 */
package day13;

public class GenericCon {
	public static void main(String[] args) {
		// 显示指定构造器的实际类型参数。
		GenericCon c = new <String>GenericCon("abc");
		// 编译器也可以自动推断构造器的实际类型参数。
		GenericCon c2 = new GenericCon("abc");
		GenericC<String> gc = new GenericC<>("abc");
		//当构造器是泛型构造器,类是泛型类,当我们显式的为构造器
		//指定类型参数,则此时,菱形语法将不能使用。
		// 错误
		// GenericC<String> gc2 = new <Integer>GenericC<>(10);
		GenericC<String> gc2 = new <Integer>GenericC<String>(10);
	}

	public <T> GenericCon(T t) {

	}
}

class GenericC<T> {
	public <E> GenericC(E e) {

	}
}

  11、泛型擦除

/*
 * 泛型的擦除
 * 泛型可以提供编译期间的类型检查。然而,这种类型检查也仅仅
 * 只能发生在编译期间,在编译之后生成的字节码文件(.class文件)
 * 中,所有的泛型信息都将会被擦除(所有的泛型信息都将丢失)。
 * 
 * 擦除前与擦除后表示:
 * 1 对于参数化类型,会使用原生类型进行替换。
 * 2 对于类型参数,会使用类型参数的上界进行替换。
 * 1) 对于无界的类型参数,使用Object进行替换。
 * 2) 对于含有一个上界的类型参数,使用上界进行替换。
 * 3) 对于含有多个上界的类型参数,使用第一个上界进行替换。
 * 
 * 因为在编译过后,再没有参数化类型,因此,instanceof右侧
 * 的类型就不能是参数化类型。
 * obj instanceof List<String>	 错误
 */
package day13;

public class Eraser {
	public static void main(String[] args) {
		// List<String> list = new ArrayList<>();
		// 擦除后
		// List list = new ArrayList();
	}

	// public <T> void f(T t) {}
	// 擦除后:
	// public void f(Object o) {}

	// public <T extends Shape> void g(T t) {}
	// 擦除后
	// public void g(Shape t) { }

	// public <T extensd Type1 & Type2> void k(T t) {}
	// 擦除后
	// public void k(Type1 t) {}

}

  12、泛型方法的重载

/*
 * 泛型方法的重载
 * 当泛型方法参与重载时,能够进行重载,要看泛型
 * 方法擦除后的参数列表而定。
 */
package day13;

public class GenericOverload {
	/*
	 * 不能重载
	 * public void f(List list) { }
	 * public void f(List<String> list) { }
	 * 可以重载
	 * public void f(String t) { }
	 * public <T> void f(T t) { }
	 * 不能重载
	 * public void f(Object o) { }
	 * public <T> void f(T t) { } 
	 * 不能重载
	 * public <E> void f(E o) { }
	 * public <T> void f(T t) { } 
	 * 可以重载
	 * public <E extends Shape> void f(E o) { }
	 * public <T> void f(T t) { } 
	 * 不能重载
	 * public <E extends Type1 & Type2> void f(E o) { }
	 * public <T extends Type1> void f(T t) { }
	 * 可以重载
	 * public <E extends Type2 & Type1> void f(E o) { }
	 * public <T extends Type1> void f(T t) { } 
	 * 不能重载
	 * public void f(int[] x) { }
	 * public void f(int... x) { }
	 */
}

  13、泛型方法的重写

/*
 * 泛型方法的重写
 * 方法重写的第2点规则:
 * 子类重写父类的方法,则要求子类与父类的参数列表类型一致,
 * 或者与父类参数列表擦除后的类型一致。
 */
package day13;

import java.util.List;

public class GenericOverride {
	public static void main(String[] args) {

	}
}

class Super {
	public void f(List<String> list) {

	}

	public void g(List list) {

	}
}

class Sub extends Super {
	@Override
	public void f(List list) {

	}
	// @Override
	// public void g(List<String> list) {}
}

  14、对象的比较  Comparable    Comparator 

package day13;

import java.util.Arrays;
import java.util.Comparator;

public class SortTest {
	public static void main(String[] args) {
		int[] x = { 5, 3, 1, 100, -2, 30 };
		Arrays.sort(x);
		System.out.println(Arrays.toString(x));
		Integer[] x2 = { 5, 3, 1, 100, -2, 30 };
		Arrays.sort(x2);
		System.out.println(Arrays.toString(x2));
		Student[] stu = { new Student(1, "a"), new Student(3, "b"), new Student(20, "c"), new Student(2, "d") };
		Arrays.sort(stu);
		// System.out.println(Arrays.toString(stu));

		// 自行指定比较规则
		// Arrays.sort(stu, new MyOrder());
		// System.out.println(Arrays.toString(stu));
		// Arrays.sort(stu, new Comparator<Student>() {
		// @Override
		// public int compare(Student o1, Student o2) {
		// return o2.getNo() - o1.getNo();
		// }
		// });
		// System.out.println(Arrays.toString(stu));
		Arrays.sort(stu, (o1, o2) -> o2.getNo() - o1.getNo());
		System.out.println(Arrays.toString(stu));
	}
}

class MyOrder implements Comparator<Student> {
	@Override
	public int compare(Student o1, Student o2) {
		// return o1.getNo() - o2.getNo();
		return o2.getNo() - o1.getNo();
	}
}

class Student implements Comparable<Student> {
	private int no;
	private String name;

	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Student(int no, String name) {
		super();
		this.no = no;
		this.name = name;
	}

	@Override
	public int compareTo(Student o) {
		// if (no > o.no) {
		// return 1;
		// } else if (no == o.no) {
		// return 0;
		// } else {
		// return -1;
		// }
		return no - o.no;
	}

	@Override
	public String toString() {
		return "Student [no=" + no + ", name=" + name + "]";
	}
}

  

      

posted @ 2017-03-18 15:08  凌-风  阅读(302)  评论(0)    收藏  举报