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 ...
随机推荐
- EF Core 数据库迁移(Migration)
工具与环境介绍 1.开发环境为vs 2015 2.mysql EF Core支持采用 Pomelo.EntityFrameworkCore.MySql 源代码地址(https://github. ...
- 日常css技巧小结(2)-- inline-block带来的迷惑
一.问题描述 在平时布局中,inline-block使用的频率比很高,主要是因为可以让行标签设置宽高.我在布局过程中,发现了两个“问题”, 1行标签.display:inline-block之后的行标 ...
- JS魔法堂:深究JS异步编程模型
前言 上周5在公司作了关于JS异步编程模型的技术分享,可能是内容太干的缘故吧,最后从大家的表情看出"这条粉肠到底在说啥?"的结果:(下面是PPT的讲义,具体的PPT和示例代码在h ...
- Javascript中关于cookie的那些事儿
Javascript-cookie 什么是cookie? 指某些网站为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密).简单点来说就是:浏览器缓存. cookie由什 ...
- 在CentOS或RHEL上安装Nux Dextop仓库
介绍 Nux Dextop是类似CentOS.RHEL.ScientificLinux的第三方RPM仓库(比如:Ardour,Shutter等等).目前,Nux Dextop对CentOS/RHEL ...
- LINQ to SQL语句(19)之ADO.NET与LINQ to SQL
它基于由 ADO.NET 提供程序模型提供的服务.因此,我们可以将 LINQ to SQL 代码与现有的 ADO.Net 应用程序混合在一起,将当前 ADO.NET 解决方案迁移到 LINQ to S ...
- nginx反向代理下thinkphp、php获取不到正确的外网ip
在记录用户发送短信需要获取用户ip时,tp一直获取的是内网ip:10.10.10.10 tp框架获取ip方法:get_client_ip /** * 获取客户端IP地址 * @param intege ...
- Java - I/O
File类 java.io 操作文件和目录,与平台无关.具体的常用实例方法: File file = new File("."); // 以当前路径创建名为 ".&quo ...
- Mysql FROM_UNIXTIME效率 VS PHP date()效率 数据说话!
这几天在做数据统计,有几个统计图的需求是这样的: 按照年.月.日统计订单数量, 比方一年12个月,统计出1月多少订单,二月多少订单,按照这种模式统计. 但是数据库里存放的是 timestamp 的 ...
- [转载]C#委托和事件(Delegate、Event、EventHandler、EventArgs)
原文链接:http://blog.csdn.net/zwj7612356/article/details/8272520 14.1.委托 当要把方法作为实参传送给其他方法的形参时,形参需要使用委托.委 ...