精华内容
下载资源
问答
  • vue提供了mixins、extends配置项,最近使用中发现很好用。 混合mixins和继承extends 看看官方文档怎么写的,其实两个都可以理解为继承,mixins接收对象数组(可理解为多继承),extends接收的是对象或函数(可理解为...
  • Class 可以通过extends关键字实现继承 这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。如下: class Test{} class ColorTest extends Test{}  上面代码定义了一个ColorTest类,该类通过extends关键字,...
  • 主要介绍了 Java基础之extends用法详解及简单实例的相关资料,需要的朋友可以参考下
  • extends T>的声明,是什么意思呢?<? super T>表示包括T在内的任何T的父类,<? extends T>表示包括T在内的任何T的子类,下面我们详细分析一下两种通配符具体的区别。  extends  List<? extends Number...
  • var Cat = new Class({ Extends: Animal, initialize: function(name, age){ this.parent(age); // calls initalize method of Animal class this.name = name; } }); var myCat = new Cat(‘Micia’, 2
  • gulp-clean-ts-extends 移植到 gulp!。 如果您首先编译所有 TypeScript 源代码,然后将它们连接到一个文件中,您可能会得到很多 __extends 声明。 此插件保留第一个并删除所有后续插件。 仅适用于非缩小的 ...
  • 主要介绍了详解JAVA中implement和extends的区别的相关资料,extends是继承接口,implement是一个类实现一个接口的关键字,需要的朋友可以参考下
  • 主要介绍了Vue Extends 扩展选项用法,结合完整实例形式分析了Vue Extends 扩展选项相关使用技巧与操作注意事项,需要的朋友可以参考下
  • 主要介绍了Java泛型extends及super区别实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 本篇文章给大家详细讲述了Java继承extends与super关键字的相关知识点,需要的朋友们可以参考学习下。
  • 今天小编就为大家分享一篇关于Java中extends一定是代表继承吗?,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
  • Java中extends类的继承

    2016-06-07 12:16:26
    Java中extends类的继承
  • 主要介绍了Java泛型extends关键字设置边界的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • vue-template-extends 装载程序允许您通过覆盖插槽来扩展SFC的模板。 安装 通过运行以下命令安装加载程序: npm npm i --save vue-template-extends 添加加载器中的WebPack配置module.rules : // webpack....
  • java中extends与implements的区别浅谈,需要的朋友可以参考一下
  • SSH整合(其中dao用extends HibernateDaoSupport方式)总结【图解】
  • 经常发现有List、Set<? extends T>的声明,是什么意思呢?表示包括T在内的任何T的父类,<? extends T>表示包括T在内的任何T的子类,下面我们详细分析一下两种通配符具体的区别。
  • 主要介绍了Vue 中 extend 、component 、mixins 、extends 的区别,非常不错,具有参考借鉴价值,需要的朋友可以参考下
  • JAVA的extends用法

    千次阅读 2021-02-25 18:50:41
    在Java中,通过关键字extends继承一个已有的类,被继承的类称为父类(超类,基类),新的类称为子类(派生类)。在Java中不允许多继承。(1)继承classAnimal{voideat(){System.out.println("Animaleat");}voidsleep(){...

    理解继承是理解面向对象程序设计的关键。在Java中,通过关键字extends继承一个已有的类,被继承的类称为父类(超类,基类),新的类称为子类(派生类)。在Java中不允许多继承。

    (1)继承

    class Animal{

    void eat(){

    System.out.println("Animal eat");

    }

    void sleep(){

    System.out.println("Animal sleep");

    }

    void breathe(){

    System.out.println("Animal breathe");

    }

    }

    class Fish extends Animal{

    }

    public class TestNew {

    public static void main(String[] args) {

    // TODO Auto-generated method stub

    Animal an = new Animal();

    Fish fn = new Fish();

    an.breathe();

    fn.breathe();

    }

    }

    在eclipse执行得:

    Animal breathe!

    Animal breathe!

    .java文件中的每个类都会在文件夹bin下生成一个对应的.class文件。执行结果说明派生类继承了父类的所有方法。

    (2)覆盖

    class Animal{

    void eat(){

    System.out.println("Animal eat");

    }

    void sleep(){

    System.out.println("Animal sleep");

    }

    void breathe(){

    System.out.println("Animal breathe");

    }

    }

    class Fish extends Animal{

    void breathe(){

    System.out.println("Fish breathe");

    }

    }

    public class TestNew {

    public static void main(String[] args) {

    // TODO Auto-generated method stub

    Animal an = new Animal();

    Fish fn = new Fish();

    an.breathe();

    fn.breathe();

    }

    }

    执行结果:

    Animal breathe

    Fish breathe

    在子类中定义一个与父类同名,返回类型,参数类型均相同的一个方法,称为方法的覆盖。方法的覆盖发生在子类与父类之间。另外,可用super提供对父类的访问。

    参考原文:http://blog.csdn.net/zhandoushi1982/article/details/5441126

    Java 中extends与implements使用方法

    Java 中extends与implements使用方法 标签: javaclassinterfacestring语言c 2011-04-14 14:57 33314人阅读 评论(7) 收藏 举报 分 ...

    四种Java线程池用法解析

    本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 http://www.jb51.net/article/81843.htm 1.new Thread的弊端 执行一个异步任务你还只是如下 ...

    设计模式 - 观察者模式&lpar;Observer Pattern&rpar; Java内置 用法

    观察者模式(Observer Pattern) Java内置 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26601659 ...

    JAVA的continue用法

    JAVA的continue用法: public class test{ public static void main(String [] args){  for(int i=0;i<=10;i ...

    Java Spring AOP用法

    Java Spring AOP用法 Spring AOP Java web 环境搭建 Java web 项目搭建 Java Spring IOC用法 spring提供了两个核心功能,一个是IoC(控制 ...

    Java Spring IOC用法

    Java Spring IOC用法 Spring IoC 在前两篇文章中,我们讲了java web环境搭建 和 java web项目搭建,现在看下spring ioc在java中的运用,开发工具为In ...

    JAVA中extends 与implements区别

    JAVA中extends 与implements有啥区别?1. 在类的声明中,通过关键字extends来创建一个类的子类.一个类通过关键字implements声明自己使用一个或者多个接口.extend ...

    JAVA中ArrayList用法

    JAVA中ArrayList用法 2011-07-20 15:02:03|  分类: 计算机专业 |  标签:java  arraylist用法  |举报|字号 订阅     Java学习过程中做题时 ...

    java 关于extends 和implement的区别

    在java中extends用于继承父类,只要父类不是声明为final或者为abstract类就可以,但是java不支持多重继承.可以使用接口实现多重继承implements,继承只能继承一个类,但im ...

    随机推荐

    Python-属性&lpar;property&rpar;

    在2.6版本中,添加了一种新的类成员函数的访问方式--property. 原型 class property([fget[, fset[, fdel[, doc]]]]) fget:获取属性 fset ...

    ios - cordova 简介

    Cordova 是一个可以让 JS 与原生代码(包括 Android 的 java,iOS 的 Objective-C 等)互相通信的一个库,并且提供了一系列的插件类,比如 JS 直接操作本地数据库的 ...

    centos could not retrieve mirrorlist

    centos could not retrieve mirrorlist >>>>>>>>>>>>>>>&gt ...

    用PHP添加购物商品

    &lbrack;ZZ&rsqb; 如何在多版本anaconda python环境下转换spyder

    https://www.zhihu.com/people/alexwhu/answers 使用anaconda的话,可以参考以下步骤: 1.打开anaconda navigator,选择左侧的环境菜单 ...

    How to Read a Paper

    How to Read a Paper 原文: https://www.yuque.com/lart/papers/yrkv5u 题目:How to Read a Paper 作者:S. Keshav ...

    NModbus类库使用

    通过串口进行通信 : 1.将 NMobus 类库导入工程中,添加引用.命名空间.工程属性必须配置 为 .NET 4.0. 2.创建 SerialPort 类的一个实例,配置参数,打开串口,如: pub ...

    word&lowbar;宏示例

    参考:https://jingyan.baidu.com/article/870c6fc3326588b03fe4beeb.html 内容自适应 Application.Browser.Target ...

    zookeeper 入门知识

    作为开启分布式架构的基石,除了必会还有的选么 自己的一些理解,有错误的话请一定要给予指正! 一.是什么? 分布式数据一致性的解决方案. 二.有什么用 数据的发布/订阅(配置中心)  . 负载均衡(du ...

    【Linux 网络编程】TCP网络编程中connect&lpar;&rpar;、listen&lpar;&rpar;和accept&lpar;&rpar;三者之间的关系

    基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: connect()函数:对于客户端的 connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三 ...

    展开全文
  • java中的继承 (extends) 详解

    万次阅读 多人点赞 2019-08-18 10:45:21
    继承(extends) 1. 父类与子类 父类也叫基类、超类 子类也叫派生类 在继承的而关系中,“子类就是一个父类“。也就是说,子类可以被当做父类来看待。例如父类是员工,子类是老师,那么我们可以说**”...

    继承(extends)

    1. 父类与子类

    • 父类也叫基类、超类

    • 子类也叫派生类

    • 在继承的而关系中,“子类就是一个父类“。也就是说,子类可以被当做父类来看待。例如父类是员工,子类是老师,那么我们可以说**”老师就是一个员工“**。

    2. 继承的格式

    2.1 定义父类的格式:(一个普通的类定义)

    public class 父类名称{
        //.....
    }
    

    2.2 定义子类的格式

    public class 子类名称 extends 父类名称{
        //.....
    }
    

    2.3 代码演示(老师类继承员工类)

    • 2.3.1 Employee类
    public class Employee(){
        public void method(){
            System.out.println("方法执行")
        }
    }
    
    • 2.3.2 Teacher类,继承自Employee类
    public class Teacher extends Employee{
    	//我们先不在里面添加任何东西
    }
    
    
    • 2.3.3 在main中,创建一个Teacher类的对象
    public class Main {
    
        public static void main(String[] args) {
    	    Teacher one = new Teacher();
            //Teacher类继承了Empolyee类的方法
    	    one.method();
        }
    }
    /*输出结果:
        执行方法
     */
    

    2.3.4 小结论

    Teacher类继承了Employee类,也就继承了它的 public void method() 方法,达到了代码复用的效果,当父类有我们子类需要用的方法时,我们就不用再去重新打一次,直接可以拿来用。

    3. 继承中成员变量的访问特点

    3.1 成员变量之间的访问 (变量不重名的情况)

    • 3.1.1 先创立一个父类Fu
    public class Fu {
        public int numFu = 10;  //关键字为public,可以直接通过(对象.变量名)访问,方便说明问题
    }
    
    • 3.1.2 再创立一个子类Zi
    public class Zi extends Fu{
        public int numZi = 20;
    }
    
    • 3.1.3 在main中分别建立父类和子类的对象
    public class Demo02ExtendsField {
        public static void main(String[] args) {
            //创建父类对象
            Fu fu = new Fu();
            //父类只能找到自己的成员numFu,并没有找到子类的成员numZi
            System.out.println(fu.numFu);
    
            //创立一个子类对象
            Zi zi = new Zi();
            //子类对象既可以打印父类的成员numFu,也可以打印自己的成员numZi
            //还是那句"先人不知道后人的事情,而后人知道先人的事情"
            System.out.println(zi.numFu);
            System.out.println(zi.numZi);
        }
    }
    

    3.2 成员变量之间的访问 (变量重名的情况)

    有两种情况:

    1. 直接通过对象访问成员变量:

      等号左边是谁,就优先用谁,没有则向上找

    2. 间接通过成员方法访问成员变量

      该方法属于谁,就优先用谁,没有则向上找

    • 假设现在父类 Fu 和子类 Zi 都有一个变量名叫num

    • Fu 类

      public class Fu {
          public int num = 10;
      
          public void methodFu(){
              //这里打印的num,一定是本类的,不会再往下找子类的
              System.out.println(num);
          }
      }
      
    • Zi类

      public class Zi extends Fu{
          public int num = 20;
      
          public void methodZi(){
              //这里打印的num,如果本类有,就优先打印本类的,如果没有再往上找
              System.out.println(num);
          }
      }
      

    第一种情况:直接通过对象访问成员变量

    等号左边是谁,就优先用谁,没有则向上找。Fu fu = new Zi();等号的左边是父类

    public class Demo02ExtendsField {
        public static void main(String[] args) {
         // Zi zi = new Fu(); 不能通过父类来构造子类,先人(父类)根本不知道后人(子类)长什么样子
            Fu fu = new Zi(); //可以通过子类来构造父类,这时等号左边是父类
            System.out.println(fu.num);  //10,打印的是父类的num
        }
    }
    

    第二种情况:间接通过成员方法访问成员变量

    public class Demo02ExtendsField {
        public static void main(String[] args) {
    
            Fu fu = new Fu();
            Zi zi = new Zi();
    
            //打印的是父类的num,因为该类没有继承其它类,他自己肯定有一个num,才能写出这个方法
            fu.methodFu();  //父类的num 10,补充:没有fu.methodZi(), 先人不知道后人的方法
    
            //如果子类有一个num,那就优先打印本类的,没有的话再往父类那里找
            zi.methodZi();  //子类的num 20
    
            //重点!子类用的是父类的方法打印num,这就要看这个方法属于谁,是谁定义的这个方法
            //因为methodFu()这个方法是属于父类的,打印的当然就是父类的num
            zi.methodFu();  //父类的num 10
        }
    }
    

    4. 区分子类方法中的重名

    假如有好多个num,父类有一个,子类有两个,怎么才能正确地打印想要的那个num呢?

    • 4.1 父类

      public class Fu {
          public int num = 10;
      }
      
    • 4.2 子类

      public class Zi extends Fu {
          public int num = 20;
      
          public void methodZi(){
              int num = 30;
              System.out.println(num);      //30, 局部变量
              System.out.println(this.num); //20, 本类的成员变量
              System.out.println(super.num);//10, 父类的成员变量
          }
      }
      
    • 4.3 看看子类方法 methodZi() 能不能正确区分三个num

      public class Demo03Main {
          public static void main(String[] args) {
              Zi zi = new Zi();
              zi.methodZi();  //30, 20, 10
          }
      }
      
    • 4.4 总结:要想正确地打印想要的num,可以这样打

      • 局部变量,上面的那个num = 30,就可以直接写
      • 本类的成员变量,上面的num = 20, 用this.成员变量名
      • 父类的成员变量,上面的num = 10, 用super.成员变量名

    5. 继承中成员方法重名的问题

    假如子类和父类都有一个方法叫 method() , 那怎么知道用的是哪一个呢?

    • 5.1 父类

      public class Fu {
          public void method(){
              System.out.println("父类重名方法执行");
          }
      }
      
    • 5.2 子类

      public class Zi extends Fu {
          public void method(){
              System.out.println("子类重名方法执行");
          }
      }
      
    • 5.3 在main中调用 method() 方法

      public class Demo04Main {
          public static void main(String[] args) {
              Fu fu1 = new Fu();
              Fu fu2 = new Zi(); //通过子类来构造fu2
              Zi zi = new Zi();
      
              fu1.method(); //父类重名方法执行, 用的是父类方法
              fu2.method(); //子类重名方法执行,用的是子类方法
              zi.method();  //子类重名方法执行, 用的是子类方法
          }
      }
      
    • 结论 :

    1. 创建的对象是谁,用谁的类来构造对象的,就优先用谁,如果没有就向上找。比如Fu fu2 = new Zi();,fu2是用子类来构造的,那fu2.method()就是用的子类的方法
    2. 注意!无论是成员变量还是成员方法,如果没有都是向上找父类,绝对不会向下找子类的。

    6. 继承方法中的覆盖重写

    5. 继承中成员方法重名的问题,我们可以引出重写(Override)的概念

    重写:在继承关系中,方法的名称一样,参数列表也一样

    • 6.1 重写 (Override) 和 重载 (Overload) 的区别

      重写:方法的名称一样,参数列表【也一样】。也叫覆盖、覆写

      重载:方法的名称一样,参数列表【不一样】。

    • 6.2 覆盖重写的注意事项 (了解)

      • 6.2.1 必须保证父子类之间方法的名称相同,参数列表也相同,否则无法进行覆盖重写

      • 6.2.2 注解:@Override,这个注解写在方法的前面,用来检验是不是有效的覆盖重写,例如当方法名写错了,@Override底下就会出现红色的波浪线,提示你这不是有效的覆盖重写。

        public class Zi extends Fu {
            @Override
            public void method(){
                System.out.println("子类重名方法执行");
            }
        }
        

        这个注解可写可不写,但是强烈推荐把它写上去。

      • 6.2.3 子类方法的返回值必须【小于等于】父类方法的返回值范围。java.lang.Object是所有类的公共最高父类(祖宗类),每个类都默认继承了它,例如String类就是Object的子类。下面代码会报错,是因为返回值的范围问题

        • 6.2.3.1 父类

          public class Fu {
              public String method(){
                  System.out.println("父类重名方法执行");
              }
          }
          
        • 6.2.3.2 子类

          public class Zi extends Fu {
              @Override
              public Object method(){  //范围:Object > String 报错
                  System.out.println("子类重名方法执行");
              }
          }
          
      • 6.2.4 子类方法的权限必须【大于等于】父类方法的权限修饰符。权限的排名:public > protected > (default) > private。备注:(default)不是关键字default,而是什么都不写,留空,例如:

        public class Fu{
            int num; //num的访问权限是default
        }
        

        下面的代码会因为重写方法的权限问题而报错:

        • 6.2.4.1 父类

          public class Fu {
              public void method(){
                  System.out.println("父类重名方法执行");
              }
          }
          
        • 6.2.4.2 子类

          public class Zi extends Fu {
              @Override
              protected void method(){  //protected < public 报错
                  System.out.println("子类重名方法执行");
              }
          }
          
          
    • 6.3 覆盖重写实战演练

      假如旧手机的功能有打电话、发短信、来电显示(显示号码)

      新手机的功能有来电显示、发短信、来电显示(显示号码、显示头像、显示姓名)

      可见新旧手机的打电话和发短信功能是一样的,但是新手机的来电显示功能比旧手机多了显示头像、显示姓名。

      我们可以把旧手机当做父类,把新手机当做子类,新手机只需要重写旧手机的来电显示功能即可

      • 6.3.1 旧手机是父类,名为Oldphone类

        public class Oldphone {  
            //打电话功能
            public void call(){
                System.out.println("打电话");
            }
            //发短信功能
            public void send(){
                System.out.println("发短信");
            }
            //来电显示功能
            public void show(){
                System.out.println("显示号码");
            }
        }
        
      • 6.3.2 新手机是子类,名为Newphone类

        public class Newphone extends Oldphone{
        
            @Override
            public void show() {
                super.show();  //不要修改原来的代码,直接通过super调用它,后面再添加新的内容
                System.out.println("显示头像");
                System.out.println("显示姓名");
            }
        }
        
      • 6.3.3 在main中实验一下

        public class Demo05Main {
            public static void main(String[] args) {
                Newphone newphone = new Newphone();
                newphone.call();
                newphone.send();
                newphone.show();
            }
        }
        /*输出结果:
            打电话
            发短信
            显示号码
            显示头像
            显示姓名
         */
        

    7. 继承中构造方法的访问特点

    7.1 概述

    子类的构造方法启动时,一定会先跑去启动父类的构造方法,等父类的构造方法执行完后,再去执行子类(本类)的构造方法。

    7.2 代码说明一下7.1

    • 7.2.1 父类(只有无参构造方法)

      public class Fu {
          //父类的无参构造方法
          public Fu(){
              System.out.println("父类构造方法执行");
          }
      }
      
      
    • 7.2.2 子类

      public class Zi extends Fu {
          //子类的无参构造方法
          public Zi(){
              System.out.println("子类构造方法执行");
          }
      }
      
      
    • 7.2.3 在main中构造一个子类

      public class Demo06Main {
          public static void main(String[] args) {
              Zi zi = new Zi();
          }
      }
      
      /*输出结果:
          父类构造方法执行
          子类构造方法执行
       */
      
    • 7.2.4 小总结

      其实子类的构造方法中隐含了super()调用,如果子类的构造方法没有写super(),编译器会帮我们默认加上去。子类就变成

      public class Zi extends Fu {
          //子类的无参构造方法
          public Zi(){
              super();  //注意!这句必须写在第一行的位置,如果父类构造函数有参数,就是super(参数),有                   参数的调用,必须要自己写上去,不然会默认调用无参构造
              System.out.println("子类构造方法执行");
          }
      }
      

    8. super关键字的三种用法总结

    8.1 用法1

    在子类的成员方法中,访问父类的成员变量,比如:

    • 8.1.1 父类

      public class Fu {
          public int num = 10;
      }
      
    • 8.1.2 子类

      public class Zi extends Fu {
          public int num = 20;
      
          public void methodZi(){
             // System.out.println(num);  这样打印的一定是本类的num
              System.out.println(super.num); //打印的是父类的num
          }
      }
      

    8.2 用法2

    在子类的成员方法中,访问父类的成员方法,比如:

    • 8.2.1 父类

      public class Fu {
          public void methodFu(){
              System.out.println("父类的成员方法执行");
          }
      }
      
      
    • 8.2.2 子类

      public class Zi extends Fu{
          public void methodZi(){
              super.methodFu(); //访问父类的methodFu()方法
              System.out.println("子类的成员方法执行");
          }
      }
      
    • 在main中执行子类的方法

      public class Demo07Main {
          public static void main(String[] args) {
              Zi zi = new Zi();
              zi.methodZi();
          }
      }
      /*输出结果:
          父类的成员方法执行
          子类的成员方法执行
       */
      

    8.3 用法3

    在子类的构造方法中,访问父类的构造方法。就在 7. 继承中构造方法的访问特点 中,请自行查阅。

    9. this关键字的三种用法

    9.1 概述

    9.1.1 在本类的成员方法中,访问本类的成员变量

    9.1.2 在本类的成员方法中,访问本类的另一个成员方法

    9.1.3 在本类的构造方法中,访问本类的另一个构造方法

    9.2 代码说明一下

    public class Zi extends Fu {
        private int num = 10;
    
        public Zi(){
            this(123);  //9.1.3 在本类的无参构造中调用有参构造
        }
    
        public Zi(int num){
            this.num = num;
        }
    
        public void methodZi(){
            System.out.println(this.num); //9.1.1 在本类的成员方法中,访问本类的成员变量
        }
    
        public void methodA(){
            System.out.println("A方法");
        }
    
        public void methodB(){
            this.methodA();  //9.1.2 在本类的成员方法中,访问本类的另一个成员方法
            System.out.println("B方法"); 
    
    

    9.3 注意事项

    • 在构造方法中调用this,那这个this调用必须是该函数中的第一个语句,也是唯一的一个
    • super和this两种在构造调用中,不能同时使用。两个都要排在第一行,我哪知道该怎么排。

    10. java继承的三个特点

    10.1 java语言是单继承

    一个类的直接父类只能有唯一的一个。

    class A{}
    class B extends A{}  正确写法
    class C{}
    class D extends A,C{} 错误写法,不能同时继承A和C
    

    试想假如class A{}有一个 method() 方法,

    Class C{}也有一个 method() 方法,

    子类D同时继承类A和类C,那当我新建一个D类对象d后,

    对象d想要调用父类的method方法,那它应该用A的 method() 还是C的 method() 呢?这就乱套了!

    在这里插入图片描述

    10.2 java语言是可以多级继承的

    虽然,java语言是单继承的,一个类的直接父类只有一个,类D不能同时继承类A和类C

    但是,可以让类A继承类C之后,类D再继承类A,C就是爷爷,A就是爸爸,D就是儿子

    类D --> 类A --> 类C,这就叫多级继承。
    在这里插入图片描述

    10.3 java语言中,一个父类可以有多个子类

    这就好比二胎政策,一个爸爸可以有多个儿子

    在这里插入图片描述

    展开全文
  • flume-ng extends source jar flume-ng-extends-source-0.8.0.jar
  • Vue mixins 和 extends 使用详解

    千次阅读 2019-09-21 11:41:13
    Vue 提供了mixins 和 extends 来在组件里直接合并一些特定的属性。 用法如下: var mixin = { created: function () { console.log(1) } } var vm = new Vue({ created: function () { console.log(2) }, mixins: ...

    Vue 提供了mixins 和 extends 来在组件里直接合并一些特定的属性。
    用法如下:

    var mixin = {
      created: function () { console.log(1) }
    }
    var vm = new Vue({
      created: function () { console.log(2) },
      mixins: [mixin]
    })
    // => 1
    // => 2
    
    var CompA = { ... }
    var CompB = {
      extends: CompA,
      ...
    }
    

    以上两者的用法来自vue官方案例,最大的区别就是extends传入的是一个组件属性对象,mixins传入的是n个组件属性对象组成的数组。

    这里我们会有一个疑问,当我们注入想动的组件属性到当前组件,合并的机制是什么?是组件覆盖mixins或者extends 还是后者覆盖前者,还是两者共存。这是本文说明的重点。我们看代码:

    mergeField是合并的核心代码,他会根据属性名,在合并方法合集strats里去找一个特定属性key的合并方法。调用合并方法进行合并操作。然后把合并的结果返回给vm实例。

    // vue实例在初始化的时候会调用该合并方法
     vm.$options = mergeOptions(
          resolveConstructorOptions(vm.constructor),
          options || {},
          vm
        );
    function mergeOptions (
        parent,
        child,
        vm
      ) {
        {
          checkComponents(child);
        }
    
        if (typeof child === 'function') {
          child = child.options;
        }
    
        normalizeProps(child, vm);
        normalizeInject(child, vm);
        normalizeDirectives(child);
        if (!child._base) {
         // 初始先合并extends和mixins的属性到 _base 对象上
          if (child.extends) {
            parent = mergeOptions(parent, child.extends, vm); 
          }
          if (child.mixins) {
            for (var i = 0, l = child.mixins.length; i < l; i++) {
              parent = mergeOptions(parent, child.mixins[i], vm);
            }
          }
        }
    
        var options = {};
        var key;
        // 先处理_base 和mixins 或者extends 混合后的内容
        for (key in parent) { 
          mergeField(key);
        }
        // 再将组件上原来的属性内容和上面的进行混合
        for (key in child) {
          if (!hasOwn(parent, key)) {
            mergeField(key);
          }
        }
        function mergeField (key) {
           // 通过属性名寻找对应的合并策略
          var strat = strats[key] || defaultStrat;
          options[key] = strat(parent[key], child[key], vm, key);
        }
        return options
      }
    

    下面将展示针对不同属性的合并策略对应的源代码:

    // 这个是属性里data和组件里data的合并方式

    strats.data = function (
        parentVal,
        childVal,
        vm
      ) {
        if (!vm) {
          if (childVal && typeof childVal !== 'function') {
            warn(
              'The "data" option should be a function ' +
              'that returns a per-instance value in component ' +
              'definitions.',
              vm
            );
    
            return parentVal
          }
          return mergeDataOrFn(parentVal, childVal)
        }
    
        return mergeDataOrFn(parentVal, childVal, vm)
      };
    

    这个是属性里 props 、methods、inject、computed的合并方法

    strats.props =
    strats.methods =
    strats.inject =
    strats.computed = function (
      parentVal,
      childVal,
      vm,
      key
    ) {
      if (childVal && "development" !== 'production') {
        assertObjectType(key, childVal, vm);
      }
      if (!parentVal) { return childVal }
      var ret = Object.create(null);
      extend(ret, parentVal);
      // childVal 覆盖 ret里的parentVal
      if (childVal) { extend(ret, childVal); }
      return ret
    };
    

    这个是对el和propsData的覆盖方法

    strats.el = strats.propsData = function (parent, child, vm, key) {
          if (!vm) {
            warn(
              "option \"" + key + "\" can only be used during instance " +
              'creation with the `new` keyword.'
            );
          }
          return defaultStrat(parent, child)
        };
    

    这是对watch属性的合并方法

    strats.watch = function (
        parentVal,
        childVal,
        vm,
        key
      ) {
        // work around Firefox's Object.prototype.watch...
        if (parentVal === nativeWatch) { parentVal = undefined; }
        if (childVal === nativeWatch) { childVal = undefined; }
        /* istanbul ignore if */
        if (!childVal) { return Object.create(parentVal || null) }
        {
          assertObjectType(key, childVal, vm);
        }
        if (!parentVal) { return childVal }
        var ret = {};
        extend(ret, parentVal);
        for (var key$1 in childVal) {
          var parent = ret[key$1];
          var child = childVal[key$1];
          if (parent && !Array.isArray(parent)) {
            parent = [parent];
          }
          // 按watch的key合并回掉函数到数组中,供后面顺序执行
          ret[key$1] = parent
            ? parent.concat(child)
            : Array.isArray(child) ? child : [child];
        }
        return ret
      };
    

    这是对provide的合并方法

    strats.provide = mergeDataOrFn;
    

    生命周期属性的覆盖方法

      var LIFECYCLE_HOOKS = [
        'beforeCreate',
        'created',
        'beforeMount',
        'mounted',
        'beforeUpdate',
        'updated',
        'beforeDestroy',
        'destroyed',
        'activated',
        'deactivated',
        'errorCaptured',
        'serverPrefetch'
      ];
    LIFECYCLE_HOOKS.forEach(function (hook) {
        strats[hook] = mergeHook;
      });
     
     function mergeHook (
        parentVal,
        childVal
      ) {
        var res = childVal
          ? parentVal
            ? parentVal.concat(childVal)
            : Array.isArray(childVal)
              ? childVal
              : [childVal]
          : parentVal;
        return res
          ? dedupeHooks(res)
          : res
      }
    

    属性中 三种vue内部类型(组件,指令,过滤器)的合并方法

     var ASSET_TYPES = [
        'component',
        'directive',
        'filter'
      ];
    ASSET_TYPES.forEach(function (type) {
        strats[type + 's'] = mergeAssets;
      });
    

    上面的多种策略对应的最终合并函数如下:

     // 合并顺序是
     // to里加入只有from中特有的属性,to和from里都有的属性,保留to里的,最后返回to
      function mergeData (to, from) {
        if (!from) { return to }
        var key, toVal, fromVal;
    
        var keys = hasSymbol
          ? Reflect.ownKeys(from)
          : Object.keys(from);
    
        for (var i = 0; i < keys.length; i++) {
          key = keys[i];
          // in case the object is already observed...
          if (key === '__ob__') { continue }
          toVal = to[key];
          fromVal = from[key];
          if (!hasOwn(to, key)) {
            set(to, key, fromVal);
          } else if (
            toVal !== fromVal &&
            isPlainObject(toVal) &&
            isPlainObject(fromVal)
          ) {
            mergeData(toVal, fromVal);
          }
        }
        return to
      }
    
    // 合并 vue中data或者reject,他们是一个函数,所以合并函数返回值
    function mergeDataOrFn (
        parentVal,
        childVal,
        vm
      ) {
        if (!vm) {
          // in a Vue.extend merge, both should be functions
          if (!childVal) {
            return parentVal
          }
          if (!parentVal) {
            return childVal
          }
          // when parentVal & childVal are both present,
          // we need to return a function that returns the
          // merged result of both functions... no need to
          // check if parentVal is a function here because
          // it has to be a function to pass previous merges.
          return function mergedDataFn () {
            return mergeData(
              typeof childVal === 'function' ? childVal.call(this, this) : childVal,
              typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal
            )
          }
        } else {
          return function mergedInstanceDataFn () {
            // instance merge
            var instanceData = typeof childVal === 'function'
              ? childVal.call(vm, vm)
              : childVal;
            var defaultData = typeof parentVal === 'function'
              ? parentVal.call(vm, vm)
              : parentVal;
            if (instanceData) {
              return mergeData(instanceData, defaultData)
            } else {
              return defaultData
            }
          }
        }
      }
    
    // 默认的合并策略,优先使用childVal,childVal没有才使用parentVal
      var defaultStrat = function (parentVal, childVal) {
        return childVal === undefined
          ? parentVal
          : childVal
      };
    
    
    // to里有的将被_from覆盖,to里没有的form有的,to里将添加。
     function extend (to, _from) {
        for (var key in _from) {
          to[key] = _from[key];
        }
        return to
      }
    

    总结:

    属性名称合并策略对应合并函数
    datamixins/extends 只会将自己有的但是组件上没有内容混合到组件上,重复定义默认使用组件上的
    如果data里的值是对象,将递归内部对象继续按照该策略合并
    mergeDataOrFn,mergeData
    provide同上mergeDataOrFn,mergeData
    propsmixins/extends 只会将自己有的但是组件上没有内容混合到组件上extend
    methods同上extend
    inject同上extend
    computed同上extend
    组件,过滤器,指令属性同上extend
    el同上defaultStrat
    propsData同上defaultStrat
    watch合并watch监控的回掉方法
    执行顺序是先mixins/extends里watch定义的回调,然后是组件的回掉
    strats.watch
    HOOKS 生命周期钩子同一种钩子的回调函数会被合并成数组
    执行顺序是先mixins/extends里定义的钩子函数,然后才是组件里定义的
    mergeHook

    mixins和extends 的合并策略都是按照上面的表格来合并的。

    展开全文
  • Java泛型 extends关键字设置边界

    千次阅读 2019-09-14 22:18:28
    本文主要介绍在泛型定义中的中的占位符如何配合extends关键字使用,形如<T extends Integer>。泛型定义存在于这三种形式中:泛型类、泛型接口、泛型方法。 一般的泛型定义中的,相当于<T extends Object>,而类型...

    本文主要介绍在泛型定义中的< >中的占位符如何配合extends关键字使用,形如<T extends Integer>。泛型定义存在于这三种形式中:泛型类、泛型接口、泛型方法。

    • 一般的泛型定义中的<T>,相当于<T extends Object>,而类型擦除则会将类型参数擦除成T的上界,即Object。则在泛型定义中作为T类型的对象可以调用Object的函数和属性。
    • 使用了extends的泛型定义中的<T extends Integer>,其上界已被明显定义了,此时会将类型参数擦除成Integer。则在泛型定义中作为T类型的对象可以调用Integer的函数和属性。

    接下来本文将以几个示例和具体分析来讲解剩下的知识点。

    类型参数多边界的分析

    此例中的泛型类,类型参数带有多个边界。讲下类的实际意义:Dimension代表物体的方位、HasColor代表物体的颜色、Weight代表物体的重量。

    interface HasColor { java.awt.Color getColor(); }
    
    class Colored<T extends HasColor> {
        T item;
        Colored(T item) { this.item = item; }
        T getItem() { return item; }
        // The bound allows you to call a method:
        java.awt.Color color() { return item.getColor(); }
    }
    
    class Dimension { public int x, y, z; }
    
    // This won't work -- class must be first, then interfaces:
    // class ColoredDimension<T extends HasColor & Dimension> { }
    
    // Multiple bounds:
    class ColoredDimension<T extends Dimension & HasColor> {
        T item;
        ColoredDimension(T item) { this.item = item; }
        T getItem() { return item; }
        java.awt.Color color() { return item.getColor(); }
        int getX() { return item.x; }
        int getY() { return item.y; }
        int getZ() { return item.z; }
    }
    
    interface Weight { int weight(); }
    
    // As with inheritance, you can have only one
    // concrete class but multiple interfaces:
    class Solid<T extends Dimension & HasColor & Weight> {
        T item;
        Solid(T item) { this.item = item; }
        T getItem() { return item; }
        java.awt.Color color() { return item.getColor(); }
        int getX() { return item.x; }
        int getY() { return item.y; }
        int getZ() { return item.z; }
        int weight() { return item.weight(); }
    }
    
    class Bounded extends Dimension implements HasColor, Weight {
        public java.awt.Color getColor() { return null; }
        public int weight() { return 0; }
    }
    
    public class BasicBounds {
        public static void main(String[] args) {
            Solid<Bounded> solid = new Solid<Bounded>(new Bounded());
            solid.color();
            solid.getY();
            solid.weight();
        }
    } ///:~
    
    • class Colored<T extends HasColor>这个泛型类的泛型定义中,要求了类型参数T的边界为HasColor,正因如此,在函数java.awt.Color color() { return item.getColor(); }中便可以通过一个T类型的变量item来调用属于HasColor的方法。
    • class ColoredDimension<T extends HasColor & Dimension> { },此时定义了边界同时为HasColor & Dimension,但是由于编译器要求占位符后的extends后第一个必须是类,之后的必须是接口(这就和正常的类的继承规则一样),所以此句通不过编译。而class ColoredDimension<T extends Dimension & HasColor>给出了正确的定义,即第一个必须是类,之后的必须是接口。
    • class ColoredDimension<T extends Dimension & HasColor>的类定义中,因为T的边界是HasColor & Dimension,所以在类定义中,既可以获取Dimension的属性,也可以调用HasColor的方法。
    • class Solid<T extends Dimension & HasColor & Weight>的类定义中,extends后第一个是类,之后的都是接口,符合刚才讲的规则。同理,也可以从这些边界中,获取属性,调用方法。
    • class Bounded extends Dimension implements HasColor, Weight这个类将在生成泛型类对象,用来指定具体类型为Bounded。因为class Solid<T extends Dimension & HasColor & Weight>的类型参数T的要求是extends Dimension & HasColor & Weight,所以指定具体类型为new Solid<Bounded>,是可以的。因为类定义中构造器的声明为Solid(T item),且具体类型为new Solid<Bounded>中指定的Bounded,所以要求构造器的实参为Bounded或者Bounded的子类。
    class derivedBounded extends Bounded {}
    
    class Bounded1 extends Dimension implements HasColor, Weight {
        public java.awt.Color getColor() { return null; }
        public int weight() { return 0; }
    }
    
    public class BasicBounds {
        public static void main(String[] args) {
            //Solid<Bounded> solid = new Solid<Integer>(new derivedBounded());//给定的具体类型不符合边界
            Solid<Bounded> solid1 = new Solid<Bounded>(new derivedBounded());//可以传递具体类型Bounded的子类
            //Solid<Bounded> solid2 = new Solid<Bounded>(new Bounded1());//编译报错,因为泛型的静态类型检查
            solid1.color();
            solid1.getY();
            solid1.weight();
        }
    } ///:~
    
    • 根据上一条,那么new Solid<Integer>(new Bounded())这里指定的具体类型,由于和泛型类定义的T类型参数的要求extends Dimension & HasColor & Weight不相符,所以编译会报错;给构造器传值时,实参可以是Bounded的子类;一个同样继承了相同边界的类Bounded1 ,不能传递给构造器,因为类型已经被指定为Bounded了。

    但是类型参数有多个边界时,java内部即java字节码到底是怎么处理的呢:

      public static void main(java.lang.String[]);
        Code:
           0: new           #2                  // class Solid
           3: dup
           4: new           #3                  // class Bounded
           7: dup
           8: invokespecial #4                  // Method Bounded."<init>":()V
          11: invokespecial #5                  // Method Solid."<init>":(LDimension;)V
          14: astore_1
    

    Method Solid."<init>":(LDimension;)V可以看到,给Solid的构造器传递参数时,编译器认为这个形参是个Dimension,这就是编译器处理多个边界的方法,永远处理为第一个边界,即类型擦除为第一个边界。但剩下的两个边界怎么办呢,这里都被处理第一个边界了,我们再去看一下Solid.class的反编译代码就能找到答案:

    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    
    import java.awt.Color;
    
    class Solid<T extends Dimension & HasColor & Weight> {
        T item;
    
        Solid(T item) {
            this.item = item;
        }
    
        T getItem() {
            return this.item;
        }
    
        Color color() {
            return ((HasColor)this.item).getColor();//类型转换为其他边界,再调用方法
        }
    
        int getX() {
            return this.item.x;
        }
    
        int getY() {
            return this.item.y;
        }
    
        int getZ() {
            return this.item.z;
        }
    
        int weight() {
            return ((Weight)this.item).weight();//类型转换为其他边界,再调用方法
        }
    }
    

    当调用的方法不属于第一个边界时,就进行类型转换处理为其他边界就行,反正T肯定是符合extends Dimension & HasColor & Weight的。

    继承有边界要求的泛型类

    通过观察上例可知,Colored、ColoredDimension、Solid这三个类在持有对象的方面有冗余的地方:都有同一个成员变量、同一个构造器、同一个get函数。而类型参数上,边界也是依次叠加的。同样,对于这些边界所带来的属性和方法,也是冗余的。
    所以下例对其进行了修改,通过继承来消除冗余,注意,下面继承的泛型类对类型参数是有边界要求的:

    //HoldItem对边界T没有要求
    class HoldItem<T> {
        T item;
        HoldItem(T item) { this.item = item; }
        T getItem() { return item; }
    }
    //Colored2对边界T有HasColor的要求
    class Colored2<T extends HasColor> extends HoldItem<T> {
        Colored2(T item) { super(item); }
        java.awt.Color color() { return item.getColor(); }
    }
    //ColoredDimension2对边界T有Dimension & HasColor的要求
    class ColoredDimension2<T extends Dimension & HasColor>
            extends Colored2<T> {
        ColoredDimension2(T item) {  super(item); }
        int getX() { return item.x; }
        int getY() { return item.y; }
        int getZ() { return item.z; }
    }
    //Solid2对边界T有Dimension & HasColor & Weight的要求,不过没有类继承它了
    class Solid2<T extends Dimension & HasColor & Weight>
            extends ColoredDimension2<T> {
        Solid2(T item) {  super(item); }
        int weight() { return item.weight(); }
    }
    
    public class InheritBounds {
        public static void main(String[] args) {
            Solid2<Bounded> solid2 =
                    new Solid2<Bounded>(new Bounded());
            solid2.color();
            solid2.getY();
            solid2.weight();
        }
    } ///:~
    
    • HoldItem这个泛型类通过类型参数T把成员变量、构造器、get函数都定义好了,之后的类通过继承它就可以获得这些属性和方法。
    • Colored2泛型类继承了HoldItem,获得了后者的属性和方法从而减少了冗余。同时,class Colored2<T extends HasColor>属于“定义泛型类”,extends HoldItem<T>属于“使用泛型类”,使用泛型类需要指定具体类型,现在确定具体类型的任务延后到了<T extends HasColor>的确认。再从边界是否符合的情况分析,HoldItem的要求是<T>属于无边界,<T extends HasColor>这样的边界定义属于HasColor边界,从范围上说<T extends HasColor>是小于等于<T>的,这样是可以的。由于T添加了HasColor边界,所以可以调用item.getColor()方法了。
    • ColoredDimension2泛型类继承了Colored2。从边界是否符合的情况分析,Colored2对T的边界要求是<T extends HasColor>,而ColoredDimension2定义中的T的边界是<T extends Dimension & HasColor><T extends Dimension & HasColor>小于等于<T extends HasColor>,符合要求。换句话说,ColoredDimension2定义中的T的边界必须比Colored2的边界要求一致,或者范围更小。
    • Solid2泛型类继承了ColoredDimension2。从边界是否符合的情况分析,<T extends Dimension & HasColor & Weight>小于等于ColoredDimension2的边界要求<T extends Dimension & HasColor>,符合要求。

    总结一下:

    • 当一个泛型类继承另一个泛型类时(前者属于“定义泛型类”,后者属于“使用泛型类”),且使用了同一个类型参数时,定义泛型类的类型参数边界定义一定要小于等于使用的那个泛型类的边界要求。

    泛型方法中的边界定义

    泛型方法中对类型参数的边界定义,同样也得符合使用的泛型类的边界要求。此例中,泛型类同样继承别的泛型类,分析同上不赘述。讲下类的实际意义:一系列接口代表了超能力、一系列类代表了超级英雄,它们拥有一个超能力的成员变量。

    import java.util.*;
    
    interface SuperPower {}
    interface XRayVision extends SuperPower {
        void seeThroughWalls();
    }
    interface SuperHearing extends SuperPower {
        void hearSubtleNoises();
    }
    interface SuperSmell extends SuperPower {
        void trackBySmell();
    }
    
    class SuperHero<POWER extends SuperPower> {
        POWER power;
        SuperHero(POWER power) { this.power = power; }
        POWER getPower() { return power; }
    }
    
    class SuperSleuth<POWER extends XRayVision> extends SuperHero<POWER> {
        SuperSleuth(POWER power) { super(power); }
        void see() { power.seeThroughWalls(); }
    }
    
    class CanineHero<POWER extends SuperHearing & SuperSmell> extends SuperHero<POWER> {
        CanineHero(POWER power) { super(power); }
        void hear() { power.hearSubtleNoises(); }
        void smell() { power.trackBySmell(); }
    }
    
    class SuperHearSmell implements SuperHearing, SuperSmell {
        public void hearSubtleNoises() {}
        public void trackBySmell() {}
    }
    
    class DogBoy extends CanineHero<SuperHearSmell> {
        DogBoy() { super(new SuperHearSmell()); }
    }
    
    public class EpicBattle {
        // Bounds in generic methods:
        static <POWER extends SuperHearing>
        void useSuperHearing(SuperHero<POWER> hero) {//泛型方法
            hero.getPower().hearSubtleNoises();
        }
        static <POWER extends SuperHearing & SuperSmell>
        void superFind(SuperHero<POWER> hero) {//泛型方法
            hero.getPower().hearSubtleNoises();
            hero.getPower().trackBySmell();
        }
        public static void main(String[] args) {
            DogBoy dogBoy = new DogBoy();
            useSuperHearing(dogBoy);
            superFind(dogBoy);
            // You can do this:
            List<? extends SuperHearing> audioBoys;
            // But you can't do this:
            // List<? extends SuperHearing & SuperSmell> dogBoys;
        }
    } ///:~
    
    • 主函数中的useSuperHearing泛型方法中,其对T的边界定义为<POWER extends SuperHearing>。而在形参中使用了泛型类SuperHero<POWER>,其对边界的要求是<POWER extends SuperPower>。因为SuperHearing继承了SuperPower,所以边界定义符合了对边界的要求。
    • 主函数中的useSuperHearing泛型方法中,其对T的边界定义为<POWER extends SuperHearing>。正因如此,在方法中便可以调用SuperHearing的方法hearSubtleNoises了。

    其他

    本文例子均来自java编程思想,例子本身不错,但奈何作者对其做的讲解很少,所以本人为其加上了详细的分析。其实这些例子都需要反复琢磨,精读之后才会对泛型的extends关键字有深刻的理解。

    展开全文
  • extends通配符

    千次阅读 2019-08-31 11:09:58
    public class Pair<T extends Number> { ... } 现在,我们只能定义: Pair<Number> p1 = null; Pair<Integer> p2 = new Pair(1, 2); Pair<Double> p3 = null; 因为 Number 、 Integer 和 Double 都符合...
  • infer 最早出现在此 PR 中,表示在 extends 条件语句中待推断的类型变量。 用在函数中 可以表示函数中的入参或函数的返回值。 函数的入参示例如下: type ParamType<T> = T extends (param: infer P) => ...
  • 这里有extends接口,我们开篇说过,extends表示绑定,后面的BindingType即可以是接口,也可以是类,下面我们就再举个绑定类的例子。 (3)、实例:绑定类 我们假设,我们有很多种类的水果,需要写一个...
  • java 泛型 extends 多个

    千次阅读 2019-02-09 15:22:13
    java 泛型 extends 多个
  • public class findmin extends Applet implements ActionListener JavaAppliet程序,在文本框里输入三个数,显示最小数
  • extends在java中的作用是继承的意思,在Java中,通过关键字extends继承一个已有的类,被继承的类称为父类【超类,基类】,新的类称为子类【派生类】,并且在Java中不允许多继承。继承是理解面向对象程序设计的关键。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,464,142
精华内容 985,656
关键字:

extends