java进阶篇

java进阶篇
Zero02接口
接口注意事项!
接口不能实例化,但可以使用匿名内部类来实现方法的方式来实现接口实例化
接口中默认都是抽象方法
实现接口必须实现方法,抽象类可以不实现
使用default修饰的接口方法无需实现
一个类可以实现多个接口 例: class S implements A , B , C{ }
接口中的属性,只能是final的,public static final 修饰。必须初始化。
如果想要访问接口的变量,可以使用接口对象或接口对象的实例化 + 变量名来访问
接口不能继承类,可以继承多个接口 例:interface A extends B , C{ }
接口的只能修饰为 public 和 默认
1 | package com.zero02; |
接口小练习
1 | interface A{ |
接口Vs继承类
当子类继承了父类,就自动的拥有父类的功能
如果子类需要扩展功能,可以通过实现接口的方式扩展.
可以理解 实现接口 是 对 java 单继承机制的一种补充
1 | class main { |
接口可以更好的解决代码的复用性和可维护性,接口更加适合设计各种规范。可以自行实现,使其更加灵活
接口的多态参数!!
可以让接口类型的对象指向被这个接口实现的类
1 | class main { |
接口的多态数组!!
接口类的实例指向一个接口类的数组,数组中的元素是实现接口的类的对象或实例,体现多态的接口类数组
1 | class main { |
接口的多态传递!!
当一个接口继承了另一个接口,实现该接口的类即要重写该接口的方法,也要重写该接口继承接口中的方法
1 | class main { |
内部类
局部内部类
- 可以访问外部类的所有成员,包括私有
- 不能添加修饰符,他相当于一个局部变量,不过可以使用final
- 局部内部类的作用域,在定义他的方法或代码块中
- 直接访问外部类的成员,创建对象再访问(必须在作用域中)
- 局部内部类两个特点: 作用域在方法体内或代码块中,本质也是一个类
- 外部其他类不能访问局部内部类
- 如果外部类和局部内部类重名时,按照就近原则访问成员,如果想要访问外部类的成员,则可以使用 外部类名 + this.成员 访问
1 | class main { |
匿名内部类!!!
- 本质上还是类,他也是个内部类,但是没有名字
- 匿名内部类的语法独特,该类既是一个类的定义,同时也是一个对象,既有定义类的特征,也有创建实例的特征。
- 可以直接访问外部类的所有成员,包括私有
- 不能添加访问修饰符,他相当于一个局部变量
- 作用域在定义他的代码块和方法体中
- 外部其他类不能访问匿名内部类
- 如果外部类和匿名内部类重名时,按照就近原则访问成员,如果想要访问外部类的成员,则可以使用 外部类名 + this.成员 访问
1 | class main { |
匿名内部类的实践
1 | package com.hspedu.innerclass; |
成员内部类
- 成员内部类是定义在外部类的成员位置,并且没有static修饰
- 可以直接访问外部类的所有成员,包括私有
- 可以添加任何访问修饰符public protected 无 private 因为他相当于一个成员
- 成员内部类的作用域为整个类体,和其他成员的作用域相同。在外部类成员方法中建立该类对象,可以调用该类的方法
- 成员内部类访问外部类成员,直接访问 。外部类访问成员内部类需要创建对象,再访问。外部其他类访问成员内部类,直接访问
- 如果外部类和成员内部类重名时,在成员内部类访问的话,按照就近原则访问成员,如果想要访问外部类的成员,则可以使用 外部类名 + this.成员 访问
1 | class main { |
静态内部类
- 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
- 可以添加任意访问修饰符 public protected 无 private ,因为它的地位就是一个成员
- 静态内部类的作用域为整个类体,和其他成员一样
- 静态内部类访问外部类,直接访问所有静态成员。 非静态无法访问。
- 外部类访问静态内部类,创建对象,再访问。 外部其他类访问静态内部类直接访问
- 如果外部类和静态内部类的成员重名时,静态内部类的方法访问成员,默认按照就近原则,如果想要访问外部类的成员,则可以使用外部类名 + 成员去访问
1 | class main { |
枚举
枚举的特点
枚举作为一个可读取的对象,存放很多常量,他们可用于随时调用。不需要修改,还可以指定一个枚举对象的常量所拥有的属性。所有常量使用static 和 final 修饰。通常对象名都大写,体现出是一个不可更改的常量。
枚举的注意事项
- 当我们使用enum 关键字开发一个枚举类时,默认会继承Enum类, 而且是一个final 类[如何证明],使用 javap 工具来演示
- 如果使用无参构造器 创建 枚举对象,则实参列表和小括号都可以省略
- 当有多个枚举对象时,使用,间隔,最后有一个分号结尾
- 枚举对象必须放在枚举类的行首.
1 | class main { |
枚举类的方法
1 | valueOf() 传递枚举类型的Class对象和枚举常量名称给静态方法valueOf,会得到于参数匹配的枚举常量 |
1 | class main { |
注解
注解的解释
- 注解(Annotation)也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息
- 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
- 在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替 java EE 旧版中所遗留的繁冗代码和XML 配置等。
基本的 Annotation 介绍
使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元
素 三个基本的 Annotation:
抑制的警告类型
- all,抑制所有警告
- boxing,抑制与封装/拆装作业相关的警告
- cast,抑制与强制转型作业相关的警告
- dep-ann,抑制与淘汰注释相关的警告
- deprecation,抑制与淘汰的相关警告
- fallthrough,抑制与 switch 陈述式中遗漏 break 相关的警告
- finally,抑制与未传回 finally 区块相关的警告
- hiding,抑制与隐藏变数的区域变数相关的警告
- incomplete-switch,抑制与 switch 陈述式(enum case)中遗漏项目相关的警告
- javadoc,抑制与 javadoc 相关的警告
元注解的基本介绍
JDK 的元 Annotation 用于修饰其他 Annotation 元注解: 本身作用不大,讲这个原因希望同学们,看源码时,可以知道他是干什么.
元注解的种类 (使用不多,了解, 不用深入研究)
- Retention //指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME
- Target // 指定注解可以在哪些地方使用
- Documented //指定该注解是否会在 javadoc 体现
- Inherited //子类会继承父类注解
异常
异常基本说明
java语言中,将程序中发生的不正常情况称为”异常”,语法错误和逻辑错误不是异常。
异常分为两种,一种是严重错误异常Error,一种是运行编译时异常Exception。
Error指无法解决的严重问题,如StackOverFloor栈溢出和OOM(out of memory)内存溢出,程序会崩溃。
Exception指其他一些偶然或外在因素产生的一般性问题,可以更改代码解决问题,如空指针访问,读取不存在的文件,网络连接中断等等,Exception分为两个,运行时异常和编译时异常
异常的总体系图
编译时异常,是在编写程序时编译器要求必须处理的异常
运行时异常,编译器检测不出来,对于这类异常,可以不做处理,因为这种异常很普遍。
常见的运行时异常
NullPointerException空指针异常
ArithmeticException算术异常
ArrayIndexOutOfBoundsException数组下标越界异常
ClassCastException类转换异常
NumberFormatException数字格式错误异常
常见的编译时异常
SQLException操作数据库时,查询表可能发生异常
IOException操作文件时,发生的异常
FileNotFoundException当操作一个不存在的文件时,发生异常
ClassNotFoundException加载类,而该类不存在时,异常
EOFException操作文件,到文件末尾,发生异常
IllegalArguementException非法的参数异常
异常处理的方式
try - catch - finally 程序员在代码中捕获发生的异常,自行处理
throws将发生的异常抛出,交给调用者来处理 (JVM或调用者)
try - finally 不会捕获异常,执行代码后,不管是否发生异常,都必须执行所有代码
1 | try{ |
1 | class A{ |
自定义异常
当程序中出现了某些错误,但该信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
通常是自定义一个异常类名作为一个类,继承Exception或RuntimeException,分别代表编译异常和运行异常
一般来说继承RuntimeException作为自定义异常类
1 | public class CustomException { |
集合
集合与数组的区别
长度区别:集合长度可变,数组长度不可变
内容区别:集合可存储不同类型的元素,数组存储只能存储单一类型元素
元素区别:集合只能存储引用类型元素,数组可存储引用类型,也可存储基本类型
集合体系框架图
注:蓝色的是接口,黑色的是实现类
接口的特点
Collection接口被list接口和set接口继承
list接口有三个实现类:ArrayList,LinkedList,Vector
Set接口被HashSet实现,被SortedSet接口继承,同时TreeSet类实现SortedSet接口,LinkedHashSet类继承HashSet类
Map接口有两个实现类,HashMap,Hashtable,同时Properties类继承Hashtable
Map接口被SortedMap接口继承,同时TreeMap类实现了SortedMap接口
Set:元素无序,不可重复的集合
List:元素有序,可重复的集合
Map:双列集合:具有映射关系的”key-value”Entry键值对的集合
Collection接口(单列集合)
collection是单列集合的最顶层接口,定义了一些通用的方法
Collection.add()添加单个元素
Collection.remove()删除指定元素,还可以指定元素索引
Collection.contains()判断指定元素是否存在与list列表中
Collection.size()获取集合中元素的个数
Collection.clear()清空所有集合中的元素
Collection.addAll()添加多个元素,可以给定一个要添加的另一个list,将两个list合并为一个
Collection.containsAll()判断多个元素是否都存在,可以给定一个要判断的另一个list,判断当前list是否存在这个list所有的元素
Collection.removeAll()删除多个元素,可以给定一个要删除的另一个list,将当前list中去除和另一个list的相同的元素
Collection.toArray()可以将collection类的集合转为数组
Collection.isEmpty()判断集合是否为空
Iterator接口遍历集合使用
Iterator是Collection的父接口,所以只要实现了Collection接口的类,都可以使用Iterator进行遍历数组
Iterator iterator = 集合对象.iterator();
Iterator接口的方法 idea快捷键:itit
Iterator.hasNext(),往往和while组合使用
Iterator.Next(),在while循环体中取出元素
for增强遍历集合格式 idea快捷键: iter
For(数据类型 引用名: 集合){
输出语句(引用名);
}
List接口的特点
有索引,精确操作元素
list集合类中元素有序(添加和取出顺序一致,且可重复)
list集合中的每个元素都有对应的顺序索引,即支持索引
list容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据需要存取容器中的元素
list接口是collection的子接口,可以使用collection和iterator的接口方法
List接口的实现类的方法
List.add(int index,Object obj)在index位置插入obj
List.addAll(int index,Collection obj)从index位置开始将obj中的所有元素添加至list中
List.get(Int index)获取指定index索引的元素
List.indexof(Object obj)返回obj在集合中第一次出现的位置
List.lastIndexOf(Object obj)返回obj在集合中最后一次出现的位置
List.remove(int index)指定index位置的元素将其移除,并返回元素
List.set(int index,Object obj)设置指定index位置的obj,相当于替换
List.subList(int fromindex,int toindex)返回一个从fromindex到toindex的子集合,[ }
ArrayList特点
查询快,增删慢,主要用于查询遍历数据,为最常用集合之一
arraylist允许null值,并且允许多个
arraylist是用数组来存储的
arraylist是线程不安全的,在多线程中使用vector
ArrayList底层
arraylist中维护了一个object类型的数组elementdata
Transient Object[] elementdata
trasient瞬间,短暂的 transient的属性不会被序列化
创建arraylist对象时,如果使用无参构造器,初始elementdata容量为0,第一次添加,则扩容
elementdata为10,如果再次扩容,则扩容为上次的1.5倍
如果指定了大小的构造器,则初始化elementdata为指定大小,如果再次扩容,则扩容为上次的1.5倍
数据结构是有序的元素序列,在内存中开辟一段连续的空键,在空键中存放元素,每个空键都有编号,通过编号可以快速找到相应元素,因此查询快,数组初始化时长度时固定的,想要增删元素,必须创建一个新数组,把源数组的元素复制进来,随后源数组销毁,耗时长,因此增删慢。
LinkedList的特点
linkedlist底层实现了双向链表和数段队列特点
查询慢,增删快
有特有的属性:
First 指向链表中的第一个元素
Last 指向链表中的最后一个元素
Next 指向元素的下一个元素
Prev 指向元素的前一个元素
删除元素,只需要改变链表的next和prev指向,就可以实现,所以效率高
可以添加任意元素(元素可以重复),包括null
linkedList是线程不安全的
LinkedList的特有方法
getFirst()返回第一个元素
getLast()返回最后一个元素
pop() 此方法用于删除或返回或弹出位于链表所表示的堆栈顶部(初始或第一位置)的对象。
push(E e) 这类似于LinkedList的addFirst()方法,只是将元素插入到链表的第一个位置或顶部。
addFirst(E e)添加元素到开头,头插
addLast(E e)添加元素到结尾,尾插
Vector类的特点
查询快,增删慢
vector底层和ArrayList一样,使用数组来存储的
Protected Object[] elementData;
vector是线程同步的,vector类的操作方法都带有synchrionized
如果需要线程安全需要使用vector
vector的效率比arraylist要低
在java编程思想中提到他又一些遗留的缺点,因此不建议使用
Vector的底层
如果使用的是无参构造器,默认的底层数组大小是10,当存储满后,按2倍扩容
如果指定大小,则每次直接按2倍扩大
ArrayList和LinkedList的比较
Arraylist是一个可变数组,根据指定流程来创建集合大小和扩容,增删效率低,因为是数组扩容,改查效率较高
LinkedList是一个双向链表,根据指针来组合整个链表中的前后关系,增删的效率较高,底层通过gc回收没有指向的元素,修改指针即可增加删除,改查效率较低
相对而言,查询较多,大部分会选择ArrayList
Set接口的特点
set是无序的,即存放和取出的顺序不一致,取出的顺序是固定的,但是和存放的顺序不一致。没有索引
不允许添加重复元素,也不允许有多个null值
set接口和list接口一样,都是collection接口的子接口,都可以使用collection接口和iterator接口的方法
Set也可以使用迭代器,增强for,但是不能通过索引遍历的方式来获取元素
HashSet的特点
查询快,元素无序,元素不可重复,没有索引
hashset底层是hashmap
JDK1.8之前:哈希表(数组+单向链表);JDK1.8之后:哈希表(数组+单向链表+红黑树)
通过获取一个元素的hash值来决定存放在数组的哪个位置上。当有两个或多个元素的hash值决定的下标相同时,会在该数组下表形成一个单向链表,存放多个元素添加的元素如果有相同值,首先调用该类的equals方法判断元素是否相同,相同会放弃添加,不同就加入如果任意一条链表的元素数量达到8并且数组的大小(table)为64,就会进化为红黑树
哈希表底层用数组+单向链表实现,即使用链表处理冲突,同一Hash值的元素都存储在一个链表里,但是当位于一个链表中的元素较多,即Hash值相等的元素较多,通过key值依次查找的效率降低。JDK1.8之后,哈希表底层采用数据+单向链表+红黑树实现,当链表长度超过阈值(8)时,链表将转换为红黑树,极大缩短查询时间。
ps:哈希值是一个十进制的整数,是对象的地址值,是一个逻辑地址,不是实际存储的物理地址,由系统随机给出。Object类的int hashCode()方法,可以获取对象的哈希值。
HashSet底层添加数据的过程
第一次添加
使用的是HashSet.put()方法
使用元素的 hashcode ^ hashcode结果的无符号右移16位的结果 获取该元素应该存放的索引下标值
底层会首先判断table是否为空,如果为空说明是第一次添加数据
如果table为null,或者大小为0,就将其扩容到16个空间
然后定义一个添加元素的临界值,是当前空间的4/3大小,如果已存在的元素大于临界值,会再一次扩容2倍
然后将元素添加进去
第二次添加
首先得到元素应该存放的索引下标值
判断此下标值是否为空,如果为空,就将元素添加进去
判断是否大于临界值,大于扩容,否则会跳过
第三次添加
首先得到元素应该存放的索引下标值
假如我们添加的和第一次添加的值相同
就进入非下标值为空的分支
首先有三种情况
如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样
并且满足准备加入的key和要添加位置的元素是同一个对象;
判断当前索引是否是一个红黑树,如果是一颗红黑数,就调用putTreeVal,来进行添加,在转成红黑树如果前table大于64并且单条链表为8个元素,才会进行树化;
否则就比较这个table当前索引的链表,遍历比较是否有相等的元素,如果没有就放在改链表的最后面
LinkedHashSet的特点
是HashSet的子类,LinkedHashSet的底层是LinkedHashMap(是hashMap的子类),
维护了一个数组 + 双向链表 + 红黑数
查询快,元素有序,元素不可重复,没有索引
LinkedHashSet根据元素的hashCode值来决定元素的存储位置
同时使用指针维护元素的次序,使得元素看起来是以插入顺序保存的
拥有before和after属性,first和last属性
添加一个元素时,先求hash值,在求索引,确定该元素在table的位置,然后将添加的元素加入到双向链表,原理和hashset类似
linkedHashSet的底层机制
添加第一次时,直接将数组table扩容到16,存放的节点类型时LinkedHashmap$Entry
table的类型时LinkedHashMap$Node, Entry继承了Node,继承关系是在内部类完成
linkedHashset的底层机制和hashset类似,但是不需要扩容,因为是双向链表指针
TreeSet的特点
数据结构:红黑树
查询快,元素有序,元素不可重复,没有索引
TreeSet实现了继承于Set接口的SortedSet接口 ,它支持两种排序方法,自然排序和定制排序,自然排序的意思就是放入元素“a”,“b”,a会自然地排在b前面,其中还有几个特有方法。
可以给添加的数据排序,默认按照字母排序
可以通过构造器传入一个comparator,自定义排序方法
Map接口的特点
元素包含两个值(key,value)即键值对,key值不允许重复,value可以重复,key和value时对应的,元素无序
Map与Collection并列存在,存储具有映射关系的键值对Entry<K,V>
Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
Map中的key不允许重复,原因和hashset一样
Map中的value可以重复
key和value可以为null,但是key不能有多个null,value可以有多个null
常用String类作为map的key
key和value存在一对一关系,通过key来获取value
Map的方法
Map.put()添加一个元素
Map.remove()根据键值删除映射关系
Map.get()根据键获取值
Map.size()获取元素个数
Map.isEmpty()Map集合是否为null
Map.clear()清除所有元素
Map.containsKey()查找键是否存在
ps:Map集合必须保证保证key唯一,作为key,必须重写hashCode方法和equals方法,以保证key唯一。
Map集合的遍历
- Set keySet = Map.keySet();//可以使用增强for,和while循环iterator
- Collection values = map.values();//可以使用增强for,和while循环iterator
- EntrySet<Entry<K,V>> entrySet = Map.entrySet()//可以使用增强for,和while循环iterator
- Entry.getKey()或者Entry.getValue()
HashMap 的 7 种遍历方式与性能分析!(强烈推荐) - 腾讯云开发者社区-腾讯云 (tencent.com)
HashMap的特点底层机制
JDK1.8之前:哈希表(数组+单向链表);JDK1.8之后:哈希表(数组+单向链表+红黑树)
查询快,元素无序,key不允许重复但可以为null,value可以重复
当添加一个和之前key一样但是value不一样的值时,会把指向的value替换
K - V 最后是 HashMap$Node node = newNode(hash,key,value,null)
K - V 为了方便程序员的遍历,还会创建EntrySet集合,该集合存放的元素类型Entry,Entry存放的就是key和value
即:transient Set<Map.Entry<K,V>> entrySet
可以通过Map.setEntry()生成Set进行遍历
然后可以通过entry对象调用getKey()或getValue()或Values()
LinkedHashMap实现类特点
JDK1.8之前:哈希表(数组+单向链表);JDK1.8之后:哈希表(数组+单向链表+红黑树)
查询快,元素有序,key不允许重复但可以为null,value可以重复
底层和LinkedHashset底层相同
Hashtable的特点
查询快,元素无序,key不允许重复并且不可以为null,value可以重复
存放的元素是键值对,即k-v
hasttable的键和值都不能为null
hashtable是线程安全的,hashMap是线程不安全的
继承了Dictionary类,实现了map接口
hashtable的键和值都不能为null,否则会抛出nullpointerException
hashtable使用方法基本上和hashMap一样
HashTable和Vector一样是古老的集合,有遗留缺陷,在JDK1.2之后 被更先进的集合取代了;HashTable是线程安全的,速度慢,HashMap是线程不安全的,速度快;
ps:Hashtable的子类Properties现在依然活跃,Properties集合是一个唯一和IO流结合的集合。
Properties
properties继承了hashtable类并且实现了map接口,也是使用一种键值对的形式来保存数据
properties的使用特点和hashtable类似
properties可以用于从xxx.properties文件中,加载数据到properties类对象。
properties也不允许空键和空值
如果添加了相同的key数据,会替换原key中的value
TreeMap的特点
查询快,元素有序,key不允许重复并且不可以为null,value可以重复。
可以给所有的node节点进行排序,默认也是按照字母排序
给构造器添加一个comparator,可以自定义排序规则
和TreeSet底层相类似
ConcurrentHashMap的特点
ConcurrentHashMap是线程安全的,和hashMap的底层是一样的,是数组+单项链表。
ConcurrentHashMap的性能要比HashMap更强,并且可以有多个线程同时执行修改ConcurrentHashMap.
ConcurrentHashMap有多个Segment组合而成,Segment本身就相当于一个HashMap对象。同HashMap一样,Segment包含一个HashEntry数组,数组中的每一个HashEntry既是一个键值对,也是一个链表的头节点.
Segment在ConcurrrentHashMap的数量是2的n次方个,共同保存在一个名为segments的数组当中。
segment是一个内部类,大致是这样的
1 | static class Segment<K, V> extends ReentrantLock implements Serializable { |
1 | ConcurrentHashMap要分为两种情况下来进行分析。一个是在jdk1.7,然后是在jdk1.8,他们之间的差别是非常大的。在jdk1.7它的底层是用数组加链表实现的。然后使用了一种分段锁来保证现场安全,它是将数组分成了16段,也就是给每个segment来配一把锁,然后再读每个segment的话就要获取对应的锁,他最多能有16个线程并发去操作。到了jdk1.8之后,他和HashMap一样也引入了红黑树这样的一种结构,同时在并发处理的方面不再使用分段锁的方式,而是采用cas加synchronize的关键字的这种方式来实现一种更加细粒度的锁,相当于是把这个锁的控制在了这种更加细微的hash桶的级别。在写入键值对的时候。这个可以锁住Hash桶的这种链表的头节点。就不会影响到其他的Hash桶的写入。 |
开发使用总结
在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现类特性进行选择,分析如下:
1.先判断存储的类型(一组对象[单列]或一组键值对[双列])
2.一组对象:collection接口
允许重复 : list
增删多:LinkedList
改查多:ArrayList
不允许重复: set
无序:HashSet【底层是hashmap,维护了一个哈希表即数组+链表+红黑树】
排序:TreeSet
插入和取出顺序一致:linkedHashSet,维护数组+双向链表
3 一组键值对 map
键无序:hashMap【底层是 jdk7:数组+链表 jdk8:数组+链表+红黑树】
键排序:TreeMap
键插入和取出顺序一致:LinkedHashMap
读取文件 Properties
Java集合总结,详细且易懂
Collection工具类的使用
是一个操作set,list,map等集合的工具类
collection中提供了一系列静态的方法对集合元素进行排序,查询和修改等操作
排序操作均为static方法
Reverse(list) 反转list中元素的顺序
Shuffle(list) 对list集合元素进行随机排序
Sort(list) 根据元素的自然排序对指定list集合元素按升序排序
Sort(list,comparator)根据元素的自定义排序对只当list集合元素按升序排序
Swap(list,int,int)将指定list集合中的i处元素和j处元素进行交换
Max(collection)根据元素的自然顺序,返回给定集合中最大的元素
Max(collection,comparator)根据comparator指定的排序,返回给定集合中的最大元素
Min(collection)根据元素的自然顺序,返回给定集合中最小的元素
Min(Collection)根据comparator指定的排序,返回给定集合中最小元素
Int frequency(collection,object)返回指定集合中指定元素的出现次数
Void copy(list dest,list src) 将src中的内容复制到dest中
Boolean replaceAll(list list,object oldval,object newval):使用新值替换list对象的虽有旧值
泛型
泛型的介绍
泛型又称为参数化类型,是jdk5.0出现的新特性,解决数据类型的安全性问题
在类声明或实例化时只要指定好需要的具体类型即可
java泛型可以保证如果在编译时没有发出警告,运行时就不会产生ClassCastException异常,同时,代码更加简洁,健壮
泛型的作用是:可以在类声明时通过一个表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型
泛型的语法
泛型的声明
interface接口
{} 和 Class类<K,V>{} 说明:1.其中,T,K,V不代表值,而是表示任意一种类型 2.任意字母都可以,常用T表示,是Type的缩写
泛型的实例化
要在类名后面指定类型参数的值(类型)如:
1
2
3List<String> strList = new ArrayList<String>();
Iterator<Customer> iterator = customer.iterator();
泛型的注意事项和细节
1 | interface List<T>{} |
自定义泛型类
1 | class 类名 <T,R..>{ |
- 普通成员可以使用泛型(属性,方法)
- 使用泛型的数组,不能初始化
- 静态方法中不能使用类的泛型
- 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
- 如果在创建对象时,没有指定类型,默认为object
1 | class Tiger<T,R,M> { |
自定义泛型接口
1 | iterface 接口名<T,R...>{ |
接口中,静态成员也不能使用泛型(这个和泛型类规定一样)
泛型接口的类型,在继承接口或者实现接口时确定
没有指定类型,默认为object
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27iterface IUsb <U,R> {
int n = 10;
U name = "hsp";//不能这样使用
//普通方法中,可以使用接口泛型
R get(U u);
void hi(R r);
void run(R r1,R r2,U u1,U u2);
//在jdk8中,可以在接口中,使用默认方法,也可以使用泛型
default R method(U u){
return null;
}
}
//在继承接口指定泛型的接口类型
iterface IA extends IUsb<String,Double>{
}
class AA implements IA{
//需要实现IA和IA的父接口的所有方法
}
//实现接口时,直接只当泛型接口的类型
Class BB implements IUsb<Integer,Float>{
//给U指定了Integer,给R指定了FLoat
}
//没有指定类型,默认为Object
class CC implements IUsb{//等价 class CC implements IUsb<Object,Object>{}
}
自定义泛型方法
1 | 修饰符 <T,R...> 返回类型 方法名(参数列表){ |
泛型方法,可以定义在普通类中,也可以定义在泛型类中
当泛型方法被调用时,类型会确定
当修饰符后面没有<T,R..>,那么方法不是泛型方法,而是使用了泛型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32class Car{//普通类
public void run(){//普通方法
}
//<T,R>就是泛型,提供给fly方法使用的
public <T,R> void fly(T t,R r){//泛型方法
System.out.println(t.getClass());
System.out.println(r.getClass());
}
}
class Fish<T,R>{//泛型类
public void run(){//普通方法
}
public<U,M> void eat(U u,M m){//泛型方法
}
//hi方法不是泛型方法,而是方法使用了类定义声明的泛型
public void hi(T t){
}
//泛型方法,可以使用类声明的泛型,也可以使用自己声明的泛型
public<K> void hell(R r,K k){
System.out.println(r.getClass());
System.out.println(k.getClass());
}
}
Car car = new Car();
car.fly("baoma",100);//当调用方法时,传入参数,编译器就会确定类型
//T -> String R -> ArrayList
Fish<String,ArrayList> fish = new Fish<>();泛型的继承和通配符
泛型不具备继承性
>:支持任意泛型类型 extends A>:支持A类以及A类的子类,规定了泛型的上限 super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限1
2
3Object o = new String("xx");
//这样写会报错
List<Object> list = new ArrayList<String>();