Java中的泛型的问题?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的泛型的问题?相关的知识,希望对你有一定的参考价值。

能解释下这些代码,尤其是最后一行的this和构造器中第一行的this,我只知道这是用来当被子类继承时获取泛型的,还有为什么强转为(ParameterizedType)类型,还有为什么要将type[0]的结果进行强转

public BaseDao()

Class clazz=this.getClass();  //通过当前对象(this)获取当前类

clazz.getGenericSuperclass(); //返回当前类的父类的Type

//转换成有泛型的ParameterizedType类

ParameterizedType parameterizedType=(ParameterizedType)clazz.getGenericSuperclass();

//上面三句其实就是为了获取BaseDao类本身

Type[] types = parameterizedType.getActualTypeArguments();

this.type=(Class<T>)types[0];

//上面两句是获取运行期的泛型类型,返回给当前对象(this)的type属性

追问

这个类是被子类继承的当子类创建的时候调用父类的构造器进行初始化,所以当前对象是子类的对象(debug的时候显示的就是子类的对象),那这个this.type中的type是子类的还是父类的,子类继承父类但是不能调用私有的属性,如果type是父类的而this代表子类的对象,那不就矛盾了吗

追答

不矛盾啊,this就是指当前对象啊,子类继承了父类,父类可继承的属性和方法,子类都是继承过来的,而且子类不是可以向上转型为父类么,所以this.type就是指当前对象的type,子类访问父类的私有属性虽然不能直接访问,但是不代表它没有啊,你不是还有getter方法么。

追问

但是我在idea中通过子类对象给私有属性

进行赋值并不行啊,this.type不就是给子类的属性赋值吗,为什么这里可以,我测试的就不行。

追答

这里可以是因为它是直接在类内部赋值的,而继承的子类,需要给私有属性赋值,需要通过setter方法

追问

是直接在子类的内部还是父类的内部,setter方法和内部赋值有区别吗,内部赋值没有什么印象呢

追答

type作为一个私有属性,在它的声明域里可以直接赋值的,子类要想访问父类的私有属性,需要通过setter方法,这里type的赋值是通过它的声明域父类里直接赋值的,而你说的继承子类的type赋值它是通过父类的构造方法间接赋值的。结构类似这样:

当你声明一个B对象,它就会通过B类的构造访问A类的构造,然后赋值给B对象的type属性,所以这里A类的this就是B对象

type作为一个私有属性,在它的声明域里可以直接赋值的,子类要想访问父类的私有属性,需要通过setter方法,这里type的赋值是通过它的声明域父类里直接赋值的,而你说的继承子类的type赋值它是通过父类的构造方法间接赋值的。结构类似这样:

当你声明一个B对象,它就会通过B类的构造访问A类的构造,然后赋值给B对象的type属性,所以这里A类的this就是B对象,主要是看哪个对象来调用,this就是哪个对象

追问

所以说这里的this.type其实是给子类继承父类的私有属性type赋值对吗,就是给子类的type赋值对吗

追答

可以这么认为

参考技术A

1、Type type = clazz.getGenericSuperclass()

2、用了子接口接收了


3、至于为什么用子接口接收,你看下它里面的方法,不符合你要的,所有要强转成子接口

4、至于为什么要取第一个值(type[0])进行强转,是因为你觉得你泛型中只有一个参数


如满意,请采纳!!!

追问

我想问的是最后一个this代表的是子类对象,那么这个this.type中的type到底是子类的还是父类的

参考技术B 这个和程序设计有关,这个数组中的第一个元素肯定实际是一个当前类的一个实例,
但是获取返回并不是此类型所以要使用强制转换追问

我想问的是最后一个this代表的是子类对象,那么这个this.type中的type到底是子类的还是父类的

参考技术C 您好,茫茫人海之中,能为君排忧解难实属朕的荣幸,在下拙见,若有错误,还望见谅!。比较器比较器这个接口也需要泛型public interface Comparable<T>
这里Comparable<Object>
ps 注意类首字母大写非常感谢您的耐心观看,如有帮助请采纳,祝生活愉快!谢谢!追问

我想问的是最后一个this代表的是子类对象,那么这个this.type中的type到底是子类的还是父类的

java中的泛型的使用与理解

什么是泛型?

  泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写 体验泛型
代码时定义一些可变部份,那些部份在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。

 

定义:

泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法
的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。

在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型
转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患

泛型的好处:

    泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

    1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。

    2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。

    3、泛型的类型参数可以有多个。

    4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。

    5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String");

 

注意:

  • 泛型是 Java 1.5 的新增特性,它以C++模板为参照,本质是参数化类型(Parameterized Type)的应用。
  • 类型参数只能用来表示引用类型,泛型在Java中要求,泛型传入的必须是包装类型,必须是Object类型的,或者是自定义的类,不能传入基本类型例如  int、double、char 等。,必须要传包装类型如Integer不能用来表示基本类型,但是传递基本类型不会报错,因为它们会自动装箱成对应的包装类。

运用:

 1 /*iG相当于占位符,用来传递数据类型,而不是数据的值,称为类型参数(名字可以自定义,当然更多的时候我们得按照规范来)
 2  * 
 3 */
 4 //自定义泛型类,多个泛型之间可以用逗号隔开如<iG,iT,..>
 5 class MyArrays<iG>{  //类的泛型必须要放在类名的后面
 6     //调换数组的元素的位置
 7     public void rever(iG[] a){
 8         System.out.println(a);
 9     }
10 }
11 public class customToolClass {
12   public static void main(String[] args){
13       String[] str=new String[10];
14       Integer[] intArr = new Integer[10];
15       //不能传基本数据类型,就算是整形数组,如int[],也要传int的包装类Integer
16       int[] arr = new int[10];
17      // MyArrays<int> my1 = new MyArray<int>(); //不能是基本数据类型
18       MyArrays<Integer> my2 = new MyArrays<Integer>(); // 只能是包装类
19       //my2.rever(arr);  //不能是整形数组
20       //标准格式是这样的,两边的类型要匹配
21       MyArrays<String> aa = new MyArrays<String>();
22       aa.rever(str);
23       //下面这两种也是可以的,但是不推荐,这是java为了向下兼容以前的版本设计的
24       MyArrays<String> cc = new MyArrays();
25       MyArrays    dd = new MyArrays<String>();
26       //--------------------------------------------------------------
27       MyArrays<Integer> aa1 = new MyArrays<Integer>();
28       aa1.rever(intArr);
29   }
30 }

 

 与普通类的定义相比,上面的代码在类名后面多出了 <iG> ,iG 是自定义的标识符,也是参数,用来传递数据的类型,而不是数据的值,我们称之为类型参数。在泛型中,不但数据的值可以通过参数传递,数据的类型也可以通过参数传递。iG只是数据类型的占位符,运行时会被替换为真正的数据类型。

传值参数(我们通常所说的参数)由小括号包围,如 (int x, double y),类型参数(泛型参数)由尖括号包围,多个参数由逗号分隔,如 <T> 或 <T, E>。注意:这只是个规范,名称可以自定义的。

类型参数需要在类名后面给出。一旦给出了类型参数,就可以在类中使用了。类型参数必须是一个合法的标识符,习惯上使用单个大写字母,通常情况下,K 表示键,V 表示值,E 表示异常或错误,T 表示一般意义上的数据类型。

泛型类在实例化时必须指出具体的类型,也就是向类型参数传值,格式为:
    className variable<dataType1, dataType2> = new className<dataType1, dataType2>();
也可以省略等号右边的数据类型,但是会产生警告,即:
    className variable<dataType1, dataType2> = new className();

因为在使用泛型类时指明了数据类型,赋给其他类型的值会抛出异常,既不需要向下转型,也没有潜在的风险,比本文一开始介绍的自动装箱和向上转型要更加实用。

测试效果图:

以上是关于Java中的泛型的问题?的主要内容,如果未能解决你的问题,请参考以下文章

java泛型 泛型的内部原理:类型擦除以及类型擦除带来的问题

泛型的泛型的好处

java中的泛型的使用与理解

java泛型泛型的内部原理:类型擦除以及类型擦除带来的问题

JAVA中的泛型类是啥东西?

java中泛型List问题