精华内容
下载资源
问答
  • java泛型中的自限定类型有什么作用?具体举个例子,一个应用场景
  • Java 自限定类型

    千次阅读 2015-12-06 21:35:55
    Java泛型中,个好像是经常性出现的习惯用法,它相当令人费解:  class SelfBounded> { // ....}  这就像两面镜子一样彼此照向对方所引起的炫目效果一样,是一种无限反射。SelfBounded类接受泛型参数T,而T由...

        在Java泛型中,有个好像是经常性出现的习惯用法,它相当令人费解:

             class SelfBounded<T extends SelfBounded<T>> { // ....}

        这就像两面镜子一样彼此照向对方所引起的炫目效果一样,是一种无限反射。SelfBounded类接受泛型参数T,而T由一个边界类限定,这个边界就是拥有T作为其参数的SelfBounded。

        当你首次看到它时,很难去解析它,它强调的是当extends关键字用于边界与用来创建子类明显不同的。

    展开全文
  • Java自限定类型(Self-Bound Types )

    千次阅读 2018-12-23 18:52:23
    Java的泛型中一种比较特殊的用法: class SelfBounded&lt;T extends SelfBounded&lt;T&gt;&gt;{} 网上的其他博客说得不是很详细,所以在这里记录一下。先看一个简单的例子(Thinking In Java 4th...

    版权声明:本文为原创文章,未经博主允许不得用于商业用途。

    引入

        Java的泛型中有一种比较特殊的用法:

    class SelfBounded<T extends SelfBounded<T>>{}
    

    网上的其他博客说得不是很详细,所以在这里记录一下。先看一个简单的例子(Thinking In Java 4th Edition P500,做了些修改)

    class BasicHolder<T> {
    	int No;
    	T element;
    	void set(T arg) { element = arg; }
    	T get() { return element; }
    	void f() {
    		System.out.println("Subtype "+No);
    	}
    } 
    

        比较容易理解,这个类负责维护一个变量,并且提供访问接口。常规用法这里不做说明,不过如下的用法也是正确的:

    class Subtype extends BasicHolder<Subtype> 
    {
    	public Subtype(int No){ this.No = No; }
    }
    

        Subtype只负责维护和自己同类型的变量。比较有趣的是你可以像俄罗斯套娃一样循环的嵌套Subtype:

    Subtype a1 = new Subtype();
    Subtype a2 = new Subtype();
    Subtype a3 = new Subtype(3);
    Subtype a4 = new Subtype(4);
    a2.set(a1);
    a3.set(a2);
    a4.set(a3);
    a4.get().get().get().f();
    

    这段代码输出为Subtype 1

    自限定类型

        理解了Subtype的原理以后再看自限定类型逻辑就清晰了许多,

    class SelfBounded<T extends SelfBounded<T>>
    

    SelfBounded也是一个普通的泛型类,只不过需要满足extends关键字限定。对于任意一个满足此条件的类型type,由于在定义type时type还没有定义完成(听起来像是废话),所以不可能有type的子类先产生。所以实际上这个extends关键字就将其限定在自己本身。即type也为SelfBounded<type>。
        因此实际上可以将BasicHolder改成:

    class BasicHolder<T extends BasicHolder<T>>
    

    而此时Subtype满足此条件,修改前后的区别为修改后会在编译阶段强制要求所有子类都满足自限定的条件。因此只有如下的子类才能够通过编译:

    class A extends SelfBounded<A>{}	//自限定的定义
    class B extends SelfBounded<A>{}	//由于A满足自限定条件,因此B的定义是合法的
    class C extends SelfBounded{}		//原生类型
    

    应用

        在Thinking In Java中给出的自限定类的用途为针对子类对基类型成员函数的重载。这里将书中的进行了简化:

    class Basic{
    	Basic b;
    	public void set(Basic b){ this.b = b; }
    }
    
    class SubType extends Basic{
    	SubType b;
    	public void set(SubType b){ this.b = b; }
    }
    
    SubType st = new SubType();
    st.set(new SubType());		//Ok
    st.set(new Basic());		//调用了继承自Basic的set函数
    

    可以看到,SubType无法覆写Basic的set函数,因此一直保留着这个接口。而自限定类型可以解决这个问题,上面的类使用自限定类重写为:

    class Basic<T extends Basic<T>>{
    	T b;
    	public void set(T b){ this.b = b; }
    }
    class SubType extends Basic<SubType>{}
    

    不仅代码变得更加简洁,而且此时再执行st.set(new Basic());语句时编译器会报错(Basic无法转化为SubType),因为实际上此时的SubType只有一个set方法,即实现了使用不同的类型对基类的成员重载。

    展开全文
  • java 泛型-自限定类型

    千次阅读 2019-06-26 17:48:52
    一,什么自限定类型 1,普通泛型 /** * @ClassName BasicHolder * @Description 普通泛型类 * @Author liangfeng * @Date 2019-06-26 11:01 * @Version 1.0 **/ public class BasicHolder<T> {...

    一,什么是自限定类型

    1,普通泛型
    /**
     * @ClassName BasicHolder
     * @Description 普通泛型类
     * @Author liangfeng
     * @Date 2019-06-26 11:01
     * @Version 1.0
     **/
    public class BasicHolder<T> {
        private T element;
    
        public void set(T t){
            element = t;
        }
    
        public T get(){
            return element;
        }
    
        public void f(){
            System.out.println(element.getClass().getName());
        }
    }
    
    /**
     * @ClassName BaseOther
     * @Description TODO
     * @Author liangfeng
     * @Date 2019-06-26 11:05
     * @Version 1.0
     **/
    public class BaseOther extends BasicHolder<Other> {
    }
    
    
    /**
     * @ClassName Other
     * @Description TODO
     * @Author liangfeng
     * @Date 2019-06-26 11:04
     * @Version 1.0
     **/
    public class Other {
    }
    
    /**
     * @ClassName Test
     * @Description TODO
     * @Author liangfeng
     * @Date 2019-06-26 11:05
     * @Version 1.0
     **/
    public class Test {
    
        public static void main(String[] args) {
            BaseOther baseOther1 = new BaseOther();
            baseOther1.set(new Other()); //传入其他类型
            Other other = baseOther1.get();//得到其他类型
            baseOther1.f();
        }
    }
    
    

    普通泛型就不必详细解释啦 。

    2,自限定泛型

    自限定的泛型 格式如下

    <T extends SelfBounded<T>>
    

    它所对应的实际类型如下实例

    public class A extends SelfBounded<A> {
    }
    

    解释:一个类继承一个带有泛型的父类 父类泛型类型为该类的类型,也就是说基类用其导出类作为泛型的类型,基类中所使用的泛型类型都是该导出类
    意义:先看如下代码

    /**
     * @ClassName SelfBounded
     * @Description 自限定泛型类
     * @Author liangfeng
     * @Date 2019-06-26 11:16
     * @Version 1.0
     **/
    public class SelfBounded<T extends SelfBounded<T>> {
    
        private T element;
    
        public SelfBounded<T> setElement(T t){
            element = t;
            return this;
        }
    
        public T getElement(){
            return element;
        }
    
        public void f(){
            System.out.println(element.getClass().getName());
        }
    
    }
    
    /**
     * @ClassName A
     * @Description TODO
     * @Author liangfeng
     * @Date 2019-06-26 11:25
     * @Version 1.0
     **/
    public class A extends SelfBounded<A> {
    }
    
    public static void main(String[] args) {
            A a = new A();
            a.setElement(new A());//参数传递A类型
            A element = a.getElement();//返回的也是A类型
    		
    }
    
    

    和前面的普通泛型比较你发现有什么区别吗 ?
    看方法传递的参数:
    普通类型方法参数和返回是使用其他类型
    自限定类型的方法参数和放回值类型只能是它自己的类型,可以保证类型参数和正在被定义的类相同

    二,参数协变

    自限定的价值在于他可以产生参数协变
    参数协变:方法参数类型随着子类类型变化而变化
    先观察下面两部分代码
    1,普通泛型参数协变

    /**
     * @ClassName Base
     * @Description TODO
     * @Author liangfeng
     * @Date 2019-06-26 17:16
     * @Version 1.0
     **/
    public class Base {
    }
    
    
    /**
     * @ClassName BaseSon
     * @Description TODO
     * @Author liangfeng
     * @Date 2019-06-26 17:17
     * @Version 1.0
     **/
    public class BaseSon extends Base {
    }
    
    /**
     * @ClassName GenericSetter
     * @Description TODO
     * @Author liangfeng
     * @Date 2019-06-26 17:18
     * @Version 1.0
     **/
    public class GenericSetter<T> {
    
        public void set(T t){
            System.out.println("GenericSetter.set(base)");
        }
    }
    
    /**
     * @ClassName GenericSetterSon
     * @Description TODO
     * @Author liangfeng
     * @Date 2019-06-26 17:23
     * @Version 1.0
     **/
    public class GenericSetterSon extends GenericSetter<Base> {
    
        public void set(BaseSon baseSon){
            System.out.println("GenericSetterSon.set(baseson)");
        }
    }
    
    
    
        public static void main(String[] args) {
            Base base = new Base();
            BaseSon baseSon = new BaseSon();
            GenericSetterSon genericSetterSon = new GenericSetterSon();
            genericSetterSon.set(baseSon);
            genericSetterSon.set(base);
        }
    
    
    

    以上的输出结果

    GenericSetterSon.set(baseson)
    GenericSetter.set(base)
    

    2,自限定的协变参数

    /**
     * @ClassName SelfBoundSetter
     * @Description TODO
     * @Author liangfeng
     * @Date 2019-06-26 17:28
     * @Version 1.0
     **/
    public class SelfBoundSetter<T extends SelfBoundSetter<T>> {
    
        void set(T t){
            System.out.println("SelfBoundSetter.set"+t.getClass().getName());
        }
    }
    
    /**
     * @ClassName SelfBoundSetterSon
     * @Description TODO
     * @Author liangfeng
     * @Date 2019-06-26 17:30
     * @Version 1.0
     **/
    public class SelfBoundSetterSon extends SelfBoundSetter<SelfBoundSetterSon> {
    	//子类无需实现新方法
    }
    
    
        public static void main(String[] args) {
            SelfBoundSetterSon selfBoundSetterSon = new SelfBoundSetterSon();
            SelfBoundSetterSon selfBoundSetterSon1 = new SelfBoundSetterSon();
            SelfBoundSetter selfBoundSetter = new SelfBoundSetter();
            selfBoundSetterSon.set(selfBoundSetterSon1);
            //selfBoundSetterSon.set(selfBoundSetter);报错 不能将SelfBoundSetter类型传递给selfBoundSetterSon类型的参数
        }
    
    

    输出结果

    SelfBoundSetter.settest.zixianding.SelfBoundSetterSon
    

    对比:
    第一部分代码 输出结果可以看出 子类方法和父类方法实现啦重载而不是覆盖 覆盖的话将不会输出GenericSetter.set(base)
    第二部分代码可以看出当子类继承父类的时候父类中的函数参数类型变成子类的类型而且只有一个方法没有重载而且子类的方法不能接受父类类型参数
    也就是说不使用自限定泛型继承机制会介入实现重载有父类和子类的两个方法
    使用自限定类型只有子类中的一个方法不存在父类的方法。

    参考:《java编程思想(第四版)》第十五章 15.12小节

    展开全文
  • Java中的枚举和自限定类型的泛型

    千次阅读 2018-08-16 10:54:37
    Java中所有的enum都继承自Java.lang.Enum类,而Enum类的定义如下: public abstract class Enum&lt;E extends Enum&...从定义可以看到,Enum类使用了自限定类型的泛型。 限定的类型参...

    Java中所有的enum都继承自Java.lang.Enum类,而Enum类的定义如下:

    public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {
        // ...
    }

    从定义可以看到,Enum类使用了自限定类型的泛型。

    自限定的类型参数有和意义呢?它可以保证泛型参数必须与正在被定义的类相同(或有相同的基类),例如:

    public class Test {
        public static void main(String[] args) {
            MyEnum1 enum1 = new MyEnum1();
            MyEnum1 enum11 = new MyEnum1();
    
            MyEnum2 enum2 = new MyEnum2();
            MyEnum2 enum22 = new MyEnum2();
    
            MyEnum3 enum3 = new MyEnum3();
            MyEnum3 enum33 = new MyEnum3();
    
            enum1.compareTo(enum11);
            enum2.compareTo(enum22);
            enum3.compareTo(enum2);
    
        }
    }
    
    abstract class AbsEnum<E extends AbsEnum<E>> implements Comparable<E> {}
    
    
    class MyEnum1 extends AbsEnum<MyEnum1> {
        @Override
        public int compareTo(MyEnum1 o) {
            return 0;
        }
    }
    
    class MyEnum2 extends AbsEnum<MyEnum2> {
        @Override
        public int compareTo(MyEnum2 o) {
            return 0;
        }
    }
    
    class MyEnum3 extends AbsEnum<MyEnum2> {
        @Override
        public int compareTo(MyEnum2 o) {
            return 0;
        }
    }

    AbsEnum是一个使用自限定类型的基类,AbsEnum要求所有继承自AbsEnum的子类的泛型参数必须时AbsEnum的子类。这样就相当于给泛型提供了一个边界。

    所以,当我们定义了一个泛型类的时候

    public enum Month {
        JAN, FEB, MAR;
    }

    编译器做的事就是把这个enum编译成Enum类的子类,使用反编译工具可得到:

    final class Month extends java.lang.Enum<Month> {
        public static final Month JAN;
        public static final Month FEB;
        public static final Month Mar;
    }

    如此就保证了Month这个枚举类的实例只能和Month的实例进行比较(如上例的MyEnum1和MyEnum2),而不会出现两个不同的枚举类进行比较(如上例的MyEnum3)

    展开全文
  • 从使用上来说,Subtype对象本身的类型是Subtype,且Subtype对象继承而来的成员(element)、方法的形参(set方法)、方法的返回值(get方法)也是Subtype了(这就是自限定的重要作用)。这样Subtype对象就只允许和Subtype...
  • 1. 自限定类型java泛型中,经常会出现如下的泛型写法:class SelfBounded<T extends SelfBounded<T>> SelfBounded类接受泛型参数T,而T由一个边界类限定,这个边界就是拥有T作为其参数的SelfBounded。这种写法...
  • Java泛型 类型变量的限定

    千次阅读 2015-06-08 15:43:24
    下面就举一个方法限定接收参数的类型的例子来说明如何限定类型变量。 首先几个简单的辅助类: package generic; public class Person extends Animal { private String name; public Person(Strin
  • 【0】README0.1) 本文描述+源代码均 转 core java volume 1, 旨在理解 java泛型程序设计 的 通配符类型+通配符的超类型限定 的知识;【1】通配符类型相关1.1)通配符类型: Pair < ? extends Employee> 表示任何...
  • JAVA 泛型限定

    千次阅读 2013-03-17 21:14:17
    //仅作为学习笔记 /* ? 通配符,也可以理解为占位符 ... super E : 可以接受E 类型 或者 E 的父类型 (下限定) */ import java.util.*; class Person { private String name; Person(String na
  • Java 泛型中的类型限定

    千次阅读 2014-05-26 14:10:19
    但是Java的泛型还有一个好处,在于可以限定T的类型,格式如下: Test,这样就要求Test的类型必须继承了Base。 注意这里的extends只是一个关键字,不同于表示继承的extends,Base可以是Class,也可以是Interface。 ...
  • 什么叫做java类的全限定名 所谓全限定名 = 包名 + 类型名 (Java)全限定类名和非限定类名的区别 全限定类名:就是类名全称,带包路径的点隔开,例如: java.lang.String。 即全限定名 = 包名+类型,又如: 在...
  • 【0】README0.1) 本文描述+源代码均 转 core java volume 1, 旨在理解 java泛型程序设计 的 类型变量限定 + 泛型代码和虚拟机 的知识;【1】类型变量的限定1.1)类和方法需要对类型变量加以限定 1.1.1)看个荔枝...
  • Java限定类名和非限定类名的区别

    万次阅读 多人点赞 2018-06-12 10:14:56
    限定类名,就是类名全称,带包路径的点隔开,例如: java.lang.String。 非限定(non-qualified)类名也叫短名,就是我们平时说的类名,不带包的,例如:String。 非限定类名是相对于限定类名来说的,在Java...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 155,510
精华内容 62,204
关键字:

java自限定类型有什么用

java 订阅