Java泛型及实践
代码及说明:
/**
* @author zsm
* @date 2016年11月2日 下午11:23:30
* @version 1.0
* @parameter
* @return
*/
// JDK5开始支持泛型。泛型(类、接口、方法);泛型通配符、通配符上限、通配符下限
class _16_Generic {
// 泛型
List<String> strListStand = new ArrayList<String>();
// 泛型菱形语法(JDK7后初始化时泛型的具体类型可省略,自动判断)
List<String> strList = new ArrayList<>(); // 泛型类、接口
public interface Fruit<T> {
void add(T fruit);
} public interface MyMap<K, V> {
Set<K> keySet(); V put(K key, V value);
} public static class Apple<T> {
private T info; public Apple() {// 不能再写成Apple<T> } public Apple(T info) {
this.info = info;
} public T getInfo() {
return this.info;
} // 静态方法、静态初始化块、静态变量声明和初始化中不能使用类的泛型形参,静态类或接口定义处则可以
// static T name;//报错
// public static void bar(T msg) {}
// static {T name = "xiaoming";} // 静态方法不能使用类的类型参数,除非该静态方法是个泛型方法
public static <E, F> void ttt(E name, F age) {
;
}
} // 实现泛型接口或继承泛型类时:若新类不是泛型类,则父类(接口)必须指定类型实参而不能仍是类型形参;若新类仍是泛型类则父类(接口)可以仍用类型形参
public class A1 extends Apple<String> {// 不能再写成Apple<T>
public String getInfo() {
return super.info;
}
} public class A2<T> extends Apple<T> {
public T getInfo() {
return super.info;
}
} // 带泛型形参的类不会随着类型实参的不同而成为不同的类,接口亦然
static void testClassEqual() {
System.out.println((new Apple<String>()).getClass() == (new Apple<Integer>()).getClass());// true
List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();
System.out.println(strList.getClass() == intList.getClass());// true
} // 若Foo是Bar的子类,则Foo[]是Bar[]的子类,但List<Foo>却不是List<Bar>的子类。可以使用泛型通配符:?,
public void wildcardTest1(List<Object> c) {// 调用时只能传入List<Object>参数,不可传入List<String>等参数,因为后者不是前者的子类
for (int i = 0; i < c.size(); i++) {
System.out.println(c.get(i));
}
} public void wildcardTest2(List<?> c) {// 此时可传入List<String>等参数,但只可从c读不可往里写,因为c类型不定。即带类型通配符定义的对象只可读不可写
for (int i = 0; i < c.size(); i++) {
System.out.println(c.get(i));
// c.add(new Object());//编译错误,不可往c里写,因为c里元素类型未定
}
} // 类型通配符上限
public abstract class Shape {
public abstract void draw(MyCanvas c);
} public class Circle extends Shape {
@Override
public void draw(MyCanvas c) {
// TODO Auto-generated method stub
System.out.println("draw a circle on " + c);
}
} public class Rectangle extends Shape {
@Override
public void draw(MyCanvas c) {
// TODO Auto-generated method stub
System.out.println("draw a rectangle on " + c);
}
} public class MyCanvas {
public void drawAll0(List<?> shapes) {// 使用通配符时类型未定,所以访问每个元素只能用终极父类Object,这导致得进行麻烦的强制类型转换
for (Object obj : shapes) {
Shape s = (Shape) obj;
s.draw(this);
}
} public void drawAll1(List<? extends Shape> shapes) {// 使用通配符上限,从而知道元素元素类型的终极父类是Shape,这样不用进行强转。至多可以有一个类上限、多个接口上限,类上限需放最前。
for (Shape s : shapes) {
s.draw(this);
}
}
} // 泛型方法:方法中所用类型形参不要求在类声明中先出现该类型形参;类型形参位于方法修饰符和返回值之间;与泛型类、接口不同的是,无须在调用泛型方法时显式指明实参类型
public <T> void fromArrayToCollection(T[] a, Collection<T> c) {// a的实参可以是T[]的子类型
for (T o : a) {
c.add(o);
}
} public void test_fromArrayToCollection() {
fromArrayToCollection((new Object[10]), new ArrayList<Object>());
fromArrayToCollection((new Integer[10]), new ArrayList<Object>());
fromArrayToCollection((new Integer[10]), new ArrayList<>());// 与泛型类、接口不同的是,无须在调用泛型方法前显式指明实参类型(指在方法名前),编译器自己确定
fromArrayToCollection((new Integer[10]), new ArrayList<Number>());
// fromArrayToCollection((new Integer[10]), new ArrayList<String>());//编译错误
} // 泛型方法和类型通配符:方法参数间或返回值与参数间存在类型依赖关系(如子类)时采用泛型方法,否则类型参数只用一次,没有存在的必要,可以改用类型通配符。
public <T, S extends T> void copy1(List<T> des, List<S> src) {// S仅用了一次且与其他参数间没有依赖关系,因此没有存在的必要,改为下面的方法。
for (S s : src) {
des.add(s);
}
} public <T> void copy2(List<T> des, List<? extends T> src) {// 去掉S,改为使用类型通配符上限。
for (T t : src) {
des.add(t);
}
} // 泛型方法 ———— 泛型构造器
class Foo<E> {
public <T> Foo(T t) {
System.out.println(t);
} public void add(E e) { }
} public void test_genericConstructor() {
new Foo("good");
new Foo(1);
new <String>Foo("good");// 显示指定构造方法类型形参的实际类型
new <String>Foo<Integer>("good");// 又指定了类的类型形参的实际类型
new Foo<>("good");// 菱形语法
// new<String> Foo<>(1);// 如果显示指定了构造器类型形参的类型,则不可用菱形语法 Foo<Integer> p1 = new <String>Foo("good");
Foo<Integer> p2 = new <String>Foo<Integer>("good");
Foo<Integer> p3 = new Foo<Integer>("good");
// Foo<Integer> p4 = new<String> Foo<>("good");//如果显示指定了构造器类型形参的类型,则不可用菱形语法
} // 类型通配符下限。
// 返回最后一个元素,类型不可丢。上面的copy2方法如果要返回最后一个被复制的元素,则返回的会是des中元素的类型T,这样就丢失了src的类型即S。可以通过修改copy1解决,也可以通过通配符下限解决。
public <T, S extends T> S copy3(List<T> des, List<S> src) {// S仅用了一次且与其他参数间没有依赖关系,因此没有存在的必要,改为下面的方法。
int i = 0;
for (i = 0; i < src.size(); i++) {
des.add(src.get(i));
}
return src.get(i - 1);
} public <T> T copy4(List<? super T> des, List<T> src) {// 去掉S,改为类型通配符下限。
int i = 0;
for (i = 0; i < src.size(); i++) {
des.add(src.get(i));
}
return src.get(i - 1);
} // 檫除与转换:带泛型声明的类间转换
public static void test_Transform() {
List list;// 不指定实际类型参数,为raw type,默认为上限类型,此为Object
List<Integer> listInteger = new ArrayList<Integer>();
listInteger.add(1);
listInteger.add(2);
list = listInteger;// List<Integer>对象赋给未指定类型的List,原始类型丢失,变为Object List<String> listStr = list;// 编译没问题,只有警告:"未经检查的转换"
System.out.println(listStr.get(0));// 但访问里面元素,会发生运行时异常
} public static void main(String[] args) {
// TODO Auto-generated method stub } }
Java泛型及实践的更多相关文章
- Java 理论和实践: 了解泛型
转载自 : http://www.ibm.com/developerworks/cn/java/j-jtp01255.html 表面上看起来,无论语法还是应用的环境(比如容器类),泛型类型(或者泛型) ...
- Java 理论和实践: 了解泛型 识别和避免学习使用泛型过程中的陷阱
Brian Goetz (brian@quiotix.com), 首席顾问, Quiotix 简介: JDK 5.0 中增加的泛型类型,是 Java 语言中类型安全的一次重要改进.但是,对于初次使用泛 ...
- Java深度历险(五)——Java泛型
作者 成富 发布于 2011年3月3日 | 注意:QCon全球软件开发大会(北京)2016年4月21-23日,了解更多详情!17 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件 ...
- java 深度探险 java 泛型
Java泛型(generics)是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter).声明的类型参数在使用时用具体的类型来替换.泛型最主要的应用是在JD ...
- Java学习笔记(二一)——Java 泛型
[前面的话] 最近脸好干,掉皮,需要买点化妆品了. Java泛型好好学习一下. [定义] 一.泛型的定义主要有以下两种: 在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个 ...
- Java 泛型(Generics)
Generics, 类似C++中的模版. 允许在定义类和接口的时候使用类型参数(type parameters), 声明的类型参数在使用的时候用具体的类型来替换. 如 ArrayList<Str ...
- 10个精妙的Java编码最佳实践
这是一个比Josh Bloch的Effective Java规则更精妙的10条Java编码实践的列表.和Josh Bloch的列表容易学习并且关注日常情况相比,这个列表将包含涉及API/SPI设计中不 ...
- 转:理解Java泛型
JDK 5.0 中增加的泛型类型,是 Java 语言中类型安全的一次重要改进.但是,对于初次使用泛型类型的用户来说,泛型的某些方面看起来可能不容易明白,甚至非常奇怪.在本月的“Java 理论和实践”中 ...
- java泛型总结(类型擦除、伪泛型、陷阱)
JDK1.5开始实现了对泛型的支持,但是java对泛型支持的底层实现采用的是类型擦除的方式,这是一种伪泛型.这种实现方式虽然可用但有其缺陷. <Thinking in Java>的作者 B ...
随机推荐
- linux2.6 内存管理——概述
在紧接着相当长的篇幅中,都是围绕着Linux如何管理内存进行阐述,在内核中分配内存并不是一件非常容易的事情,因为在此过程中必须遵从内核特定的状态约束.linux内存管理建立在基本的分页机制基础上,在l ...
- Python笔记之不可不练
如果您已经有了一定的Python编程基础,那么本文就是为您的编程能力锦上添花,如果您刚刚开始对Python有一点点兴趣,不怕,Python的重点基础知识已经总结在博文<Python笔记之不可不知 ...
- ActiveMQ消息队列的使用及应用
这里就不说怎么安装了,直接解压出来就行了. 谢绝转载,作者保留所有权力 目录: 一:JMQ的两种消息模式 1.1:点对点的消息模式 1.2:订阅模式 二:点对点的实现代码 2.1:点对点的发送端 2 ...
- FFmpeg学习4:音频格式转换
前段时间,在学习试用FFmpeg播放音频的时候总是有杂音,网上的很多教程是基于之前版本的FFmpeg的,而新的FFmepg3中audio增加了平面(planar)格式,而SDL播放音频是不支持平面格式 ...
- 利用Python进行数据分析(14) pandas基础: 数据转换
数据转换指的是对数据的过滤.清理以及其他的转换操作. 移除重复数据 DataFrame里经常会出现重复行,DataFrame提供一个duplicated()方法检测各行是否重复,另一个drop_dup ...
- c#+handle.exe实现升级程序在运行时自动解除文件被占用的问题
我公司最近升级程序经常报出更新失败问题,究其原因,原来是更新时,他们可能又打开了正在被更新的文件,导致更新文件时,文件被其它进程占用,无法正常更新而报错,为了解决这个问题,我花了一周时间查询多方资料及 ...
- Effective前端4:尽可能地使用伪元素
伪元素是一个好东西,但是很多人都没怎么用,因为他们觉得伪元素太诡异了.其实使用伪元素有很多好处,最大的好处是它可以简化页面的html标签,同时用起来也很方便,善于使用伪元素可以让你的页面更加地简洁优雅 ...
- FastSocket学习笔记~再说客户端与服务端的组成
废话多说 很久之前,我写过几篇FastSocket的文章,基本属于使用的方法,而缺乏对概念的总结讲解,而本讲就是弥补一下上几讲的不足,将核心的模块再说说,再谈谈,再聊聊! 首先FastSocket由C ...
- JsCharts图表的介绍和简单使用
一.JSCharts介绍 JScharts是一个用于在浏览器直接绘制图表的javascript工 具包.JScharts支持柱状图.圆饼图以及线性图,可以直接将这个图插入网页, JScharts图的数 ...
- Java中的多线程你只要看这一篇就够了
学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:279558494 我们一起学Java! 引 如果对什么是线程.什么是进程仍存有疑惑, ...