java编程思想:通配符(后面有两个小节,研究的不够深入)(代码片段)

junjie2019 junjie2019     2022-11-29     581

关键词:

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.get(0);
        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)
        return list.get(0);
    

    //泛型类实现的版本,使用确切的类型参数的版本
    static class Reader<T>
        T readExact(List<T> list)
            return list.get(0);
        

        <H> H readExact2(List<H> list)
            return list.get(0);
        
    

    //泛型类实现的版本,使用了协变通配符
    static class ConvairanReader<T>
        T readerConvariant(List<? extends T> list) 
            return list.get(0);
        
    


    //测试一:
    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编程思想》~异常终于拿出压箱底的那本《Java编程思想》。这本书我年轻的时候就买了,但是翻过几页后就放弃了。没想到这两天翻了一下,真的有收获。看了一下第12章异常,有两个地方令我感悟很深。使用嵌... 查看详情

面向接口编程详解——模式研究

通过前面两篇,我想各位朋友对“面向接口编程”的思想有了一定认识,并通过第二篇的例子,获得了一定的直观印象。但是,第二篇中的例子旨在展示面向接口编程的实现方法,比较简单,不能体现出面向接口编程的优... 查看详情

深入理解java泛型协变逆变泛型通配符自限定(代码片段)

...的应用,解答了许多比较难的问题。纯函数协变逆变泛型通配符PECS法则自限定Part1:协变与逆变Java8引入了函数式接口,从此方法传参可以传递函数了,有人说这是语法糖。实际上,这是编程范式的转换,思想体系的变化。一、纯... 查看详情

java面向对象

...的面向对象,这是一种新的思想,让我们从之前的结构化编程转化称为面向对象编程。前几天我们很不习惯,也不是很理解,但学习到了后面,我们多多练习,也理解了面向对象的好处,能让我们更能理解这样编程的好处,能够... 查看详情

《java编程思想》有必要买吗

《java编程思想》有必要买吗 1.看到过好多个这样的提问,其实我一般真的不那么容易分享自己的这点心得的,这是第一次回答这样的“推荐书籍”方面的问题。  我买编程方面的书籍,有一个非常清晰、坚决的原则——电... 查看详情

java编程思想(初始化与清理)

  随着计算机革命的发展,“不安全”的编程方式已逐渐成为编程代价高昂的主因之一。  初始化和清理正是涉及安全的两个问题。C++引入了构造器的概念,在创建对象时被自动调用的特殊方法。Java也采用了构造器,... 查看详情

java编程思想第四版(完整中文高清版)pdf

​这是一本有独到、深入的见解的Java语言,以通俗易懂及小而直接的示例解释了一个个晦涩抽象的概念。本书共22章,包括操作符、控制执行流程、访问权限控制、复用类、多态、接口、通过异常处理错误、字符串、泛型、数组... 查看详情

java编程思想(七复用类)

   复用代码是Java众多引人注目的功能之一。   复用类有两个方法。第一种:只需在新的类中产生现有类的对象。由于新的类是由现有类的对象所组成,所以这种方法称为组合。第二种:按照现有类的类型来创建新类。... 查看详情

用word通配符添加空格

...头的第几章(节、段)后面加一个空格,请问有什么替换通配符可以实现?段中也有出现第几章(节、段)的地方,但段中的不需要加空格。查找内容输入:(^13第?[章,节,段])替换内容输入:\\1注意:(数字1的后边加一个你要添... 查看详情

简述变量间的相关分析都有哪些方法

...测另一个变量的取值.这部分内容涉及到一些重要的统计思想和方法,对学生的学习和教师的教学都有一定的难度.本文就研究对象、核心概念、研究方法、统计思想及相关应用进行简单的解读,提出一些教学建议,希望对教学... 查看详情

java开发实战!java编程思想和java疯狂讲义

一、不少培训班候选人的简历中,缺乏足够的商业项目年限不少同学会有这样得感受:投出去不少简历,但就没有面试机会,对培训班出身的朋友来说,可能这种情况更甚,原因是,这些简历没过筛选... 查看详情

你所不知道的java编程思想

读thinkinginjava这本书的时候,有这么一句话“在编译单元的内部,可以有一个公共(public)类,它必须拥有与文件相同的名字”有以下疑问:在一个类中说可以有一个public类,那是不是也就是说可以没有呢?抱着这个问题... 查看详情

java编程思想一第二章(对象)

...继续学习,然后再经过考虑和各大博主推荐选择了《java编程思想》这本书,在此分享学习心得跟大家共勉,也算是对自己的监督吧。(本内容需要有一定的基础才能看,类似于基础回顾,强化理解,新手可能有些地方不太能听懂)... 查看详情

java编程思想(对象导论)

...。   一开始在各种大牛的网上博客上看到推荐《Java编程思想》买来之后,发现确实还是很不错的一本书,推荐有一定编程基础的人学习。   了解Java。首先从jdk开始介绍。也是最基础的东西。   JRE(JavaRuntimeEnvironment... 查看详情

androidmvvm-编程思想3(封装基类basemvvmactivity,basemvvmfragment)(代码片段)

...识很了解,可以直接看下一节。目录:AndroidMVVM-编程思想1(入门介绍MVVM,DataBinding,ViewModel,LiveData)AndroidMVVM-编程思想2(入门实战MVVM,DataBinding,ViewModel,LiveData)AndroidMVVM-编程思... 查看详情

java编程思想

Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而且在大型项目开发中也是常用的知识,既有简单的概念理解题(比如i... 查看详情

java中的泛型---java编程思想

...解泛型是学好基础里面中非常重要的。于是,我对《Java编程思想》这本书中泛型章节进行了研读。可惜遗憾的是,自己没有太多的经验,有些东西看了几次也是有点懵。只能以后有机会,再进行学习了。但是自己也理解了挺多... 查看详情

[读书笔记]java编程思想(代码片段)

目录第1章对象导论第2章一切都是对象第3章操作符第4章控制执行流程第5章初始化与清理第6章访问权限控制第7章复用类第8章多态第9章接口第10章内部类第11章持有对象第12章通过异常处理错误第13章字符串第14章类型信息第15章泛... 查看详情