泛型(Generic)
泛型的概述:泛型是一种将类型的确定提前到编译时期的一种参数化类型。
格式:
泛型只允许设置引用数据类型,这里的E可以是A~Z任意一个字母。
泛型的分类:
泛型类:把泛型定义在类上
泛型接口:把泛型定义在接口上
泛型方法:把泛型定义在方法上
泛型的好处:
1.消除了黄色警告线
2.去除类型转换(例如不用讲Object类向下转型),提高了效率。
3.提高了安全性,避免了类型转换异常。
4.简化了代码。
5.提高了代码的扩展和可维护性。
泛型的特点:
1.泛型具有传递性
2.泛型可以定义多个
3.泛型只能设置引用数据类型
4.泛型的命名可以是A~Z之间
public class GenericDemo01 {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("三国演义");
c.add("水浒传");
c.add("红楼梦");
c.add("西游记");
Iterator<String> it = c.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s + "|" + s.length());
}
for (String s : c) {
System.out.println(s + "|" + s.length());
}
}
}
泛型类:
public class GenericDemo02 {
public static void main(String[] args) {
GenericClass<String, Float, Character> gc = new GenericClass<String, Float, Character>();
gc.setF('A');
gc.setH(3.55f);
gc.setT("小明");
}
}
//泛型可以定义多个
class GenericClass<T, H, F> {
private T t;
private H h;
private F f;
public GenericClass() {
}
public GenericClass(T t, H h, F f) {
super();
this.t = t;
this.h = h;
this.f = f;
}
public T getT() {
return t;
}
public H getH() {
return h;
}
public void setH(H h) {
this.h = h;
}
public F getF() {
return f;
}
public void setF(F f) {
this.f = f;
}
public void setT(T t) {
this.t = t;
}
}
泛型接口
使用泛型接口的三种方式
1.在实现类的时候确定泛型类型
2.在实现类的时候不确定泛型类型,在创建接口的时候确定泛型类型。
3.在匿名内部类的时候确定泛型类型。
public class InterfaceDemo01 {
public static void main(String[] args) {
IGeneric<Integer, String> gi = new GenericImpl();
gi.show("小明");
gi.concat(20, "老王");
//在创建接口的时候确定泛型
IGeneric<String, Double> gi2 = new GenericImpl2<String, Double>();
gi2.show(6.66);
gi2.concat("小张", 6.66);
//在匿名内部类的时候确定泛型
IGeneric<String, Integer> gi3 = new IGeneric<String, Integer>() {
@Override
public void show(Integer t) {
System.out.println("Hello" + t);
}
@Override
public void concat(String e, Integer r) {
System.out.println(e + r);
}
};
gi3.show(100);
gi3.concat("你好", 88);
}
}
interface IGeneric<E, T> {
void show(T t);
void concat(E e, T r);
}
//在实现类的时候确定接口类型
class GenericImpl implements IGeneric<Integer, String> {
@Override
public void show(String t) {
System.out.println(t);
}
@Override
public void concat(Integer e, String r) {
System.out.println(r + e);
}
}
//在实现类的时候也不确定接口类型
class GenericImpl2<E, T> implements IGeneric<E, T> {
@Override
public void show(T t) {
System.out.println(t);
}
@Override
public void concat(E e, T r) {
System.out.println(e);
System.out.println(r);
}
}
泛型方法
使用泛型方法:在方法调用的时候确定泛型
特点:
1.泛型方法在方法调用的时候确定类型
2.泛型方法独立于泛型类,泛型方法又称为局部泛型
3.泛型方法也可以定义多个。
public class GenericDemo04 {
public static void main(String[] args) {
GenericMethod<String, Integer> gm = new GenericMethod<String, Integer>();
System.out.println(gm.show(200));
gm.test("ad", 100);
}
}
class GenericMethod<E, T> {
private E e;
private T t;
public GenericMethod() {
super();
}
public GenericMethod(E e, T t) {
super();
this.e = e;
this.t = t;
}
public <X> X show(X x) {
return x;
}
public <K, V> void test(K k, V v) {
System.out.println(k.getClass().getName());
System.out.println(v.getClass().getName());
}
public E getE() {
return e;
}
public void setE(E e) {
this.e = e;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
集合转数组;数组转集合
public class GenericDemo05 {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("a");
c.add("b");
c.add("c");
//将集合转数组
String[] str = c.toArray(new String[] {});
for (String s : str) {
System.out.println(s);
}
//将数组转集合 T[]
Integer[] arr = { 11, 22, 33 };
List<Integer> asList = Arrays.asList(arr);
for (Integer ii : asList) {
System.out.println(ii);
}
}
}
泛型限定符
- <?> 代表任意类型
- <? extends E> 代表泛型可以是E类型或者是E的子类
- <? super T> 代表泛型可以是T类型或是T的父类
泛型嵌套
概述:泛型里面定义泛型
public class GenericDemo07 {
public static void main(String[] args) {
Collection<Student> ac = new ArrayList<Student>();
ac.add(new Student("张三", 30));
ac.add(new Student("李四", 35));
ac.add(new Student("王五", 40));
Collection<Student> bc = new ArrayList<Student>();
bc.add(new Student("赵六", 30));
bc.add(new Student("孙七", 35));
Collection<Student> cc = new ArrayList<Student>();
cc.add(new Student("隔壁老王", 30));
Collection<Collection<Student>> classes = new ArrayList<Collection<Student>>();
classes.add(ac);
classes.add(bc);
classes.add(cc);
/*Iterator<Collection<Student>> iterator = classes.iterator();
while (iterator.hasNext()) {
Collection<Student> c = iterator.next();
Iterator<Student> it = c.iterator();
while (it.hasNext()) {
Student s = it.next();
System.out.println(s.getName() + "|" + s.getAge());
}
}*/
for (Collection<Student> collection : classes) {
for (Student s : collection) {
System.out.println(s.getName() + "|" + s.getAge());
}
}
}
}
集合
集合是一批类,它是一套框架体系。
一:. 集合为什么要设计出这么多类?
集合分为单列集合和双列集合,单列集合类似于数组存储一组数据,双列集合存储具有关系两列数据,并且有很多不同数据结构的子类,所以设计很多类组合而成
二:. 集合顶层父类为什么设计成接口而不设计成普通类?
因为我们认为容器中的元素又不同的特点:
a. 是否有序 【存储有序,怎么样存进去的就怎样出来】
数据结构 【数据的存储方式】
b. 是否唯一
c. 是否可排序
d. 是否安全
针对不同的特点会有不同的实现,那么这个时候父类必须设计成接口,子类根据不同的数据结构和实现方式实现自己的增删查改的功能,所以父类设计为接口
数组和集合的区别
长度
数组的长度固定不变的
集合长度是可以根据实际需要改变
内容
数组存储的是同一种类型的元素
集合可以存储不同类型的元素
数据类型
数组可以存储基本数据类型,也可以存储引用数据类型
集合只能存储引用类型
注意:虽然集合不能存储基本数据类型,但是可以存储基本数据类型的包装类类型
public class CollectionDemo01 {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("老王");
c.add("老李");
c.add("老张");
System.out.println(c);//[老王, 老李, 老张]
c.remove("老李");
System.out.println(c);//[老王, 老张]
Collection<String> c2 = new ArrayList<String>();
c2.add("10");
c2.add("20");
c.addAll(c2);//[老王, 老张, 10, 20]
System.out.println(c);
c.retainAll(c2);//取交集
System.out.println(c);//[10, 20]
}
}
集合的遍历
一: toArray遍历方式:将集合转换成数组进行遍历
二:1. 迭代器遍历:// 通过集合创建迭代器对象
Iterator it = c.iterator();
Foreach遍历集合
Foreach遍历集合的格式:
For(元素类型 元素名 : 集合) {
通过元素名操作元素;
}
-
foreach简化遍历
-
Foreach本质还是使用了迭代器
Object obj;
for (Iterator iterator = c.iterator(); iterator.hasNext(); System.out.println(obj))
obj = iterator.next();
-
Foreach遍历集合和while的区别
(1) Foreach遍历之后就会释放迭代器对象,节约内存
(2) While循环遍历集合可读性更强
并发修改异常
java.util.ConcurrentModificationException
异常名称: 并发修改异常
产生原因: 在遍历迭代器对象元素的同时使用集合对象修改了元素
解决办法:
1.可以遍历原集合并且使用原集合修改 toArray 如果是List接口的子集合还可以使用 普通for 2.使用迭代器遍历并且使用迭代器修改 后期可以使用 ListIterator 进行处理
public class CollectDemo02 { public static void main(String[] args) { Collection<String> c = new ArrayList<String>(); c.add("张三"); c.add("李四"); c.add("王五"); c.add("赵六"); c.add("孙七"); // 需求: 如果集合中存在李四,就删除李四 //遍历原集合并且使用原集合修改 Object[] objs = c.toArray(); for (Object obj : objs) { if (obj.equals("李四")) { c.remove("王五"); } } System.out.println(c); } }
Collection集合去除重复元素
-
创建一个新的集合,然后使用地址传递
(1) 如果比较的是系统类,String 不需要重写equals方法
(2) 如果比较的是自定义对象,需要自己根据需求重写equals方法
-
/*1.创建员工类 (编号 姓名 年龄 工资)
2.使用集合存储 员工 (要求存储重复元素 id编号相同即为重复)
3.遍历集合,输出所有员工信息 (要求至少使用4种遍历方式)
4.去除集合中的重复元素*/
public class CollectionDemo {
public static void main(String[] args) {
Collection c = new ArrayList();
Employee e1 = new Employee("1001", "小李", 20, 5000);
Employee e2 = new Employee("1002", "小王", 20, 4000);
Employee e3 = new Employee("1003", "小张", 22, 6000);
Employee e4 = new Employee("1004", "小孙", 28, 8000);
Employee e5 = new Employee("1001", "小李", 20, 5000);
Employee e6 = new Employee("1002", "小王", 20, 4000);
//往集合添加元素
c.add(e1);
c.add(e2);
c.add(e3);
c.add(e4);
c.add(e5);
c.add(e6);
//循环遍历
//方法一:for循环
Object[] obj = c.toArray();
for (int i = 0; i < obj.length; i++) {
System.out.println(obj[i]);
}
System.out.println("========================");
//方法二:foreach循环
for (Object obj1 : c) {
System.out.println(obj1);
}
System.out.println("========================");
//方法三:while循环
/*
* 有下一个元素,则输出下一个元素
* 没有下一个元素,退出循环
* //创建集合迭代器
*/
Iterator it = c.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println("=========================");
//去除集合中重复的元素
Collection c1 = new ArrayList();
// 遍历旧集合
for (Object obj2 : c) {
//判断新集合是否包含该元素
if (!c1.contains(obj2)) {
//如果不包含的话就添加该元素
c1.add(obj2);
}
}
//地址传递
c = c1;
for (Object obj3 : c) {
System.out.println(obj3);
}
System.out.println("=========================");
c.remove(e2);
c.remove(e3);
for (Object object : c) {
System.out.println(object);
}
System.out.println("=========================");
c.add(new Employee("1008", "老昂", 3985, 18));
for (Object object4 : c) {
System.out.println(object4);
}
}
}
//创建员工类
class Employee {
private String id;
protected String name;
private double salary;
private int age;
public Employee() {
}
public Employee(String id, String name, double salary, int age) {
this.id = id;
this.name = name;
this.salary = salary;
this.age = age;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override//重写equals方法
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}