Java学习笔记之集合框架2
一、泛型Generic
泛型概述:泛型是一种特殊的类型,它把指定类型的工作推迟到客户端代码声明并实例化类或方法的时候进行。也被称为参数化类型。早期的Object类型可以接收任意的对象类型,但是在实际的使用中会有类型转换的问题,也就存在这隐患,所以Java提供了泛型来解决这个安全问题.
泛型优点:提高了程序的安全性,将运行期遇到的问题转移到编译器,省去了类型强转的麻烦。
泛型格式:< 泛型类型 >
注意:这里的泛型类型可以是任意的内容,是一种类型约束提高程序的安全性。
泛型常用在接口,类和方法上。
测试实例:使用ArrayList集合,存储自定义对象,并遍历 (泛型版本)
//自定义类
public class Person {
private Stringname;
public Person(Stringname) {
this.name =name;
}
public String getName(){
returnname;
}
}
//测试类
public class GenericDemo2 {
public static void main(String[] args) {
//1、创建集合对象:泛型
ArrayList<Person>list =new ArrayList<Person>();
//2、创建元素对象
Person p1 = new Person("青龙");
Person p2 = new Person("白虎");
Person p3 = new Person("朱雀");
Person p4 = new Person("玄武");
//3、添加元素到集合
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
//4、遍历
Iterator<Person>it = list.iterator();
while (it.hasNext()) {
Person p = it.next();
System.out.println(p.getName());
}
}
}
输出结果:青龙 白虎 朱雀 玄武
泛型类:把泛型定义在类上
格式:publicclass 类名<泛型类型1,…>
注意:泛型类型必须是引用类型
测试实例:自定义泛型类
<QQ> 定义一个泛型,QQ 使用当前这个泛型,这个QQ在程序运行的时候,会对应着一个具体的数据类型
//自定义泛型类
public class Test<QQ> {
private QQname;
public Test() {
super();
}
public Test(QQname) {
super();
this.name =name;
}
public void setName(QQ name){
this.name =name;
}
public QQ getName(){
returnname;
}
}
//泛型类测试
public class QQTest {
public static void main(String[] args) {
//QQ在使用时对应String类型
Test<String>t = newTest<String>();
t.setName("哈哈");
System.out.println(t.getName() );
//QQ在使用时对应Integer类型
Test<Integer>t2 = newTest<Integer>();
t2.setName(123);
System.out.println(t2.getName() );
}
}
输出结果:
哈哈
123
泛型方法:把泛型定义在方法上
格式:public <泛型类型>返回类型 方法名(泛型类型.)
通常泛型方法和泛型类一起使用。
注意:创建多个泛型类对象的时候,可以赋值不同的泛型类型,不会产生冲突。
K 的类型是在创建对象的时候确定的。TT 类型是在调用方法的时候确定的这里的K,TT 理解为是一种数据类型的变量名
//自定义泛型类
public classGenericMethod<K> {
//普通方法
public Stringmethod(Stringstr){
returnstr +"哈哈";
}
//泛型方法,方法的泛型和类的泛型一致
public K function(Kstr){
returnstr;
}
//泛型方法
public <TT> TTshow(TTstr) {
returnstr;
}
}
//泛型方法的测试类
public classGenericMethodTest {
public static void main(String[] args) {
//此处<String>相当于给<K>赋值,即K = String
GenericMethod<String>gm =newGenericMethod<String>();
System.out.println(gm.method("haha"));
String str = gm.function("呵呵");
System.out.println(str);
//TT = Integer
Integer in = gm.show(123);
System.out.println(in);
}
}
输出结果是:
haha哈哈
呵呵
123
泛型接口:把泛型定义在接口上
格式:publicinterface 接口名<泛型类型1…>
例如
//自定义泛型接口
public interface Inter<TT>{
public TT show(TTstr);//抽象方法
}
实现泛型接口的类:
方式1:在编写类的时候实现泛型接口的类型
public class InterImpl implementsInter<String> {
@Override//重写接口中的show方法
public Stringshow(Stringstr) {
returnstr;
}
}
方式2:创建对象的时候,确定泛型的数据类型
//InterImpl<QQ> 声明泛型QQ
//implements Inter<QQ> 使用QQ所代表的数据类型
public classInterImpl<QQ> implements Inter<QQ>{
@Override
public QQ show(QQstr) {
returnstr;
}
}
测试类
public class Test {
public static void main(String[] args) {
//方式1在编写类的时候实现泛型接口的类型
InterImplimpl = new InterImpl();
Stringstr = impl.show("haha");
System.out.println(str);
//方式2创建对象的时候,确定泛型的数据类型
InterImpl<String>impl =new InterImpl<String>();
String str = impl.show("hehe");
System.out.println(str);
}
}
泛型通配符
泛型通配符<?>
?是通配符,表示任意类型。如果泛型的类型没有明确,那么这个类型可以是
Object类以及任意的Java类。
向上限定:?extends E
?表示泛型的类型可以是E所对应的数据类型,或者是E的子类类型。
例如:
?extends Animal
? 代表了 Animal类型,或者Animal子类类型dog、cat…
向下限定:?super E
?表示泛型类型可以是 E所对应的数据类型,或者是E的父类类型。
例如:
? super Dog
? 代表的是 Dog类型,或者是Dog的父类类型
//泛型案例
public class CollectionDemo {
public static void main(String[] args) {
//通配符:?
Collection<?>c1 = newArrayList<Animal>();
Collection<?>c2 = newArrayList<Dog>();
Collection<?>c3 = newArrayList<Cat>();
Collection<?>c4 = newArrayList<Object>();
//向上限定,最高是Animal类型
Collection<? extends Animal>c5 =newArrayList<Animal>();
Collection<? extends Animal>c6 =newArrayList<Dog>();
Collection<? extends Animal>c7 =newArrayList<Cat>();
//Collection<? extends Animal> c8 =new ArrayList<Object>();
//因为 Object类型,不是Animal类型或Animal的子类型
//向下限定,最低是Animal类型
Collection<? super Animal>c9 =newArrayList<Animal>();
//Collection<? super Animal> c10 =new ArrayList<Dog>();
//因为Dog不是 Animal类型或者 Animal的父类型
//Collection<? super Animal> c11 =new ArrayList<Cat>();
//因为Cat不是 Animal类型或者 Animal的父类型
Collection<? super Animal>c12 =newArrayList<Object>();
}
}
注意:泛型JDK7后的新格式菱形泛型,如下。
ArrayList<String>list = new ArrayList<>();
目前使用最多的还是传统格式,如下。
ArrayList<String>list = new ArrayList<String>();
二、增强for循环
概述:简化数组和Collection集合的遍历,jdk1.5后出现的特性,它的底层是用迭代器实现
格式:for(元素数据类型 变量: 数组或者Collection集合){
使用变量即可,该变量就是元素
}
特点:简化遍历
注意:
增强for的目标要判断是否为null
如果需要使用索引,推荐使用传统for循环
如果不需要使用索引,推荐是使用增强for(),也可以使用迭代器,增强for循环就是来替代迭代器的。
测试案例:
public class ForEachDemo {
public static void main(String[] args) {
//jdk7 新特性,菱形泛型
//ArrayList<String>list = new ArrayList<>();
ArrayList<String>list =new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
//普通for循环,迭代器方式
for(Iterator<String>it =list.iterator();it.hasNext(); ) {
System.out.print(it.next() +" ");
}
System.out.println();
//增强for循环,替代迭代器
for (Stringstr :list) {
System.out.print(str +" ");
}
}
}
案例2:使用ArrayList集合存储多个自定义对象,并遍历(泛型,增强for)
public class ForEachTest2 {
public static void main(String[] args) {
//创建集合对象
ArrayList<Person>list =new ArrayList<Person>();
//创建自定义对象并添加到集合中
list.add(new Person("青龙"));
list.add(new Person("白虎"));
list.add(new Person("朱雀"));
//用增强for循环遍历集合
for(Personp :list) {
System.out.print(p.getName() +" ");
}
}
}
//自定义类
public class Person {
private Stringname;
public Person(Stringname) {
this.name =name;
}
public String getName(){
returnname;
}
}
结果是:青龙 白虎 朱雀
三、静态导入
格式:import static 包名….类名.方法名, 可以直接导入到方法的级别.
注意:方法必须是静态的.当多个类中有相同的方法同时导入时,会出现方法在使用时不确定是哪个类中的情况,所以静态导入无实际意义。
测试案例:
//静态导入,直接导入方法所在的包
import static java.lang.Math.abs;
public class StaticImportDemo{
public static void main(String[] args) {
//普通调用,类名.方法名
System.out.println(Math.abs(-3.14));//3.14
//静态导入,直接使用方法名
System.out.println(abs(-3.5));//3.5
}
}
四、可变参数
概述:定义方法的时候不知道该定义多少个参数
格式:修饰符 返回值类型 方法名(数据类型… 变量名){ }
注意:这里的变量其实是一个数组。可变参数方法的形式参数可以有多个,但最后一个参数必须是可变参数。可变参数方法的形式参数中只能有一个参数是可变长的。可变参数可以传入 一个数据,也可以是多个数据,还可以没有数据。不常用。
下列是可变参数方法错误的书写
int sum(int... num,charch){ }//可变参数必须是参数列表的最后一个参数
int sum(int... num,char...ch){ }//形参中只有一个参数是可变参数
测试案例:
public class ArgsDemo {
public static void main(String[] args) {
System.out.println(getSum(1,2));//2个参数
System.out.println(getSum(1,2,3,4,5));//多个参数
System.out.println(getSum()); //没有参数
}
public static int getSum(int...num) {
//[I@179dce4,通过打印num值可知可变参数就是一个数组
System.out.println(num);
int sum = 0;
for (intn :num) {
sum += n;
}
returnsum;
}
}
输出结果是:
num =[I@659e0bfd
3
num =[I@2a139a55
15
num =[I@15db9742
0
[I@15db9742说明:[表示数组,I表示是int类型,@15db9742表示变量的哈希码值,也可以理解为“地址”。
五、集合嵌套
概述:集合的嵌套就是集合中的元素是一个集合。
测试案例:
public class ArrayListTest {
public static void main(String[] args) {
//创建学校集合:集合中嵌套集合
ArrayList<ArrayList<String>>MIT =new
ArrayList<ArrayList<String>>();
//创建计算机系集合
ArrayList<String>CED = new ArrayList<String>();
//向计算机系添加学科
CED.add("C");
CED.add("C++");
CED.add("OS");
//创建电子工程系
ArrayList<String>DEE = new ArrayList<String>();
//向电子工程系添加学科
DEE.add("Analog");
DEE.add("Digital");
//把院系添加到学校中
MIT.add(CED);
MIT.add(DEE);
//打印总集合
System.out.println(MIT);
}
}
结果是:[[C,C++, OS], [Analog, Digital]]