java泛型类的继承规则
首先看一看java泛型类的使用:
/**
* 一个泛型方法:使程序更加安全
* 并且能被更多的使用
* @author 丁**
*
* @param <T>
*/
class Pair<T>{
private T first;
private T second; //实例化类型变量
public static<T> Pair<T> makePair(Class<T> cl){
try {
return new Pair<>(cl.newInstance(), cl.newInstance());
} catch (Exception e) {
return null;
}
} public Pair(){ first = null; second = null; }
public Pair(T first, T second){ this.first = first; this.second = second;} public T getFirst() {
return first;
}
public void setFirst(T first) {
this.first = first;
}
public T getSecond() {
return second;
}
public void setSecond(T second) {
this.second = second;
} }
class Father {
private int age = 40;
public void getName(){
System.out.println(age);
}
}
class Son extends Father{
private int age = 12;
public void getName() {
System.out.println(age);
}
}
在普通类中:Father aa = new Son();父类是可以用来指向子类的
但是在泛型类中却不是如此:
Pair<Son> bb = new Pair<>();
Pair<Father> cc = bb;//error
1:虽然Son是Father的子类,但是Pair<T>之间没有继承关系:
List<Object> a1 = new ArrayList<>();
List<String> a2 = new ArrayList<>();
//设a1可以等于a2
//a1 = a2;
//a1.add(1111);因为是对a1进行操作,所以可以添加Object,a1.add(Object ad);
//a2.get(0);报错,因为a1添加Object进入了a2的空间中,但是a2是String类型,所以报错
2:可以将参数化类型转换成一个原始类型:
List<String> a2 = new ArrayList<>();
List a3 = a2;//可以通过编译,但是后面使用方法时可能会产生类型错误!
//这时候a3对象时原始类型,所以add(Object obj);
a3.add(123);//是对a3进行操作,但是最终结果保存到了a2中,将一个Integer装入String中
显然是错误的;
3:泛型类可以扩展或实现其他的泛型类:
//泛型接口
interface List1<E>{
} //实现了泛型接口的泛型类
class List2<T, E> implements List1<E>{ } //泛型类
class List3<T>{ } //继承了其他泛型类的泛型类
class List4<T, E> extends List3<E>{ }
List1<Father> b1 = new List2<Son, Father>();//因为List2实现了List1
List3<Father> b2 = new List4<Son, Father>();//List4继承了List3,所以List3是父类,可以指向子类对象。
虽然这样也完成了泛型类的继承,实现了和普通类一样的多态,但是使用起来并不是特别好,就这样java引入了通配符概念:
通配符上限:
/*
通配符的上限:Pair<? extends Father> c2
extends是关键字
Pair<T>代表的是某个唯一(具体的泛型类)的泛型类:比如Pair<Son>,Pair<Father>
但是Pair<? extends Father>不是具体的泛型类,它所指的是参数类型为Father的子类的所有泛型类(包括Father)
*/
Pair<? extends Father> c3;
Pair<Father> c1 = new Pair<>();
Pair<Son> c2 = new Pair<>();
//c2 = c1;error
c3 = c1;
c3 = c2;
需要注意的是:
/*
* 使用通配符的上限的问题:
* ? extends Father getFirst();
* void setFirst(? extends Father);
* 当c2= c1时:
* c2.setFirst(Father father);时,会将Father对象添加到Son对象内存中,这是不好的
* 所以使用extends上限时,不能使用setFirst(? extends Father),add(? extends Father)* 等方法。
* 但可以使用getFirst();方法
*/
c2.setFirst( new Father(); );//error
通配符下限:
/*
* 通配符的下限:
* ? super Son
* 表示的不是某个具体的泛型类,而是表示参数类型为Son的父类的所有可能的泛型类(包括* * Son)
* 和通配符上限一样,通配符的超类型限定不能使用getFirst()方法,但可以使用setFirst(XX)方法
*/
Pair<Son> c1 = new Pair<>();
Pair<? super Son> c3;
c3 = c1; //另一种超类型限定的写法
Pair<T extends Comparable<? super T>> c4;
无限定通配符:
//无限定通配符
Pair<Son> c7 = new Pair<>();
Pair<String> c5 = new Pair<>();
//c7 = c5;error,因为他们不是同一种类型
Pair<?> c6 = new Pair<>();
c6 = c5;//Pair<?>是所有的Pair泛型类的父类,Pair<?> c6 = new Pair<xx>();
Pair<?>和Pair的本质不同在于:可以用任意的Object对象调用原始的Pair类的setObject()方法;
通配符的捕获:
//交换First,Second变量值
public static void swap(Pair<?> p){
? t = p.getFirst();//error,因为通配符(?)不是类型变量,所以不能直接将?写入代码中,利用通配符的捕获来解决这个问题。
p.setFirst(p.getSecond());
p.setSecond(t);
}
//交换First,Second变量值
public static void swap(Pair<?> p){
swapHelper(p);//在调用下面的方法时,类型参数就被捕获了。
} //利用通配符的捕获来解决该问题
public static <T> void swapHelper(Pair<T> p){
T t = p.getFirst();//T是具体的某个类型。
p.setFirst(p.getSecond());
p.setSecond(t);
}
注意:通配符的捕获只有在许多限制的情况下才是合法的,编译器必须能够确信通配符表达的是单个,确定的类型。
java泛型类的继承规则的更多相关文章
- JAVA封装、继承
封装 1.概念: 将类的某些信息隐藏在类的内部,不允许外部程序访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 2.好处: a.只能通过规定的方法访问数据 b.隐藏类的实例细节,方便修改和实 ...
- Java中的继承
我们在以前的学习中,我们会了C#中的继承,今天我们来了解了解Java中的继承,其实都大同小异啦! 1.语法 修饰符 SubClass extends SuperClass(){ //类定义部分 } e ...
- Java面向对象的继承
继承也是面向对象的又一重要特性,继承是类于类的一种关系,通俗来说狗属于动物类,那么狗这个类就继承了动物类 java中的继承是单继承的,一个类只能继承与一个父类 子类继承父类之后,子类就拥有了父类的所有 ...
- JAVA中的继承和覆盖
java里面的继承是子类继承父类的一些方法和属性(除private属性和方法之外):对于父类的私有属性和方法子类是没有继承的.可是要想子类也能訪问到父类的私有属性,必须给私有属性以外界訪问的方法接口. ...
- java类的继承,多态,抽象类与接口
知识点梳理: 1,怎样定义自己的类. MyStarFrame,MyStarPanel 类中定义: (1)属性(数据),变量. (2)方法(函数),行为. (3)构造方法(特征,作用,何时被调用 ...
- java类的继承的一些细节
类的继承是java面向对象体系的一个重要方面(封装.继承.多态),对于java类的继承,需要注意如下细节. 1.构造函数. 如果一个类没有任何构造函数,系统会默认分配一个无参的构造函数给它,这个构造函 ...
- java方法的继承,覆盖与重载
java中的继承使用extends关键字,在子类继承了父类之后将会获得父类的全部属性与方法(父类的构造器除外).如果在定义java类时没有显示定义她的父类,那么这个类默认将扩展java.lang.Ob ...
- Java 类设计----Java类的继承
Java类的继承 为描述和处理个人信息,定义类Person: public class Person { public String name; public inat age; public Dat ...
- Java中的继承、封装、多态的理解
Java中的继承.封装.多态 继承的理解: 1.继承是面向对象的三大特征之一,也是实现代码复用的重要手段.Java的继承具有单继承的特点,每个子类只有一个直接父类. 2.Java的继承通过extend ...
随机推荐
- SSL证书绑定成功
LNMPA一键安装包:装好后, 静态文件用nginx服务器,php文件用Apache服务器, 默认Apache端口为88:nginx为80: SSL证书装之前80端口, 装好后用443端口:
- PHP网站常见安全漏洞,及相应防范措施总结
目前,基于PHP的网站开发已经成为目前网站开发的主流,本文笔者重点从PHP网站攻击与安全防范方面进行探究,旨在减少网站漏洞,希望对大家有所帮助! 一.常见PHP网站安全漏洞 对于PHP的漏洞,目前常见 ...
- Android + Eclipse + PhoneGap 环境配置
用了3天的时间,终于把环境搭建完毕,郁闷了N天,终于完成了.这里我只是讲述我安装的过程,仅供大家参考. 环境搭建首先要去下载一些安装包: (下载前注意一下,电脑是32位还是64位的请注意选择安装包) ...
- css超出内容以省略号显示
控制只显示2行,并以省略号结束 text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-or ...
- Redis-配置认证密码
1.找到redis.conf,配置密码 2.要重新启动一下redis 3.用redis-cli重新登陆,我们查询的时候提示"Authentication required"查询失败 ...
- junit4初体验
OK,现在我们正式开始junit4系列的整理.前面的junit38作为4的补充知道就好了,实际编码中我们以4为主.这里先来一把junit的初体验,同时也让我们来一步一步的了解下TDD的好处. ORM大 ...
- Java与C/C++的区别
首先应该清楚,Java是由C++发展而来的,它保留了c++的大部分内容,类似于c++,但句法更清晰,规模更小,更易学.它是在对多种程序设计语言进行了深入细致研究的基础上,据弃了其他语言的不足之 ...
- IIS使用十大原则,(IIS过期时间,IIS缓存设置) 【转载】
1. 自定义错误页虽然自定义错误页很简单,但只有少数管理员有效地利用了它.管理员可以在MMC中将HTTP错误信息映像到服务器上的绝对URL或是某个文件,更为详细的信息可以在这里找到.如果你嫌这太麻烦, ...
- weex 启动 android 模拟器(mac环境)
一.android studio和android sdk下载 1.android studio下载并安装https://developer.android.com/studio/index.html ...
- Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式
在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...