目录
1 集合
1.1集合的框架体系
1): 集合主要是两组(单列集合 , 双列集合)
2):Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合
3): Map 接口的实现子类 是双列集合,存放的 K-V
1.2 Collection接口的常用方法
1):Collection实现子类可以存放多个元素,每个元素是Object
2):部分Collection的实现类,可以存放重复元素,有些不可以
3):部分Collection的实现类,有些是有序的,有些无序
4):Collection接口没有直接的实现子类,是通过它的子接口List和Set来实现的
5):add(),添加单个元素
6):remove(),删除指定元素
7):contains(),查找元素是否存在
8):size(),获取元素个数
9):isEmpty(),判断是否为空
10):clear(),清空
11):addAll(集合),添加多个元素
12):containsAll(集合),查找多个元素是否都存在
13):removeAll(集合),删除多个元素
public class Collection_ {
public static void main(String[] args) {
//以ArrarList为例
List list = new ArrayList();
// add:添加单个元素
list.add("jack");
list.add(0);//
// 自动装箱list.add(new Integer(10))
list.add(true);
System.out.println("list=" + list);
// remove:删除指定元素
//list.remove(0);删除第一个元素,输入数字就是删除的指定下标的元素
Integer integer = 0;
list.remove(integer);//指定删除某个元素
System.out.println("list=" + list);
// contains:查找元素是否存在
System.out.println(list.contains("jack"));//T
// size:获取元素个数
System.out.println(list.size());//2
//isEmpty:判断是否为空
System.out.println(list.isEmpty());//F
// clear:清空
list.clear();
System.out.println("list=" + list);
// addAll:添加多个元素
ArrayList list2 = new ArrayList();
list2.add("红楼梦");
list2.add("三国演义");
list.addAll(list2);
System.out.println("list=" + list);
// containsAll:查找多个元素是否都存在
System.out.println(list.containsAll(list2));//T
list.add("聊斋");
// removeAll:删除多个元素
list.removeAll(list2);
System.out.println("list=" + list);//[聊斋]
// 说明:以 ArrayList 实现
}
}
1.3 迭代器遍历
1):Collection接口遍历元素方式1-使用Iterator(迭代器)
2):Iterator对象称为迭代器,主要用于遍历Collection集合中元素
3):所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,既可以返回一个迭代器
4):Iterator仅用于遍历集合,Iterator本身并不存放对象
5):Iterator接口的方法,hasNext():判断是否还有下一个对象;next():指针下下移,返回对象,先调用hasNext(),再调用next(),快捷键itit
6):如果希望再次遍历,需要重置迭代器iterator = col.iterator();
7):增强for是简化版本的,输入I快捷键
public class Iterator_ {
public static void main(String[] args) {
ArrayList col = new ArrayList();
col.add(new Book("三国演义", "罗贯中", 10));
col.add(new Book("小李飞刀", "古龙", 5));
col.add(new Book("红楼梦", "曹雪芹", 34));
//现在希望能够遍历 col 集合
//1. 先得到 col 对应的 迭代器
Iterator iterator = col.iterator();
//2. 使用 while 循环遍历
// while (iterator.hasNext()) {//判断是否还有数据
//返回下一个元素,类型是 Object
// Object obj = iterator.next();
// System.out.println("obj=" + obj);
// }
//快速生成 while->itit
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println("obj:"+next);
}
//再次使用,需要重置迭代器
iterator = col.iterator();
//增强for循环
for(Object book:col)
{
System.out.println(book);
}
}
}
class Book{
private String name;
private String auther;
private int price;
public Book(String name, String auther, int price) {
this.name = name;
this.auther = auther;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuther() {
return auther;
}
public void setAuther(String auther) {
this.auther = auther;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", auther='" + auther + '\'' +
", price=" + price +
'}';
}
}
2 List接口
2.1 List接口和常用方法
List接口是Collection接口的子接口
1):List集合类中元素有序(添加顺序和取出顺序一致),且可重复
2):List集合中的每个元素都有其对应的顺序索引,即支持索引
3):List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
4):List接口的实现类有,ArraryLis、LinkedList和Vector
5):add(int,object),在int位置插入元素或直接在末尾插入元素
6):add(int,Collection),在int位置将集合插入进去
7):get(int),获得int位置处的元素,从0开始
8):indexOf(Object),返回元素在集合中首次出现的位置
9):lastIndexOf(Object),返回元素在集合中最后一次出现的位置
10):remove(int),移除指定int位置的元素
11):set(int,Object),设置指定int位置的元素为Object,替换
12):subList(int,int),返回指定序列的子集合
public class List_ {
public static void main(String[] args) {
//1. List 集合类中元素有序(即添加顺序和取出顺序一致)、且可重复 [案例]
List list1 = new ArrayList();
list1.add("jack");
list1.add("tom");
List list2 = new ArrayList();
list2.add(222);
list2.add(222);
//2. List 集合中的每个元素都有其对应的顺序索引,即支持索引
// 索引是从 0 开始的
System.out.println("get():"+list2.get(1));//tom
System.out.println(list1.addAll(list2));
System.out.println("list1添加了list2:"+list1);
System.out.println(list1.indexOf("tom"));
//int:移除指定下标的元素,Object:删除对应的元素,只删除一次
System.out.println("remove前"+list2);
System.out.println(list2.remove((Integer)222));
System.out.println("remove后"+list2);
//替换,索引必须存在
System.out.println(list1.set(0,"4"));
System.out.println(list1);
//int1<=sublist<int2
System.out.println(list1.subList(1,3));
}
}
13):练习
public class Exercise {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add(new Book("红楼梦","曹雪芹",156));
arrayList.add(new Book("西游记","吴承恩",46));
arrayList.add(new Book("水浒传","施耐庵",96));
arrayList.add(new Book("三国演义","罗贯中",36));
sort(arrayList);
for(Object ob:arrayList){
System.out.println("输出"+ob);
}
}
public static List sort(List list){
int len=list.size();
for (int i = 0; i < len-1; i++) {//比较的轮数
for (int j=0;j<len-1-i;j++){//一轮中比较的次数
Book book1=(Book) list.get(j);
Book book2=(Book) list.get(j+1);
if(book1.getPrice()>book2.getPrice()){
list.set(j,book2);
list.set(j+1,book1);
}
}
}
return list;
}
}
class Book{
private String name;
private String auther;
private int price;
public Book(String name, String auther, int price) {
this.name = name;
this.auther = auther;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuther() {
return auther;
}
public void setAuther(String auther) {
this.auther = auther;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "名称:" +
"name='" + name + '\'' +
", auther='" + auther + '\'' +
", price=" + price ;
}
}
2.2 ArrayList 分析
1):ArrayList可以加入null,并且可以多个
2):ArrayList是由数组来实现数据存储的
3):ArrayList基本等同于Vector,ArrayList是线程不安全的(但执行效率高),多线程不要使用
4):ArrayList中维护了一个Object类型的数组elementData
5):当创建对象时,如果使用的是无参构造器,则初始化elementData容量为0
6):当添加元素时,先判断是否需要扩容,如果需要,则调用grow(),否则直接添加元素到合适位置
7):如果使用的是无参构造器,如果第一次添加,则扩容elementData为10,如果需要再次扩容,则扩容为elementData的1.5倍
8):如果使用的是指定容量capacity的构造器,则初始elementData容量为capacity
9):如果使用的是指定容量capacity的构造器,如果需要扩容,则直接扩容elementData为1.5倍
2.3 Vector类
1):Vector底层是一个对象数组,protected Object[] elementData
2):Vector是线程同步的,即线程安全,开发中,需要线程同步安全时,优先考虑使用Vector
3):如果使用的是无参构造器,默认10,后面按照2倍扩容
4):如果指定大小,则直接按2倍扩容
2.4 LinkedList类
1):LinkedList底层实现了双向链表和双端队列特点
2):可以添加任意元素(元素可以重复),包括null
3):线程不安全,没有实现同步
4):LinkedList中维护了两个属性first和last分别指向首节点和尾节点
5):每个节点(Node对象),里面又维护了prev、next、item三个属性,prev指向前一个、next指向后一个节点,最终实现双向链表
6):LinkedList元素的添加和删除不是通过数组来完成的,所以效率较高
7):单线程时:如果改查较多选择ArrayList,增删较多选择LinkedList,一般都是改查较多
3 Set
3.1 Set接口和常用方法
和List一样是Collection的子接口,因此,常用方法和它一样
1):无序(添加和取出顺序不一致),但是取出顺序固定,没有索引
2):不允许重复元素,所以最多包含一个null
3):Set接口的实现类有:HashSet、TreeSet...
4):Set不能通过索引获取,只能用迭代器和增强for获得
3.2 HashSet
1): HashSet实现了Set,第一次添加时系统扩容到16,阙值为12(0.75),到达阙值二倍扩容
2): HashSet实际上是 HashMap,table(数组)中每个元素对应一个链表(hash值相同的但是内容不同的)
3):可以存null,只能有一个
4): HashSet无序,不保证元素跟存入时的顺序一致,取决于hash后,在确定索引的结果
5):不能有重复元素
6):HashSet添加一个元素时,先得到hash值-会转成->索引值
7):HashSet找到存储数据表table,看这个索引位置是否已经存放元素
8):如果有,调用equals比较,相同放弃添加,不相同添加到最后
9):在jdk8中,如果一条链表的元素个数到达默认值8,并且table大于等于64,就会进行树化(红黑树)
public class Set_ {
public static void main(String[] args) {
Set hashSet = new HashSet();
hashSet.add(55);
hashSet.add(66);
hashSet.add(null);
hashSet.add(55);
System.out.println(hashSet);//取出顺序固定,但不是开始存入的顺序,不存放重复元素,可以添加null
hashSet=new HashSet();
hashSet.add(new Dog("tom"));//ok
hashSet.add(new Dog("tom"));//ok
hashSet.add(new String("hsp"));//ok
hashSet.add(new String("hsp"));//加入不了.
System.out.println("set=" + hashSet);
}
}
class Dog{
private String name;
public Dog(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
'}';
}
}
10):练习
public class Exercise {
public static void main(String[] args) {
/*定义一个 Employee 类,该类包含:private 成员属性 name,age 要求:
创建 3 个 Employee 对象放入 HashSet 中
当 name 和 age 的值相同时,认为是相同员工, 不能添加到 java.util.HashSet 集合*/
//加入时,先比较code再调用equals
HashSet hashSet = new HashSet();
hashSet.add(new Person("lll",20));
hashSet.add(new Person("www",19));
hashSet.add(new Person("lll",20));//修改equals()和hashCode()后不可以添加相同的
System.out.println(hashSet);
}
}
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
11):练习2,当A要修改code值和equals()包含B类时,A类中的属性类型是B类,B类也要修改code值和equals(),因为A类需要根据比较属性的hash返回不同的hash值,A类中的属性类型有B类,即B类要根据内容比较返回不同的hash值,否则如果不重写hashCode()相同内容由于new的原因,返回的是不同的hash值,B类的内容相同却返回了不同的hash值,导致A连锁反应,两个A对象内容相同hash值却不同,导致错误的成功添加到HashSet。equals()同理,hash相同则在同一个链表然后调用equals(),如果B类不重写equals(),导致A连锁,相同内容equals()返回false,最后导致两个A对象内容相同却可以成功添加到HashSet。
public class Exercise2 {
public static void main(String[] args) {
//定义一个Employee类,该类包含:private成员属性name,sal,birthday(MyDate类型),
//其中 birthday 为 MyDate类型(属性包括:year, month, day),要求:
//当 name 和 age 的值相同时,认为是相同员工, 不能添加到 HashSet
HashSet hashSet = new HashSet();
hashSet.add(new Employee("jeff",520,new MyDate(2002,10,7)));
hashSet.add(new Employee("jeff",820,new MyDate(2002,10,7)));
System.out.println(hashSet);
}
}
class Employee{
private String name;
private double sal;
private MyDate date;
public Employee(String name, double sal, MyDate date) {
this.name = name;
this.sal = sal;
this.date = date;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return Objects.equals(name, employee.name) && Objects.equals(date, employee.date);
}
@Override
public int hashCode() {
return Objects.hash(name, date);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", sal=" + sal +
", date=" + date +
'}';
}
}
class MyDate{
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
@Override
public String toString() {
return year + "- " + month + "-" + day ;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyDate myDate = (MyDate) o;
return year == myDate.year && month == myDate.month && day == myDate.day;
}
@Override
public int hashCode() {
return Objects.hash(year, month, day);
}
}
3.3 LinkedHashSet
1):LinkedHashSet是HashSet的子类
2):LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表
3):LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,这使元素看起来是以插入顺序保存的
4):LinkedHashSet不允许添重复元素
5):在LinkedHastSet中维护了一个hash表和双向链表(LinkedHashSet有head和tail)
6):每一个节点有pre和next属性,这样可以形成双向链表
7):在添加一个元素时,先求hash值,在求索引.,确定该元素在hashtable的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加[原则和hashset一样])
8):tail.next = newElement;newElement.pre = tail;tail = newEelment;这样就形成了双向链表,使元素顺序跟加入时的顺序一致
9):添加第一次时,直接将table扩容到16
3.4 TreeSet
1):使用无参构造器创建时,仍然是无序的,以添加的对象实现的Comparable接口的compareTo()方法去重,后面添加时如果添加的对象A没有实现Comparable接口则报错,因为底层会把对象A转成Comparable
2):使用TreeSet提供的一个构造器,可以传入一个比较器去重
public class TreeSet_ {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();//实际上是调用String的compareTo方法进行遍历比较
treeSet.add("r");
treeSet.add("r");
System.out.println(treeSet);
}
}
public class TreeSet_ {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//调用String的compareTo()进行比较,从首字母开始比较
return (((String)o1).length()-((String) o2).length());
}
});//return 0的时候数据不会加入进去,规则的设置会导致=0的数据加不进去
treeSet.add("aaa");
treeSet.add("r");
treeSet.add("rrr");//无法加入,以长度为比较器加入
System.out.println(treeSet);
}
}
4 Map
4.1 Map接口和常用方法
1):Map和Collection接口并列存在,用于保存具有隐射关系的数据Key-Value
2):Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
3):Map中的key不允许重复(Set),原因和HashSet一样,code和equals
4):Map中的value可以重复(Collection)
5):Map中的key和value都可以为null
6):常用String类作为Map的key
7):key和value之间存在单向一对一关系,即通过指定key总的找到对应的value
8):Map存放数据,一对K-V是放在一个HashMap$Node(table表【数组+单向链表+红黑树(64)】)中的,是因为Node实现了Entry接口,有些书上也说,一对K-V就是一对Entry(为了遍历方便所以EntrySet指向table中的真正的数据)
9):put(),添加
10):remove(),根据键删除映射关系
11):get(),根据键获取值
12):size(),获取元素个数
13):isEmpty(),判断个数是否为空
14):clear(),清除
15):containsKey(),查找键是否存在
16):HashMap(),线程不安全
public class Map_ {
public static void main(String[] args) {
HashMap hashMap = new HashMap();
hashMap.put("k01","赵露丝");
hashMap.put("k01","替换");
hashMap.put("k02","");
hashMap.put("","杨幂");
hashMap.put(3,"杨幂");
hashMap.put("k04","鞠婧祎");
//无序,key不能重复,key重复了就替换,key、value都可以为null
System.out.println(hashMap);
//get(),根据key的值返回value
System.out.println(hashMap.get("k03"));
//删除对应的key和value,返回key对应移除的value
System.out.println(hashMap.remove("k01"));
System.out.println(hashMap);
System.out.println(hashMap.size());
System.out.println(hashMap.isEmpty());
System.out.println(hashMap.containsKey("k04"));
hashMap.clear();
System.out.println(hashMap);
}
}
4.2 Map的遍历方法
1):keySet(),获取所有的键
2):entrySet(),获取所有关系
3):values(),获取所有的值
//遍历方式1 KeySet
Set keyset=hashMap.keySet();
System.out.println("-----------方法一增强for--------");
for(Object obj:keyset){
System.out.println(obj+"++"+hashMap.get(obj));
}
System.out.println("-----------方法一迭代器--------");
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next+"++"+hashMap.get(next));
}
//遍历方法2
System.out.println("-----------方法二取出所有的value--------");
Collection values = hashMap.values();
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()) {
Object next = iterator1.next();
System.out.println("只能取出value"+next);
}
//遍历方法3,EntrySet
System.out.println("-----------方法三增强for--------");
Set set = hashMap.entrySet();
for (Object o:set){
Map.Entry m=(Map.Entry)o;
System.out.println(m.getKey()+"-"+m.getValue());
}
System.out.println("-----------方法三迭代器--------");
Iterator iterator2 = set.iterator();
while (iterator2.hasNext()) {
Object next = iterator2.next();
Map.Entry m=(Map.Entry)next;
System.out.println(m.getKey()+"-"+m.getValue());
}
4.3 HashMap
1):HashMap底层维护了Node类型的数组table,默认值为null
2):当创建对象时,将加载因子(loadfactor)初始化为0.75,初始化Node类型的数组table
3):当添加key-val时,通过key的哈希值得到在table的索引,然后判断该索引处是否有元素,如果没有元素直接添加,如果该索引处有元素,继续判断该元素的key是否和准备加入的key相等,如果相等,则直接替换val;如果不相等(key不相等hash相等)和后面的继续比较、有相等的替换然后break不相等加在后面,需要判断是树结构还是链表结构,做出相应的处理(链表:则调用equals循环比较都不相等则加在后面,有相等的则进行替换),如果添加时发现容量不够则扩容
4):第一次添加,需要扩容table容量为16,临界值(threshold)为12,到了临界值就扩容
5):以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的2倍,以此类推
6):在Java8中,如果一条链表的元素超过8(TREEIFY_THRESHOLD)并且table>=64(MIN_TREEIFY_CAPACITY)就会进行树化
4.4 Hashtable
1):存放的元素是键值对即K-V
2):Hashtable的键和值都不能为null
3):Hashtable使用方法基本上和HashMap一样
4):Hashtable是线程安全的
5):底层有数组Hashtable$Entry[]初始化大小为11,临界值是11*0.75=8
6):扩容:到了临界值扩容(例如到了8个则扩容到23),扩容到原来的2倍+1
4.5 Properties
1):Properties类继承Hashtable类并实现了Map接口,也是使用键值对的形式来保存数据
2):Properties的使用特点和Hashtable类似,key和value不能为null,相同的键替换
3):Properties还可用于xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改
4):工作后 xxx.properties文件通常作为配置文件
4.6 TreeMap
1):使用默认构造器创建TreeMap无序
2):使用传入比较器的构造器创建,可以指定规则有序
5 开发中如何选择集合实现类
1):先判断存储类型-一组对象还是一组键值对
2):一组对象Collection接口,
允许重复:List【有序】
增删多:LinkedList[底层维护了一个双向链表]
改查多:ArrayList[底层维护Object类型的可变数组]
不允许重复:Set
无序:HashSet[底层是HashMap,维护了一个哈希表,数组+链表+红黑树]
排序:TreeSet
插入和取出顺序一致:LinkedHashSet,维护数组+双向链表
3):一组键值对:Map
键无序:HashMap[底层是:哈希表 数组+链表+红黑树]
键排序:TreeMap
键插入和取出顺序一致:LinkedHashMap
读取文件:Properties
6 Collections工具类
6.1 Collections工具类介绍
1):Collections工具类是一个操作Set、List和Map等集合的工具类
2):Collections工具类中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作
6.2 排序操作
1):reverse(List),反转List中元素的顺序
2):shuffle(List),对List集合元素进行随机排序
3):sort(List),根据元素的自然顺序对指定List集合元素按升序排序
4):sort(List,Comparator),根据指定的Comparator产生的顺序对List集合进行排序
5):swap(List,int,int),将指定List集合中的i处元素和j处元素进行交换
6.3 查找操作
1): Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
2):Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
3):Object min(Collection)
4):Object min(Collection,Comparator)
5): int frequency(Collection,Object):返回指定集合中指定元素的出现次
数
6):void copy(List dest,List src):将src中的内容复制到dest中,我们需要先给 dest 赋值,大小和 list.size()一样
7):boolean replaceAll(List list,Object oldVal,Object newVal):使用
新值替换List对象的所有旧值
7 泛型
7.1 泛型引入
1): 当我们 ArrayList 表示存放到 ArrayList 集合中的元素是 Dog 类型 (细节后面说...)
2): 如果编译器发现添加的类型,不满足要求,就会报错
3): 在遍历的时候,用增强for循环可以直接取出 Dog 类型而不是 Object,for(Dog o:arraylist)
4): public class ArrayList<E> {} E 称为泛型,那么 Dog->E
ArrayList<Dog> arrayList = new ArrayList<Dog>();
arrayList.add(new Dog("旺财", 10));
arrayList.add(new Dog("发财", 1));
arrayList.add(new Dog("小黄", 5)
//arrayList.add(new Cat("招财猫", 8));报错
System.out.println("===使用泛型====");
for (Dog dog : arrayList) {
System.out.println(dog.getName() + "-" + dog.getAge());
7.2 泛型介绍
泛型:广泛的类型,表示引用数据类型的类型,E ->Integer、String、Dog.....不可以是int....等基本数据类型
1):泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题
2):在类声明或实例化时只要指定好需要的具体的类型即可。ArrayList<Dog> arrayList
3):Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮
4):泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方
法的返回值的类型,或者是参数类型。
5):在编译期间,就确定 E 是什么类型
Person<Integer> person2 = new Person<Integer>("hahha");
//则Person类里面所有的E都是String了
class Person<E> {
E s ;
//E 表示 s 的数据类型, 该数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E 是什么类型
public Person(E s) {//E 也可以是参数类型
this.s = s;
}
public E f() {//返回类型使用 E
return s;
}
}
7.3 泛型的语法
interface 接口名<T>{}
class 类名<K,V>{}
1):其中T,K,V都不代表值,而是表示引用类型
2):任意字母都可以,常用T
3):泛型的实例化,要在类名后面指定类型参数的值(类型)
eg:lterator<Customer> iterator = customers.iterator();
4):在指定泛型具体类型后,可以传入该类型或者其子类类型
5):如果没有传入泛型类型,默认是Object,ArrayList arrayList = new ArrayList();等价 ArrayListarrayList = new ArrayList();
6):泛型的使用形式可以简写,例如ArrayList<Integer> list3 = new ArrayList<>(); 编译器会进行类型推断
7):exercise
public class Generic_ {
public static void main(String[] args) {
/**
* 定义 Employee 类
* 1) 该类包含:private 成员变量 name,sal,birthday,其中 birthday 为 MyDate 类的对象;
* 2) 为每一个属性定义 getter, setter 方法;
* 3) 重写 toString 方法输出 name, sal, birthday
* 4) MyDate 类包含: private 成员变量 month,day,year;并为每一个属性定义 getter, setter 方法;
* 5) 创建该类的 3 个对象,并把这些对象放入 ArrayList 集合中(ArrayList 需使用泛型来定义),对集合中的元素进
行排序,并遍历输出:
*
* 排序方式: 调用 ArrayList 的 sort 方法 , * 传入 Comparator 对象[使用泛型],先按照 name 排序,如果 name 相同,则按生日日期的先后排序。【即:定制排序】
*/
ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee("tom", 20000, new MyDate(1980,12,11)));
employees.add(new Employee("jack", 12000, new MyDate(2001,12,12)));
employees.add(new Employee("tom", 50000, new MyDate(1980,12,10)));
System.out.println(employees);
Collections.sort(employees, new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
int i1= o1.getName().compareTo(o2.getName());
if (i1!=0){
return i1;
}
return o1.getBirthday().compareTo(o2.getBirthday());
}
});
System.out.println("排序后\n"+employees);
}
}
class Employee{
private String name;
private double sal;
private MyDate birthday;
public Employee(String name, double sal, MyDate birthday) {
this.name = name;
this.sal = sal;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", sal=" + sal +
", birthday=" + birthday +
'}';
}
}
class MyDate implements Comparable<MyDate>{
private int year;
private int month ;
private int day ;
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
@Override
public String toString() {
return year +
"-" + month +
"-" + day;
}
@Override
public int compareTo(MyDate o) {
int yearMinus=year-o.getYear();
int monthMinus=month-o.month;
int dayMinus=day-o.day;
if(yearMinus!=0){
return yearMinus;
}
if(monthMinus!=0){
return monthMinus;
}
return dayMinus;
}
}
7.4 自定义泛型类
自定义泛型属性只能在泛型接口和泛型类中
1):基本语法
class 类名<T,R...>{//可以有多个泛型
成员
}
把这种称为自定义泛型类
2):普通成员可以使用泛型(属性、方法)
3):使用泛型的数组不能初始化(数组在new的时候不知道类型没办法开空间)
4):静态方法中不能使用类的泛型(静态跟类相关,类加载时对象还没有创建,JVM不知道静态是什么类型)
5):泛型类的类型,是在创建对象时指定的
6):如果在创建对象时没有指定类型,默认为Object
7.5 自定义接口
1):基本语法
interface 接口名<T,R...>{//可以有多个泛型
成员
}
2):静态成员不能使用泛型
3):泛型接口的类型在继承接口或者实现接口时确定
3):没有指定类型默认为Object
7.6 自定义泛型方法
1):基本语法
修饰符 <T,R...> 返回类型 方法名(参数列表){
}
2):泛型方法可以定义在普通类中,也可以定义在泛型类中
3):当泛型方法被调用时,传入参数,类型就会被确定
4):public void print(E e){}是使用了泛型不是泛型方法
5):泛型方法可以使用类声明的泛型,也可以使用方法中声明的泛型
class Fish<E>{ E e; public <T> void print(T t,E e){ }; }
7.7 泛型的继承和通配符
1):泛型不具备继承性
2):<?>:跟在有类型型参的类或接口后面,表示支持任意泛型类型,例如:List<?> e表示可以接受类型型参为任意的List
3):<? extends A>:支持A类以及A类的子类,规定了泛型的上限
4):<? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限
8 JUnit的使用
1):JUnit是一个java语言的单元测试框架
2):多数java的开发环境已经集成了JUnit作为单元测试的工具
3):在需要测试的方法前加@Test,点击绿色小箭头运行方法(光标放在对应的方法处快捷键也可以运行)