zoukankan      html  css  js  c++  java
  • 泛型

    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 + "]";
    	}
    }
    

      

          

  • 相关阅读:
    新版SourceTree免帐号登录安装
    常用 Git 命令清单
    Linux添加/删除用户和用户组
    使用sklearn优雅地进行数据挖掘
    matplotlib 散点图scatter
    使用Python进行描述性统计
    pandas将字段中的字符类型转化为时间类型,并设置为索引
    xp系统报错 windows explorer has encountered a problem and needs to close.We are sorry for the inconvenience
    python下几种打开文件的方式
    Python 使用 Matplotlib 做图时,如何画竖直和水平的分割线或者点画线或者直线?
  • 原文地址:https://www.cnblogs.com/liuwei6/p/6574193.html
Copyright © 2011-2022 走看看