泛型小结

参考书籍:《Java Generics and Collections》  authors:Maurice Naftalin,Philip Wadler

                  《Effective Java》                            author  :Joshua Bloch      译者:杨春花,俞黎敏

在没有泛型之前,从集合中读取的每一个对象都必须进行转换,如果不小心插入类型错误的对象,在运行期间对象转换的时候就会出错。有了泛型之后就可以告诉编译器集合能接受哪些类型的对象,在插入的时候进行自动转换,对象转换出错时及时报错。

每个类型都定义了parameterized type参数化类型和raw type原生类型,如List<String>,List便是原生类型,String便是参数化类型。

一些术语

Wildcards(通配符)

下面这个例子介绍了带有extends和super的wildcards的用法即通配符的两种形式:? extends E和? super E,另外只写?表示? extends Object的简写。

package com.company.collections.subtypingwildcards;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * wildcards通配符和subtyping子类型
 * 接口Collection有如下方法
 *    interface Collection<E> {
		  ...
			//"? extends E" ?局势wildcards通配符表示任何一种类型,这里表示E的任何一种子类型
		  public boolean addAll(Collection<? extends E> c);
		  ...
	  }
	  类Collections如下方法
	  // ? super T 表示src的元素师T的subtype,dst是T的supertype
	  	public static <T> void copy(List<? super T> dst, List<? extends T> src) {
		  for (int i = 0; i < src.size(); i++) {
		    dst.set(i, src.get(i));
		  }
		}

 *
 */
public class SubtypingWildcards {
	public static void main(String[] args) {
		//Wildcards with extends例子如下
		List<Number> nums = new ArrayList<Number>();
		List<Integer> ints = Arrays.asList(1, 2);
		List<Double> dbls = Arrays.asList(2.78, 3.14);
		//List<Number>是Collection<? extends Number>的子类型 
		//List<Integer>是Collection<? extends Number>的子类型,故ints可添加,dbls类似
		nums.addAll(ints);
		nums.addAll(dbls);
//		List<Integer> ints = Arrays.asList(1,2);
//		List<? extends Number> nums = ints;//because List<Integer> is a subtype of List<? extends Number>,没错
//		nums.add(3.14);  // compile-time error只能存放Integer,不解释

		//Wildcards with super例子如下
		List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
		List<Integer> ints2 = Arrays.asList(5, 6);
		Collections.copy(objs, ints2);
		for (Iterator iterator = objs.iterator(); iterator.hasNext();) {
			Object object = (Object) iterator.next();
			System.out.println(object.toString());
		}

	}
}


通配符什么时候使用,以及使用中需要注意的地方,例子如下(主要介绍的是The Get and Put Principle取出存取法则

package com.company.collections.subtypingwildcards;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 *什么时候用wildcards通配符?用? extends E还是? super E ?
 *
 *GetPut法则:从数据结构中取出数据用extends,存入数据用super,取和存都需要的时候就不用通配符
 *            If an extends wildcard  is present, 那就只能取数据
 *            if a  super    wildcard is present, 那就只能存数据
 *很好理解,取数据时,写了一方法参数有? extends E那么E的所有子类包括自己都能调用方法取数据
 *         存数据时,写了一方法参数有? super E那么存的时候不仅可以存E类型的,还可以存E的超类
 *
 *
 */
public class GetPutPrinciple {
	public static void main(String[] args) {
		//取数据  ? extends E
		List<Integer> ints = Arrays.asList(1,2,3);
		 System.out.println(sum(ints));

		List<Double> doubles = Arrays.asList(2.78,3.14);
		 System.out.println(sum(doubles));

		List<Number> nums = Arrays.<Number>asList(1,2,2.78,3.14);
		 System.out.println(sum(nums));
		//存数据 ? super E
		 List<Integer> ints2 = new ArrayList<Integer>();
		 count(ints2, 5);
		 System.out.println(ints2.toString());
		 //要是不用super,下面这两个调用就是非法的了
		 List<Number> nums2 = new ArrayList<Number>();
		 count(nums2, 5);  nums2.add(5.0);
		 System.out.println(nums2.toString());

		 List<Object> objs = new ArrayList<Object>();
		 count(objs, 5);  objs.add("five");
		 System.out.println(objs.toString());


		//既要取数据又要存数据,不用通配符?
		 List<Number> nums3 = new ArrayList<Number>();
		 System.out.println(sumCount(nums3,5));
		 
		 
//		 List<Integer> ints4 = Arrays.asList(1,2,3);
//		 List<? extends Number> nums4 = ints;
//		 double dbl = sum(nums4);  // ok
//		 nums4.add(3);  // compile-time error
		 
//		 List<Object> objs5 = Arrays.<Object>asList(1,"two");
//		 List<? super Integer> ints5 = objs;
//		 ints5.add(3);  // ok
//		 double dbl5 = sum(ints5);  // compile-time error


	}
	public static double sum(Collection<? extends Number> nums) {
		double s = 0.0;
		for (Number num : nums) s += num.doubleValue();
		return s;
	}
	public static void count(Collection<? super Integer> ints, int n) {
		  for (int i = 0; i < n; i++) ints.add(i);
		}
	public static double sumCount(Collection<Number> nums, int n) {
		  count(nums, n);
		  return sum(nums);
		}



}



与Array比较

区别一:

在书《Java Generics and Collections》中有讲到:array  subtyping is covariant,the subtyping relation for generics  is invariant。意思是说数组子类是协变量,而泛型不是,也就是,对于数组S[] 和T[],只要S是T的子类型,那么S[]便是T[]的子类型,叫协变,而泛型List<S>和List<T>,若S是T的子类型,但List<S>不是List<T>的子类型,二者相对独立。

区别二:

数组是具体化的(reified),因此数组在运行时才会知道并且检查元素类型约束,而泛型是通过擦除(erasure),所以编译期值强化他们的类型信息,在运行的时候丢弃元素类型信息,擦除可以让泛型与没有使用泛型的代码任意互用。在运行时,每个泛型类只有一种类型. 具体地说, List<Integer>, List<String> 和 List<List<String>> 在运行时都将具有相同的类型: List。

看下面例子

		Integer[] ints3 = new Integer[] {1,2,3};
		Number[] nums3 = ints3;
		nums3[2] = 3.14;  // array store 运行时报错,编译没问题

 

		List<Integer> ints1 = Arrays.asList(1,2,3);
		List<Number> nums1 = ints1; // compile-time error
		nums1.add(2, 3.14);

数组的例子很好理解,nums3实际是Integer类型,加个double类型数据当然报错,nums3是在运行时动态绑定为Integer的,故编译器没错。而泛型呢,编译期就报错,因为List<Integer>不是List<Number>的子类型,Integer是Number的子类型不管用,泛型不是协变的。

实际上,我要说的的是泛型将数组运行期类型检查提前到了编译期,好处就是编译期类型检查了,运行期就没必要检查了,更加高效,另外若有错误编译期间能即时报错。

另外,泛型的方法比数组的多,数组就是存取。但是,数组毕竟比泛型效率更高,因为数组不像泛型要装箱(boxing)。

使用数组的唯一理由是: 大量的原始数据类型, 可能可以获得性能上的提升. 不过一定要谨记: 不要优化你的程序, 除非经过严格而精确的测量证明存在性能问题. 另外, 有些情况下, 由于某些遗留系统的兼容问题, 你可能仍需要使用数组.所以,尽量使用泛型而不是数组。


擦除

前面已经解释了擦除。下面举几个例子说明一下。

以下内容引用自http://zy19982004.iteye.com/blog/1977055

使用擦除的核心动机:使得泛型化的客户端代码可以使用非泛型化的类库,非泛型化的客户端代码可以使用泛型化的类库。这个被称为“兼容迁移性”。这也从侧面反应了,前期的设计多么重要,倘若JDK1.0就将泛型纳入其中,必将是Java使用者的一大福音。

package com.jyz.study.jdk.generic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 在泛型代码内部,无法获得任何有关泛型参数类型的信息
 * @author JoyoungZhang@gmail.com
 *
 */
public class ClassTypeParameters {
	
	static class Frob<T>{}
	static class FrobF<T extends Number>{}
	static class FrobPM<P,M>{}
	
	private static List list1 = new ArrayList();
	private static List<Integer> list2 = new ArrayList<Integer>();
	private static Map<Integer, Integer> map1 = new HashMap<Integer, Integer>();
	
	
	static Frob f1 = new Frob();
	static FrobF<Integer> f2 = new FrobF<Integer>();
	static FrobPM<Integer, Double> f3 = new FrobPM<Integer, Double>();
	

	//Calss.getTypeParameters()将返回一个TypeVariable对象数组
	//表示有泛型声明所声明的形式类型参数
	public static void main(String[] args) {
		System.out.println(Arrays.toString(list1.getClass().getTypeParameters()));
		System.out.println(Arrays.toString(list2.getClass().getTypeParameters()));
		System.out.println(Arrays.toString(map1.getClass().getTypeParameters()));
		
		System.out.println(list1.getClass().getSimpleName());
		System.out.println(list2.getClass().getSimpleName());
		
		System.out.println(Arrays.toString(f1.getClass().getTypeParameters()));
		System.out.println(Arrays.toString(f2.getClass().getTypeParameters()));
		System.out.println(Arrays.toString(f3.getClass().getTypeParameters()));
	}
	
}


输出结果
[E]
[E]
[K, V]
ArrayList
ArrayList
[T]
[T]
[P, M]

 

 

擦除原则:

  1. 无限定的形式类型参数将被替换为Object。比喻List<T> T是无限定的,被替换为Object。
  2. 有限定的形式类型参数将被替换为第一个限定类型。比喻List<T extends Comparable & Serializable>,T被替换为Comparable,也称T被擦除到了Comparable。

 

 

动物目标检测数据集 一、基础信息 数据集名称:动物目标检测数据集 图片数量: - 训练集:9,134张图片 - 验证集:1,529张图片 - 测试集:1,519张图片 总计:12,182张图片 分类类别: Bear(熊)、Cat(猫)、Cattle(牛)、Chicken(鸡)、Deer(鹿)、Dog(狗)、Elephant(大象)、Horse(马)、Monkey(猴子)、Sheep(绵羊) 标注格式: YOLO格式,包含归一化坐标的边界框和数字编码类别标签,支持目标检测模开发。 数据特性: 涵盖俯拍视角、地面视角等多角度动物影像,适用于复杂环境下的动物识别需求。 二、适用场景 农业智能监测: 支持畜牧管理系统开发,自动识别牲畜种类并统计数量,提升养殖场管理效率。 野生动物保护: 应用于自然保护区监控系统,实时检测特定动物物种,辅助生态研究和盗猎预警。 智能养殖设备: 为自动饲喂系统、健康监测设备等提供视觉识别能力,实现精准个体识别。 教育研究工具: 适用于动物行为学研究和计算机视觉教学,提供标准化的多物种检测数据集。 遥感图像分析: 支持航拍图像中的动物种群分布分析,适用于生态调查和栖息地研究。 三、数据集优势 多物种覆盖: 包含10类常见经济动物和野生动物,覆盖陆生哺乳动物与家禽类别,满足跨场景需求。 高密度标注: 支持单图多目标检测,部分样本包含重叠目标标注,模拟真实场景下的复杂检测需求。 数据平衡性: 经分层抽样保证各类别均衡分布,避免模训练时的类别偏差问题。 工业级适用性: 标注数据兼容YOLO系列模框架,支持快速迁移学习和生产环境部署。 场景多样性: 包含白天/夜间、近距离/远距离、单体/群体等多种拍摄条件,增强模鲁棒性。
数据集介绍:农场与野生动物目标检测数据集 一、基础信息 数据集名称:农场与野生动物目标检测数据集 图片规模: - 训练集:13,154张图片 - 验证集:559张图片 - 测试集:92张图片 分类类别: - Cow(牛):农场核心牲畜,包含多种姿态和场景 - Deer(鹿):涵盖野外环境中的鹿类目标 - Sheep(羊):包含不同品种的绵羊和山羊 - Waterdeer(獐):稀有野生动物目标检测样本 标注格式: YOLO格式标准标注,含精确边界框坐标和类别标签 数据特征: 包含航拍、地面拍摄等多视角数据,适用于复杂环境下的目标检测任务 二、适用场景 智慧农业系统开发: 支持畜牧数量统计、牲畜行为监测等农业自动化管理应用 野生动物保护监测: 适用于自然保护区生物多样性监测系统的开发与优化 生态研究数据库构建: 为动物分布研究提供标准化视觉数据支撑 智能畜牧管理: 赋能养殖场自动化监控系统,实现牲畜健康状态追踪 多目标检测算法验证: 提供跨物种检测基准,支持算法鲁棒性测试 三、数据集优势 多场景覆盖能力: 整合农场环境与自然场景数据,包含光照变化、遮挡等真实场景 精确标注体系: - 经专业团队双重校验的YOLO格式标注 - 边界框精准匹配动物形态特征 数据多样性突出: - 包含静态、动态多种动物状态 - 涵盖个体与群体检测场景 任务适配性强: - 可直接应用于YOLO系列模训练 - 支持从目标检测扩展到行为分析等衍生任务 生态研究价值: 特别包含獐等稀有物种样本,助力野生动物保护AI应用开发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值