/**
* Java泛型纪要
* 泛型的使用场景:
* 引言:在下段代码中:
*/
public static void main(String[] args) {
/**
* 创建List对象;
* 没有规定存储什么类型;
* 此时存储什么样的类型都不会报错;
* 例如:String 、int 、Double。。。等等;
*/
List list = new ArrayList();
/**
* 插入数据:
* list.add("String"); 插入String类型数据;
* list.add(111); 插入int类型的数据;
* 此时在没有限定具体类型的情况下list对象可以装在任意类型的数据进入。
*/
list.add("String");
list.add(111);
/**
* 创建一个预设数据类型的List集合listStr;
* List集合的特点:存储数据无序,且可以存储重复数据;
*
* 我们知道,在某些特定的业务场景之下,可能某个接口需要纯净类型的数据集合;
* 那么此时我们就需要把现拥有的数据集合进行拆分处理,最终返回对应需要的纯类型数据集合;
* 那么基于这种业务场景下,给出如下小Demo:
* Demo说明:模拟一个需要存储特定类型数据的集合;将现有的多元素类型的集合数据插入到预订类型集合中测试;
*
*
* 运行时会出现一个问题:
* 编译时通过;
* 运行时会有java.lang.ClassCastException异常;
* 因为:预设的集合类型是String类型,那么在listS集合中就只能装载String类型的元素数据;
* 而list对象中同时存在String和int类型的数据;因此当存储int类型的数据进入listStr集合时无法自动类型转换,
* 故而会报java.lang.ClassCastException的异常;
*/
List<String> listStr = new ArrayList<String>();
/**
* 第一种循环遍历方式;
* 循环
*/
for(int i=0; i<list.size(); i++){
listStr.add((String) list.get(i));
System.out.println(list.get(i));
}
/**
* 第二种迭代遍历方式;
* 遍历
*
* iterator(); 获取迭代器对象;
* hasNext(); 验证当前迭代位之后是否还有元素数据;
* next(); 获取迭代位的后一位元素数据;
*
* 迭代器的原理:迭代器的遍历存储是以数组方式运行,但是在初始化状态中,迭代器的下标不会指向第一位元素;
* hasNext(); 方法运行时预判是否存在0+1|n+1下标位,存在返回true;不存在返回false;
* next(); 方法会在调用的时候返回0+1|n+1下标位上的元素;
*/
// Iterator iterator = list.iterator();
// while(iterator.hasNext()){
// listStr.add((String) iterator.next());
// System.out.println(iterator.next());
// }
}
/**
* 泛型的使用:
*
* 1. 类中使用
*
* 语法:
* 修饰符 class 类名<代表泛型的变量> { }
*
* 以下附上一段小Demo供参考;
*/
/**
* 定义拥有泛型的类;
* 语法:修饰符 class 类名<代表泛型的变量> { }
*
* @author Administrator
* @param <E>
*/
public class ClassFXnTest<E> {
/**
* E在java中没有这种类型,此处只是一个变量;
* 届时传入什么类型,E就表示什么类型;
*/
E val;
/**
* 构造赋值;
* @param e
*/
public ClassFXnTest(E e){
this.val = e;
}
/**
* 参数获取;
* @return
*/
public E getStr(){
return val;
}
}
/**
* 创建临时数据获取的测试类;
* @author Administrator
*/
class GoPear{
/**
* main函数:程序执行的入口;
* @param args
*/
public static void main(String[] args) {
/**
* 创建ClassFXnTest对象利用其构造方法直接赋值进入;
*/
ClassFXnTest<String> fun = new ClassFXnTest<String>("小灰灰");
System.out.println(fun.getStr());
}
}
/**
* 2. 方法中使用
* 语法:
* 修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
*/
package cn.tan.inter.interfaces;
import cn.tan.inter.interfaces.InterfaceTest;
/**
* 定义含有泛型的方法类;
* @author TANJIYUAN
*/
public class InterfaceTest {
/**
* 定义含有泛型的方法;
* 方法返回参数对象类型;
* @param e
*/
public <E> void printE(E e) {
System.out.println(e.getClass());
}
// 返回对象内容;
public <E> E getE(E e) {
return e;
}
}
/**
* 测试类
* @author TANJIYUAN
*/
class Goto{
public static void main(String[] args) {
// 实例化对象;
InterfaceTest interfaces = new InterfaceTest();
// 打印方法参数对象类型;
interfaces.printE("222");
interfaces.printE(333);
}
}
/**
* 3. 接口中使用:
*
* 语法:
* 修饰符 interface接口名<代表泛型的变量> { }
*
* 下面给出以下示例代码:
*/
/**
* 定义一个含有泛型的接口;
* @author TANJIYUAN
* @param <E>
*/
public interface Fu<E> {
/**
* 抽象方法Go;
* Java中没有E这种类型;
* 在这里E仅仅只是一个变量;
* 最终会根据传入的参数类型决定E为什么类型;
* @param e
*/
public abstract void go(E e);
/**
* 抽象方法;
* @return
*/
public abstract E getE();
}
/**
* 定义了实现含有泛型Fu接口的实现类Zi;
* 注意:
* 所实现接口的泛型类型确定有两种情况:
* 第一种情况:能够确定,那么子类实现父类时就要确定父类泛型的具体类型;
* 代码如下:
* @author TANJIYUAN
*/
//class Zi implements Fu<Boolean>{
//
// @Override
// public void go(Boolean flag) {
// // Codding ...
// }
//
// @Override
// public Boolean getE() {
// // Codding ...
// return true;
// }
//}
/**
* 第二种情况:
* 如果类型始终不能够确定,那就在对象创建时最终确定对象的类型;
* 代码如下:
* @author TANJIYUAN
*/
class Zi<E> implements Fu<E>{
@Override
public void go(E e) {
System.out.println(e.getClass());
// Codding ...
}
@Override
public E getE() {
// Codding ...
return null;
}
}
class Test {
public static void main(String[] args) {
Zi<String> zi = new Zi<String>();
zi.go("小灰灰");
}
}
/**
* 4. 泛型通配符
* 场景:当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示;
* 需要注意:一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
*/
/**
* 定义一个仅接收Collection集合数据参数,未知类型的方法;
* 其中泛型中的?标示占位;其所表示的类型在未传参之前属于未知;
* @param coll
*/
public static void gotos(Collection<?> coll){
// Codding ...
System.out.println(coll.getClass());
}
/**
* 程序执行的入口;
* @param args
*/
public static void main(String[] args) {
// 定义一个List集合;
List<String> list = new ArrayList<String>();
// 定义一个Set集合;
Set<Integer> set = new HashSet<Integer>();
/**
* 定义一个Map
* 暂借这个案例说明一下:Map非Collection下的实现接口;
* 以下案例供参考:
* gotos(map); // 报错;
* 报错原因是Map即非Collection子集那就和方法中定义的泛型不符,故而报错;
*
* 其中Map非Collection子集:原因是Map数据结构不同于Collection数据接口;
*/
Map<Integer,Boolean> map = new HashMap<Integer,Boolean>();
// gotos(map); // 报错;
gotos(list);
gotos(set);
}
/**
* 5. 受限泛型
*
* 泛型上限:
* 语法:对象类型 <? extends 指定对象类型 > 对象名称
* 特点:只接受"指定对象类型"或者其子类类型的数据对象;
*
* 泛型下限
* 语法:对象类型 <? super 指定对象类型 > 对象名称
* 特点:只接受"指定对象类型"或者其父类类型的数据对象;
*
*
*/
/**
* 定一个拥有泛型上限参数的方法;
* 其中泛型中占位的关系是:
* 在Collection<?>泛型中,未来的参数类型必须是Number或者Number下的子类;
* 如果传入参数类型不满足"? extends Number",则编译不通过;
* @param coll
*/
public static void getExtends(Collection<? extends Number> coll){
// Codding ...
};
/**
* 定义一个拥有泛型下限参数的方法;
* 其中的泛型占位关系是:
* 在Collection<?>泛型中,未来传入的参数必须Number或者Number类的父类;
* 如果传入参数类型不满足"? super Number",同样编译不通过;
* @param coll
*/
public static void getSuper(Collection<? super Number> coll){
// Codding ...
}
public static void main(String[] args) {
// 定义临时测试集合;
List<String> strList = new ArrayList<String>();
List<Integer> intList = new ArrayList<Integer>();
List<Number> numList = new ArrayList<Number>();
List<Object> objList = new ArrayList<Object>();
// 上限方法测试;
// getExtends(strList); // 编译失败;String类型并非Number类的子类;
getExtends(intList);
getExtends(numList);
// getExtends(objList); // 编译失败; objList类型并非Number类的子类;
// 下限方法测试;
// getSuper(strList); // 编译失败;String类型并非Number类的父类;
// getSuper(intList); // 编译失败; Integer类型并非Number类的父类;
getSuper(numList);
getSuper(objList);
}
/**
* 今天整理关于泛型的纪要:
* 无意间看到网上有一篇关于泛型的文章举了一个列出指定类子类列表的示例;
* 觉得其没有理解其中的原理,特在此编辑一例小Demo参考;
* @author Administrator
*/
// 定义一个父类;
public class Animal {}
// 定义一个继承自Animal的子类Dog;
class Dog extends Animal{}
// 定义一个继承自Animal的子类Cat;
class Cat extends Animal{}
/**
* 定义一个测试类;
* 用例目的:
* 说明编译失败的原因;
* @author Administrator
*/
class Test {
// 程序的主函数|入口;
public static void main(String[] args) {
// 实例化对应的子类对象;
List<Dog> listDog = new ArrayList<Dog>();
List<Cat> listCat = new ArrayList<Cat>();
/**
* 在此说明一下:由于此案例是就网页文章进行分析,所以或有不清楚的地方,读者不必细究;
* 原文中:getExtendSAnimal()方法使用的泛型上限语法属于神秘人提供,他只知其用而不知其所以用;
* 而getAnimal()方法中使用的集合存储是其的第一稿,若论实现也是没问题的,只是多了许多不必要的强类型转换;
*
* 以下做出案例分析:
* 如上:创建了两个实例化对象listDog,listCat;
* 这两个对象都属于Animal对象的子集,按理说通过getExtendSAnimal()和getAnimal()都可以实现;
* 但是,在正常开发中,为了提高运行效率,我们要尽量避免代码中出现的强类型转换;
* 1.网页博主的getAnimal()方法虽然如下编译出错,但是通过强类型转换可以实现.为了效率可读尽量避免此中方式;
* 具体的实现方式在下面的注解文档中有示例;
* getExtendSAnimal()方式属于泛型上限处理,没什么的大的问题.此处也就不多做赘述;
*/
getExtendSAnimal(listDog);
getExtendSAnimal(listCat);
/**
* 此处遍历出错是因为传入的集合对象类型非Animal类型;
* 若要编译通过需进行类型转换;
*/
// getAnimal(listDog); // 编译失败
// getAnimal(listCat); // 编译失败;
// List<Animal> listDog = new ArrayList<Animal>();
// List<Animal> listCat = new ArrayList<Animal>();
//
// getExtendSAnimal(listDog);
// getExtendSAnimal(listCat);
// getAnimal(listDog);
// getAnimal(listCat);
}
/**
* 定义一个接受限定类型的方法;
* 技术点:泛型通配符、泛型上限;
* @param coll
*/
public static void getExtendSAnimal(Collection<? extends Animal> coll){
// Codding ...
}
/**
* 定义一个接收指定类型的Animal类型参数的方法;
* 技术点:集合泛型;
* @param list
*/
public static void getAnimal(List<Animal> list){
// Codding ...
}
}