Java编程思想:通配符(后面有两个小节,研究的不够深入)
import java.util.*; public class Test { public static void main(String[] args) { } } /* 15.9 边界 要点: 1.T继承的顺序,类放必须放在第一位,后面跟接口 2.类与接口用&进行链接 3.可以继承于一个类,可以实现多个接口 4.可以使用边界类的方法 5.可以使用边界类的公共变量 在继承的每个层次上添加边界限制 */ /* 15.10 通配符 问题: 编译器允许你将Fruit放置在这个数组中,这对于编译器来说是有意义的,但是它有一个Fruit[] 引用——它没有理由不允许将Fruit对象或者任何从Fruit对象继承出来的对象(例如Orange) 放置在这个数组中。但是,在运行时的数组机制知道它处理的时Apple[],因此会在向数组中放置 异构类型时抛出异常。 */ class Fruit{} class Apple extends Fruit {} class LittleApple extends Apple {} class Orange extends Fruit {} /* 需求: 以下转换你是有需求的,但是不允许 */ class Need{ static void test() { //List<Fruit> fruits = new ArrayList<Apple>(); } } /* 需求: 通配符可以满足以上你的需求 List<? extends Fruit>:具有任何从Fruit继承的类型的列表,但是这并不意味着 这个List将持有任何类型的Fruit。通配符引用的是明确的类型,它意味着“某种first 引用没有指定的具体类型的”。因此这个被赋值的List必须持有诸如Fruit或Apple这样的 某种指定类型,但是为了向上转型为fruit,这个类型是什么样的,没人关心。 */ class Need1{ static void test(){ // List<? extends Fruit> fruits = new ArrayList<Apple>(); // fruits.add(new Apple()); // fruits.add(new Fruit()); // fruits.add(new Object()); } } /* 15.10.1 编译器有多聪明 尽管add()将接受一个具有泛型参数类型的参数,但是contains()和 indexOf()将接受Object类型的 参数。因此当你指定一个ArrayList<? extends Fruit>时,add()的参数就变成了“? extends Fruit”。 从这个描述中,编译器并不能了解这里需要的是Fruit的哪个具体子类型,因此它不会接受任何类型的 Fruit。如果先经Apple先向上转型为Fruit也无济于事——编译器直接拒绝对参数列表中涉及通配符 的方法(如add())的调用。 在使用contains()和indexOf()时,参数类型时Object,因此不涉及任何通配符,而编译器也将允许 这个调用。这意味这将由泛型类型的涉及者来决定哪些调用是安全的,并有Object类型作为其 参数类型。 */ class CompilerIntelligent{ static void test() { List<? extends Fruit> fruits = Arrays.asList(new Apple()); Apple a = (Apple)fruits.); fruits.contains(new Apple()); fruits.indexOf(new Apple()); } } /* 需求: 为了在类型中使用通配符的情况下禁止这类调用,我们需要在参数列表中使用类型参数。 */ class Holder<T>{ private T value; public Holder() {} public Holder(T val) {value = val;} public T get(){return value;} public void set(T val){ value = value; } public boolean equals(Object obj){ return value.equals(obj); } static void main(String[] args) { //常规是允许操作的 Holder<Apple> apples = new Holder<>(new Apple()); Apple d = apples.get(); apples.set(d); Holder<? extends Fruit> fruits = apples; Fruit p = fruits.get(); //fruits.set(p); //这个方法果然被禁用了,哈哈 } } /* 15.10.2 逆变 知识点: 超类型通配符:可以申明通配符是由某个特定类的任何基类来界定的,方法是 <? super MyClass>,甚至可以使用类型参数:<? super T>。这使得你 可以安全的传递一个对象到泛型类型中。 */ /* extends:有继承的意思,可以很明显的感觉到,你持有的可能是我持有的子类 这是一个错误的理解!!! //super:有父类的意思,但是这儿明显没有这个用法,更像是在指定我的父类就是你 */ /* 卧槽,我发现我理解错了!super和extends的的确确是相反的两个方向。extends是向下 而super是向上的。那为什么这个地方可以放进去两个值了,因为这个地方说的是我List容 器里放的就是你Apple的父类,所以你Apple,以及Apple子类都可以放在里面。 在来思考一下,为什么extends就不能够放了List<? extends Fruit>说的是我List容器 里放的就是你Frutit的子类,那完了,到底是哪个子类,谁也搞不清 */ class SuperTypeWildcards { static void test(List<? super Apple> apples) { apples.add(new Apple()); apples.add(new LittleApple()); } } /* 协变与通配符的一个案例 */ class GenericReading{ static List<Apple> apples = Arrays.asList(new Apple()); static List<Fruit> fruits = Arrays.asList(new Fruit()); //泛型方法实现的,使用确切的类型参数的版本 static <T> T readExact(List<T> list){ ); } //泛型类实现的版本,使用确切的类型参数的版本 static class Reader<T>{ T readExact(List<T> list){ ); } <H> H readExact2(List<H> list){ ); } } //泛型类实现的版本,使用了协变通配符 static class ConvairanReader<T>{ T readerConvariant(List<? extends T> list) { ); } } //测试一: static void f1() { Apple a = readExact(apples); Fruit f1 = readExact(fruits); /* 分析: readExact(apples)返回的是一个Apple对象, 只是在赋值的时候进行了一次转型而已 */ Fruit f2 = readExact(apples); } //测试二: static void f2() { Reader<Fruit> fruitReader = new Reader<>(); Fruit f = fruitReader.readExact(fruits); /* 分析: 首先在声明fruitReader时,由于指定的参数类型时Fruit, 同时这个对象的readExact方法与这个参数类型绑定了,也 就说此时的readExact方法,只能接受一个List<Fruit> 类型 如果在类里添加一个泛型方法,所有的问题都会迎刃而解。 */ //Fruit f = fruitReader.readExact(apples); } static void f3() { ConvairanReader<Fruit> fruitReader = new ConvairanReader<>(); Fruit f = fruitReader.readerConvariant(fruits); /* 分析: 虽然在创建对象时指定了类型参数为Fruit,但是方法接受的参数中 又明确说明了可以接受<? extends Fruit>,所以这个地方是允许 的。哈哈 */ Fruit a = fruitReader.readerConvariant(apples); } static void test(){ } } /* 15.10.3 无界通配符 ——标记一下,这后面有一部分,没有细读,需要是再读吧 知识点: 使用无界通配符好像等于使用原生类型,事实上,编译器初看起来是支持这种判断的。 在很多情况下,编译器很少关心你使用的是原生类型,还是<?>。在这种情况跟中, <?>可以被认为是一种装饰,但是它仍旧是有价值的,因为,实际上,它是在声明: “我想用Java的泛型来编写这段代码,我在这里并不是要用原生类型,但是在当前这 种情况下,泛型参数可以持有任何类型” */ /* 需求: 当你在处理多个泛型参数时,有时允许一个参数可以是任何类型,同时为其他参数 确定某种特定类型的这种能力会显得很重要。 List:实际上也是List<Object> List<?>:表示具有某种特定类型的非原生List,只是我们不知道这种类型是什么 */ class UnboundedWildCards2{ static Map map1; static Map<?,?> map2; static Map<String,?> map3; static void test() { map1 = new HashMap(); map2 = new HashMap(); map3 = new HashMap(); //这个地方会有警告,但是我用Ide看不到 } } /* 编译器何时才会关注原生类型和涉及无界通配符类型之间的差异呢? */ class Wildcards{ //这个实验很失败,看不到书中的效果 static void rawArgs(Holder holder,Object arg){ holder.set(arg);//看不到警告 holder.set(new Wildcards()); holder.get(); } // static void unbounedArgs(Holder<?> holder,Object arg){ // holder.set(arg); 报错了,这儿 } } /* 15.10.4 捕获转换 ——没有细读,稍等放放再读吧 */
Java编程思想:通配符(后面有两个小节,研究的不够深入)的更多相关文章
- Java编程思想(11~17)
[注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第十一章 持有对象 11.1 泛型和类型安全的容器>eg: List<St ...
- Java编程思想(后)
Java编程思想(后) 持有对象 如果一个程序只包含固定数量的且其生命期都是已知的对象,那么这是一个非常简单的程序. Java中的库基本类型: List, Set, Queue和Map --- 称为集 ...
- Java中的泛型 --- Java 编程思想
前言 我一直都认为泛型是程序语言设计中一个非常基础,重要的概念,Java 中的泛型到底是怎么样的,为什么会有泛型,泛型怎么发展出来的.通透理解泛型是学好基础里面中非常重要的.于是,我对<Ja ...
- Java编程思想 4th 第2章 一切都是对象
Java是基于C++的,但Java是一种更纯粹的面向对象程序设计语言,和C++不同的是,Java只支持面向对象编程,因此Java的编程风格也是纯OOP风格的,即一切都是类,所有事情通过类对象协作来完成 ...
- 33.JAVA编程思想——JAVA IO File类
33.JAVA编程思想--JAVA IO File类 RandomAccessFile用于包括了已知长度记录的文件.以便我们能用 seek()从一条记录移至还有一条:然后读取或改动那些记录. 各记录的 ...
- JAVA编程思想——分析阅读
需要源码.JDK1.6 .编码风格参考阿里java规约 7/12开始 有点意识到自己喜欢理论大而泛的模糊知识的学习,而不喜欢实践和细节的打磨,是因为粗心浮躁导致的么? cron表达式使用 设计能力.领 ...
- 《Java编程思想》学习笔记(二)——类加载及执行顺序
<Java编程思想>学习笔记(二)--类加载及执行顺序 (这是很久之前写的,保存在印象笔记上,今天写在博客上.) 今天看Java编程思想,看到这样一道代码 //: OrderOfIniti ...
- #Java编程思想笔记(一)——static
Java编程思想笔记(一)--static 看<Java编程思想>已经有一段时间了,一直以来都把笔记做在印象笔记上,今天开始写博客来记录. 第一篇笔记来写static关键字. static ...
- [Java编程思想-学习笔记]第3章 操作符
3.1 更简单的打印语句 学习编程语言的通许遇到的第一个程序无非打印"Hello, world"了,然而在Java中要写成 System.out.println("He ...
- Java编程思想重点笔记(Java开发必看)
Java编程思想重点笔记(Java开发必看) Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而 ...
随机推荐
- ADO.NET基础开发
ADO.NET是微软新一代.NET数据库的访问架构,ADO是ActiveX Data Objects的缩写.ADO.NET是数据库应用程序和数据源之间沟通的桥梁,主要提供了一个面向对象的数据访问架构, ...
- Win8Metro(C#)数字图像处理--2.5图像亮度调整
原文:Win8Metro(C#)数字图像处理--2.5图像亮度调整 2.5图像亮度调整函数 [函数名称] 图像亮度调整函数BrightnessAdjustProcess(WriteableBit ...
- Win10《芒果TV》更新v3.5.2星玥版:修复电视台直播异常,优化添加下载提示
Win10版<芒果TV>在更新夏至版之后,根据收集到的热心用户反馈,全平台同步更新星玥版v3.5.2,修复电视台直播异常,优化添加下载提示,进一步提升使用体验. Win10版<芒果T ...
- QT5 屏幕旋转90度
主要思路是将所有项目界面加载到QGraphicsScene,再进行旋转操作.直接上代码#include <QApplication>#include <QGraphicsView&g ...
- 解决Nextcloud 无法删除目录
1)进入维护模式 sudo -u www php /www/wwwroot/192.168.40.159/occ maintenance:mode --on 2)使用mysql命令行工具,在nextc ...
- 第五章 FISCO BCOS 区块链浏览器的部署
想了解相关区块链开发,技术提问,请加QQ群:538327407 前提 前面我们已经通过底层部署.sdk调测.自定义智能合约编写与部署.联合单元测试调测,已经初步对FISCO BCOS的区块链底层和实际 ...
- Redis相关面试题
Reids:单线程+io多路复用机制 Redis与Memcached的区别: 一.memcached值是简单字符串,redis支持hash.set.list等复杂数据类型 二.redis可持久化数据, ...
- 推荐一个高效,易用功能强大的可视化API管理平台
项目管理 提供基本的项目分组,项目管理,接口管理功能 接口管理 友好的接口文档,基于websocket的多人协作接口编辑功能和类postman测试工具,让多人协作成倍提升开发效率 MockServer ...
- Python自学day-3
一.集合 集合元素不会重复,而且是无序的. 定义集合: set_1 = {1,2,3,4,5} set求交集(intersection): set1 = set([1,2, ...
- 妹子问我maven是啥?从相亲说起。。
自从上一篇原创文章: 第一次教妹子安装IDEA 在<java技术之家>公号发表之后,大家的好评如潮,这给了我继续写下去的信心.感谢你们的支持,我会继续努力的. 自从漂亮妹妹加入我们研发团队 ...