三石说:java 基础 之 泛型
lipiwang 2024-11-22 17:21 4 浏览 0 评论
在没有介绍泛型的使用时想想我们在哪些地方使用泛型的居多,那么一定是集合中。在前面的集合中已经看到了使用到泛型了,今天来看下泛型具体的概念及用法。
泛型:
要使代码能够应用于“某种具体的类型而不是一个具体的接口或类”。增加了泛型支持后的集合,完全可以记住集合中元素的类型,并可以在编译时检查集合中元素的类型,如果试图向集合中添加不满足类型要求的对象,编译器就会提示错误。增加泛型后的集合,可以让代码更加简洁,程序更加健壮(Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常)。除此之外,Java泛型还增强了枚举类、反射等方面的功能
当创建带泛型声明的自定义类,为该类定义构造器时,构造器名还是原来的类名,不要增加泛型声明。
例如,为Apple类定义构造器,其构造器名依然是Apple,而不是Apple<T>调用该构造器时却可以使用Apple的形式,当然应该为T形参传入实际的类型参数。Java 7提供了菱形语法,允许省略<>中的类型实参。
元组:
将一组对象直接打包存储于其中的一个单一的对象。这个容器对象允许读取其中的元素,但是不允许对其存放新的对象(这也称为:数据传送对象)
比如一个二维的元组:
public class TwoTuple<A,B>{
public final A first;
public final B second;
public TwoTuple(A a, B b){ first = a; second = b;}
public String toStirng() {
return "("+first+","+second+")";
}
}
用泛型类构造一个堆栈类:
下面的例子使用了末端哨兵来判断堆栈何时为空,这个末端哨兵在构造LinkedStack时创建,然后每调用一次push()方法,就会创建一个Node对象,并将其链接到前一个Node对象。
public class LinkedStack<T> {
private static class Node<U> {
U item;
Node<U> next;
Node() { item = null; next = null; }
Node(U item, Node<U> next) {
this.item = item;
this.next = next;
}
boolean end() { return item == null && next == null; }
}
private Node<T> top = new Node<T>(); // End sentinel
public void push(T item) {
top = new Node<T>(item, top);
}
public T pop() {
T result = top.item;
if(!top.end())
top = top.next;
return result;
}
public static void main(String[] args) {
LinkedStack<String> lss = new LinkedStack<String>();
for(String s : "Phasers on stun!".split(" "))
lss.push(s);
String s;
while((s = lss.pop()) != null)
System.out.println(s);
}
} /* Output:
stun!
on
Phasers
*///:~
泛型接口:
public interface Generator{T next();}
用泛型接口实现生成Fibonacci数列:
public class Fibonacci implements Generator<Interger> {
private int count=0;
public Integer next(){return fib(count++);}
private int fib(int n){
if(n<2) return 1;
return fib(n-2)+fib(n-1);
}
public static void main(String[] args){
Fibonacci gen = new Fibonacci();
for(int i=0;i<18;i++){
System.out.println(gen.next()+" ");
}
}
}
/* output
1 1 2 3 5 8 13 21 34 55 89 144 233 377 ...
泛型方法:
泛型方法使得该方法能够独立于类而产生变化。无论何时,只要你能做到,就应该尽量使用泛型方法。也就是说如果使用泛型方法可以取代整个类泛型化,那么就应该使用泛型方法,因为他可以使得事情更清楚明白。
定义泛型方法:修饰符 返回参数 方法名(接收参数){}
public class MyUtils{
泛型中的类型转换,在未知类型时不能进行强转:用下面方式应该先判断
List<?>[] lsa=new ArrayList<?>[10];
Object[] oa=(Object[]) lsa;
List<Integer> li=new ArrayList<Integer>();
li.add(new Integer(3));
oa[1]=li;
Object target=lsa[1].get(0);
if (target instanceof String){
// 下面代码安全了
String s=(String) target;
}
使用泛型构建一个Set的使用工具(交集,差集):
import java.util.*;
public class Sets {
// 将两个set合并为一个set
public static <T> Set<T> union(Set<T> a, Set<T> b) {
Set<T> result = new HashSet<T>(a);
result.addAll(b);
return result;
}
// 返回共有的交集
public static <T>
Set<T> intersection(Set<T> a, Set<T> b) {
Set<T> result = new HashSet<T>(a);
result.retainAll(b);
return result;
}
// 从superset移除subset包含的元素
// Subtract subset from superset:
public static <T> Set<T>
difference(Set<T> superset, Set<T> subset) {
Set<T> result = new HashSet<T>(superset);
result.removeAll(subset);
return result;
}
// 返回交集之外的所有元素
// Reflexive--everything not in the intersection:
public static <T> Set<T> complement(Set<T> a, Set<T> b) {
return difference(union(a, b), intersection(a, b));
}
} ///:~
泛型边界通配符
泛型的上限:?extends 类型。
泛型的下限:?super 类型。
如果要从集合中读取类型T的数据,并且不能写入 可以使用 ? extends 通配符;(Producer Extends)
如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super)
// <T> 标明是一个泛型方法。
public static <T> void copy(Collection<T> dest , Collection<? extends T> src){..
.} //①这里的?只能为T的子类 带有子类限定的可以从泛型读取
//
public static <T> T copy(Collection<? super T> dest , Collection<T> src){.
..} //② ?只能为T的父类或者T 带有子类限定的可以从泛型写入
}如果既要存又要取,那么就不要使用任何通配符
上界的list只能get不能add,下届的list只能add不能get
编译器可以支持像上转型,不支持像下转型。
PECS参考:https://blog.51cto.com/flyingcat2013/1616068
泛型擦除:
在泛型代码内部,无法获取任何有关泛型参数类型的信息。java使用泛型擦除,比如List 和List 在运行时都是相同的类型,均被擦除为"原生"类型即List. 泛型擦除就是被擦除为父类。保留了类型的上限
比如:
List<String> list = new ArrayList<>();
//类型被擦除了,保留的是类型的上限,String的上限就是Object
List list1 = list;
泛型的面试题
Q&A Java中的泛型是什么 ? 使用泛型的好处是什么?
在集合中存储对象并在使用前进行类型转换是多么的不方便。泛型防止了那种情况的发生。它提供了编译期的类型安全,确保你只能把正确类型的对象放入 集合中,避免了在运行时出现ClassCastException
Q&A Java的泛型是如何工作的 ? 什么是类型擦除 ?
泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。例如 List在运行时仅用一个List来表示。这样做的目的,是确保能和Java 5之前的版本开发二进制类库进行兼容。你无法在运行时访问到类型参数,因为编译器已经把泛型类型转换成了原始类型。
Q&A什么是泛型中的限定通配符和非限定通配符 ?
限定通配符对类型进行了限制。有两种限定通配符,一种是它通过确保类型必须是T的子类来设定类型的上界,另一种是它通过确保类型必须是T的父类来设定类型的下界。泛型类型必须用限定内的类型来进行初始化,否则会导致编译错误。另一方面表 示了非限定通配符,因为可以用任意类型来替代
Q&A List 上界 和List 下界 之间有什么区别 ?
上界的list只能get不能add,下届的list只能add不能get
编译器可以支持像上转型,不支持像下转型。
Q&A 你可以把List传递给一个接受List参数的方法吗?
因为List可以存储任何类型的对象包括String, Integer等等,而List却只能用来存储Strings。
List objectList;
List stringList;
objectList = stringList; //compilation error incompatible types
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
List<Object> objectList = new ArrayList<>();
stringList.add("add");
stringList.add("123");
objectList.add("123");
objectList.add("234");
// 让objectList转为stringList,编译错误stringList必须是接收的List<String> List<Object>之间不能转换。
// stringList= objectList; // 编译错误,List<String> List<Object> 是没有任何关系的。
// objectList=stringList; // 编译错误
List<?> list = new ArrayList<>();
list = stringList;
System.out.println(list);
list = objectList;
System.out.println(list);
// list.add("sss"); // 编译器不允许这样使用
}
在泛型的面试中很大一部分会出现泛型边界问题,以及泛型的擦除。这是常常会问及的,所以我们需要格外的注意。
相关推荐
- ubuntu单机安装open-falcon极度详细操作
-
备注:以下操作均由本人实际操作并得到验证,喜欢的同学可尝试操作安装。步骤一1.1环境准备(使用系统:ubuntu18.04)1.1.1安装redisubuntu下安装(参考借鉴:https://...
- Linux搭建promtail、loki、grafana轻量日志监控系统
-
一:简介日志监控告警系统,较为主流的是ELK(Elasticsearch、Logstash和Kibana核心套件构成),虽然优点是功能丰富,允许复杂的操作。但是,这些方案往往规模复杂,资源占用高,...
- 一文搞懂,WAF阻止恶意攻击的8种方法
-
WAF(Web应用程序防火墙)是应用程序和互联网流量之间的第一道防线,它监视和过滤Internet流量以阻止不良流量和恶意请求,WAF是确保Web服务的可用性和完整性的重要安全解决方案。它...
- 14配置appvolume(ios14.6配置文件)
-
使用AppVolumes应用程序功能,您可以管理应用程序的整个生命周期,包括打包、更新和停用应用程序。您还可以自定义应用程序分配,以向最终用户提供应用程序的特定版本14.1安装appvolume...
- 目前流行的缺陷管理工具(缺陷管理方式存在的优缺点)
-
摘自:https://blog.csdn.net/jasonteststudy/article/details/7090127?utm_medium=distribute.pc_relevant.no...
- 开源数字货币交易所开发学习笔记(2)——SpringCloud
-
前言码云(Gitee)上开源数字货币交易所源码CoinExchange的整体架构用了SpringCloud,对于经验丰富的Java程序员来说,可能很简单,但是对于我这种入门级程序员,还是有学习的必要的...
- 开发JAX-RPC Web Services for WebSphere(下)
-
在开发JAX-RPCWebServicesforWebSphere(上)一文中,小编为大家介绍了如何创建一个Web服务项目、如何创建一个服务类和Web服务,以及部署项目等内容。接下来小编将为大...
- CXF学习笔记1(cxf client)
-
webservice是发布服务的简单并实用的一种技术了,个人学习了CXF这个框架,也比较简单,发布了一些笔记,希望对笔友收藏并有些作用哦1.什么是webServicewebService让一个程序可...
- 分布式RPC最全详解(图文全面总结)
-
分布式通信RPC是非常重要的分布式系统组件,大厂经常考察的Dubbo等RPC框架,下面我就全面来详解分布式通信RPC@mikechen本篇已收于mikechen原创超30万字《阿里架构师进阶专题合集》...
- Oracle WebLogic远程命令执行0day漏洞(CVE-2019-2725补丁绕过)预警
-
概述近日,奇安信天眼与安服团队通过数据监控发现,野外出现OracleWebLogic远程命令执行漏洞最新利用代码,此攻击利用绕过了厂商今年4月底所发布的最新安全补丁(CVE-2019-2725)。由...
- Spring IoC Container 原理解析(spring中ioc三种实现原理)
-
IoC、DI基础概念关于IoC和DI大家都不陌生,我们直接上martinfowler的原文,里面已经有DI的例子和spring的使用示例《InversionofControlContainer...
- Arthas线上服务器问题排查(arthas部署)
-
1Arthas(阿尔萨斯)能为你做什么?这个类从哪个jar包加载的?为什么会报各种类相关的Exception?我改的代码为什么没有执行到?难道是我没commit?分支搞错了?遇到问题无法在...
- 工具篇之IDEA功能插件HTTP_CLENT(idea2021插件)
-
工具描述:Java开发人员通用的开发者工具IDEA集成了HTTPClient功能,之后可以无需单独安装使用PostMan用来模拟http请求。创建方式:1)简易模式Tools->HTTPCl...
- RPC、Web Service等几种远程监控通信方式对比
-
几种远程监控通信方式的介绍一.RPCRPC使用C/S方式,采用http协议,发送请求到服务器,等待服务器返回结果。这个请求包括一个参数集和一个文本集,通常形成“classname.meth...
- 《github精选系列》——SpringBoot 全家桶
-
1简单总结1SpringBoot全家桶简介2项目简介3子项目列表4环境5运行6后续计划7问题反馈gitee地址:https://gitee.com/yidao620/springbo...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)