泛型Generics
一般通过“容器”来容纳和管理数据。程序中的“容器”就是用来容纳和管理数据。
数组就是一种容器,可以在其中放置对象或基本类型数据。
数组的优势:是一种简单的线性序列,可以快速地访问数组元素,效率高。如果从效率和类型检查的角度讲,数组是最好的。
数组的劣势:不灵活。容量需要事先定义好,不能随着需求的变化而扩容。比如:在一个用户管理系统中,要把今天注册的所有用户取出来,那么这样的用户有多少个?在写程序时是无法确定的。因此,在这里就不能使用数组。
容器,也叫集合(Collection)
泛型:可以帮助我们建立类型安全的集合。在使用了泛型的集合中,遍历时不必进行强制类型转换。JDK提供了支持泛型的编译器,将运行时的类型检查提前到了编译时执行,提高了代码可读性和安全性。
泛型的本质就是“数据类型的参数化”。可以把“泛型”理解为数据类型的一个占位符(形式参数),即告诉编译器,在调用泛型时必须传入实际类型。
未使用泛型时:
package cn.dym11;
//测试泛型
public class TestGeneric {
public static void main(String[] args) {
MyCollection mc=new MyCollection();
mc.set("代止兮", 0);
mc.set(8888, 1);
Integer a=(Integer) mc.get(1);
String b=(String) mc.get(0);
}
}
class MyCollection {
Object [] objs=new Object[5];
public void set(Object obj,int index) {
objs[index]=obj;
}
public Object get(int index) {
return objs[index];
}
}
使用泛型:
package cn.dym11;
//测试泛型
public class TestGeneric {
public static void main(String[] args) {
MyCollection<String> mc=new MyCollection<String>();
mc.set("代止兮", 0);
String b=mc.get(0);
}
}
class MyCollection <E> {
Object [] objs=new Object[5];
public void set(E e,int index) {
objs[index]=e;
}
public E get(int index) {
return (E) objs[index];
}
}
自定义泛型、容器中使用泛型
在类的声明处增加泛型列表,如:<T,E,V>
public class Test {
public static void main(String[] args) {
// 以下代码中List、Set、Map、Iterator都是与容器相关的接口;
List<String> list = new ArrayList<String>();
Set<Man> mans = new HashSet<Man>();
Map<Integer, Man> maps = new HashMap<Integer, Man>();
Iterator<Man> iterator = mans.iterator();
}
}
Collection、List、Set、Map、Iterator接口都定义了泛型。
Collection接口
Collection 表示一组对象,它是集中、收集的意思。Collection接口的两个子接口是List、Set接口。
注:由于List、Set是Collection的子接口,意味着所有List、Set的实现类都有上面的方法。
package cn.dym11;
import java.util.ArrayList;
import java.util.Collection;
//测试Collection接口中的方法
public class TestList {
public static void main(String[] args) {
Collection<String> c=new ArrayList<>();
System.out.println(c.size());
System.out.println(c.isEmpty());
c.add("代止兮");
c.add("苍凌");
System.out.println(c);
System.out.println(c.size());
System.out.println(c.contains("苍凌"));
Object[] objs=c.toArray();
System.out.println(objs);
c.remove("苍凌");
System.out.println(c);
c.clear();
System.out.println(c.size());
}
}
package cn.dym11;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
//测试Collection接口中的方法
public class TestList {
public static void main(String[] args) {
test02();
}
public static void test02() {
List<String> list01=new ArrayList <>();
list01.add("aa");
list01.add("bb");
list01.add("cc");
List<String> list02=new ArrayList <>();
list02.add("aa");
list02.add("dd");
list02.add("ee");
System.out.println("list01:"+list01); //list01:[aa, bb, cc]
// list01.addAll(list02);
// System.out.println("list01:"+list01); //list01:[aa, bb, cc, aa, dd, ee]
// list01.removeAll(list02);
// System.out.println("list01:"+list01); //list01:[bb, cc]
list01.retainAll(list02);
System.out.println("list01:"+list01); // list01:[aa]
System.out.println(list01.containsAll(list02));
}
}
List特点和常用方法
List是有序、可重复的容器
有序:List中每个元素都有索引标记。
可重复:List允许加入重复的元素。更确切地讲,List通常允许满足 e1.equals(e2) 的元素重复加入容器。
List接口常用的实现类有3个:ArrayList、LinkedList和Vector
List中操作索引的常用方法
package cn.dym11;
import java.util.ArrayList;
import java.util.List;
public class TsetList01 {
public static void main(String[] args) {
test01();
}
public static void test01(){
List<String> list=new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
System.out.println(list);
list.add(2,"代止兮");
System.out.println(list);
list.remove(2);
System.out.println(list);
list.set(2, "代止兮");
System.out.println(list);
System.out.println(list.get(2));
list.add("C");
list.add("B");
list.add("A");
System.out.println(list);
System.out.println(list.indexOf("B")); //找到,返回索引位置
System.out.println(list.indexOf("d")); //找不到,返回-1
System.out.println(list.lastIndexOf("B"));
}
}
ArrayList特点和底层实现
ArrayList底层是用数组实现的存储。 特点:查询效率高,增删效率低,线程不安全。
ArrayList底层使用Object数组来存储元素数据
数组长度是有限的,而ArrayList是可以存放任意数量的对象,长度不受限制,那么它是怎么实现的呢?本质上就是通过定义新的更大的数组,将旧数组中的内容拷贝到新数组,来实现扩容。
自定义实现一个ArrayList,体会底层原理
第一个版本:
package cn.dym11;
// 自定义实现一个ArrayList,体会底层原理
public class SxtArrayList {
private Object[] elementData;
private int size;
private static final int DEFAULT_CAPACITY=10;
public SxtArrayList() {
elementData=new Object[DEFAULT_CAPACITY];
}
public SxtArrayList(int capacity) {
elementData=new Object[capacity];
}
public void add(Object obj) {
elementData[size++]=obj;
}
public String toString() {
StringBuilder sb=new StringBuilder();
// [a,b,c]
sb.append("[");
// for(Object obj:elementData) {
// sb.append(obj);
// }
// sb.append("]");
for(int i=0;i<size;i++) {
sb.append(elementData[i]+",");
}
sb.setCharAt(sb.length()-1, ']');
return sb.toString();
}
public static void main(String[] args) {
SxtArrayList s1=new SxtArrayList(20);
s1.add("aa");
s1.add("bb");
System.out.println(s1);
}
}
//增加泛型
//增加数组扩容
package cn.dym11;
// 自定义实现一个ArrayList,体会底层原理
//增加泛型
//增加数组扩容
public class SxtArrayList02<E> {
private Object[] elementData;
private int size;
private static final int DEFAULT_CAPACITY=10;
public SxtArrayList02() {
elementData=new Object[DEFAULT_CAPACITY];
}
public SxtArrayList02(int capacity) {
elementData=new Object[capacity];
}
public void add(E element) {
// 什么时候扩容??
if(size==elementData.length) {
//怎么扩容?? //扩容操作
Object[] newArray=new Object[elementData.length+(elementData.length>>1)];
System.arraycopy(elementData, 0, newArray, 0,elementData.length );
elementData=newArray;
}
elementData[size++]=element;
}
public String toString() {
StringBuilder sb=new StringBuilder();
// [a,b,c]
sb.append("[");
// for(Object obj:elementData) {
// sb.append(obj);
// }
// sb.append("]");
for(int i=0;i<size;i++) {
sb.append(elementData[i]+",");
}
sb.setCharAt(sb.length()-1, ']');
return sb.toString();
}
public static void main(String[] args) {
SxtArrayList02 s1=new SxtArrayList02(20);
for(int i=0;i<40;i++) {
s1.add("dym"+i);
}
System.out.println(s1);
}
}