72.泛型
(1)概念
泛型就是在集合中指定存储的数据类型,而且只能存储这种类型,在List<类型>必须要指定, ArrayList<>可以指定也可以不指定。基本数据类不能作为泛型。
import java.util.ArrayList;import java.util.List;import java.util.ListIterator;public class Generic { public static void main(String[] args) { //指定集合中只能存储一种数据类型 Listlist = new ArrayList<>(); Person p=new Person("frank",12); Person p1=new Person("lisa",11); list.add(p); list.add(p1); List list1 = new ArrayList<>(); //age的int类型自动转成Integer类型 Student s=new Student("david",11,1); Student s1=new Student("mia",12,2); //指定存储person的集合中可以存储指定类型和它的子类 list1.add(s); list1.add(s1); //指定存储person的集合中可以存储指定类型和存储它的子类的子集合 list.addAll(list1); 创建一个迭代器对象 ListIterator personListIterator = list.listIterator(); while(personListIterator.hasNext()){ //获得到Person型 Person next = personListIterator.next(); System.out.println(next); } }}
(2)自定义泛型
在自定义泛型时
语法:class/interface 类名/接口名 <T>{
}
T只是泛型的一个标准,使用什么字符都可以,但是都要大写,不要使用特殊字符,建议用T
自定义泛型类
public class GenericClass{ //定义一个泛型的属性 private T t; public T getT() { return t; } public void setT(T t) { this.t = t; }}
public class GenericClass1{ //定义三个泛型的属性 private T t; private E e; private Z z; public T getT() { return t; } public void setT(T t) { this.t = t; } public E getE() { return e; } public void setE(E e) { this.e = e; } public Z getZ() { return z; } public void setZ(Z z) { this.z = z; } @Override public String toString() { return "GenericClass1{" + "t=" + t + ", e=" + e + ", z=" + z + '}'; }}
import java.util.Arrays;import java.util.Date;public class GenericTest { public static void main(String[] args) { //指定泛型是String GenericClassg = new GenericClass<>(); g.setT("eric"); System.out.println(g.getT()); //指定泛型是Integer GenericClass g1 = new GenericClass<>(); g1.setT(12); System.out.println(g1.getT()); //指定泛型是Integer数组 GenericClass g2 = new GenericClass<>(); g2.setT(new Integer[]{1,2,3}); System.out.println(Arrays.toString(g2.getT())); //测试3个泛型 GenericClass1 g3 = new GenericClass1<>(); g3.setT(new Person("milk",12)); g3.setE(1); g3.setZ(new Date()); System.out.println(g3); }}
73.增强for循环
在Jdk1.5以后出现了增强的for
对数组,集合来做遍历
语法:
for(数据类型 变量:集合变量){
///
}
数据类型是集合或者数组中的数的类型
import java.util.ArrayList;import java.util.List;public class ForDemo { public static void main(String[] args) { String[] str={"pop","qoq","mom","bob"}; System.out.println("-------------数组遍历----------------"); for (String s : str) { System.out.println(s); } Listlist=new ArrayList<>(); list.add("pop"); list.add("bop"); list.add("pop"); list.add("pop"); System.out.println("-------------集合遍历----------------"); for (String s : list) { System.out.println(s); if(s.equals("bop")){ s="bob"; } } System.out.println("-------------普通for循环遍历----------------"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); if(list.get(i).equals("bop")){ list.add("mom"); } } }}
增强的for循环遍历不支持并发,不可以增加或者删除改变集合或者数组的长度会出现异常报错,但是可以对某个成分进行更改,编译运行灭有出现错误,但是对结果却没有任何影响
普通的for循环可以实现并发
74.Set接口
一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2)
的元素对 e1
和 e2
,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。
在所有构造方法以及 add、equals 和 hashCode 方法的协定上,Set 接口还加入了其他规定,这些规定超出了从 Collection 接口所继承的内容。出于方便考虑,它还包括了其他继承方法的声明(这些声明的规范已经专门针对 Set 接口进行了修改,但是没有包含任何其他的规定)。
对这些构造方法的其他规定是(不要奇怪),所有构造方法必须创建一个不包含重复元素的 set(正如上面所定义的)。
注:如果将可变对象用作 set 元素,那么必须极其小心。如果对象是 set 中某个元素,以一种影响 equals 比较的方式改变对象的值,那么 set 的行为就是不确定的。此项禁止的一个特殊情况是不允许某个 set 包含其自身作为元素。
某些 set 实现对其所包含的元素有所限制。例如,某些实现禁止 null 元素,而某些则对其元素的类型所有限制。试图添加不合格的元素会抛出未经检查的异常,通常是 NullPointerException 或 ClassCastException。试图查询不合格的元素是否存在可能会抛出异常,也可能简单地返回 false;某些实现会采用前一种行为,而某些则采用后者。概括地说,试图对不合格元素执行操作时,如果完成该操作后不会导致在 set 中插入不合格的元素,则该操作可能抛出一个异常,也可能成功,这取决于实现的选择。此接口的规范中将这样的异常标记为“可选”。
(1)HashSet
此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
此类为基本操作提供了稳定性能,这些基本操作包括 add、remove、contains 和 size,假定哈希函数将这些元素正确地分布在桶中。对此 set 进行迭代所需的时间与 HashSet 实例的大小(元素的数量)和底层 HashMap 实例(桶的数量)的“容量”的和成比例。因此,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。
注意,此实现不是同步的。如果多个线程同时访问一个哈希 set,而其中至少一个线程修改了该 set,那么它必须 保持外部同步。这通常是通过对自然封装该 set 的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet
方法来“包装” set。最好在创建时完成这一操作,以防止对该 set 进行意外的不同步访问:
Set s = Collections.synchronizedSet(new HashSet(...));
此类的 iterator 方法返回的迭代器是快速失败 的:在创建迭代器之后,如果对 set 进行修改,除非通过迭代器自身的 remove 方法,否则在任何时间以任何方式对其进行修改,Iterator 都将抛出 ConcurrentModificationException
。因此,面对并发的修改,迭代器很快就会完全失败,而不冒将来在某个不确定时间发生任意不确定行为的风险。
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器在尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误做法:迭代器的快速失败行为应该仅用于检测 bug。
特点:
1.元素唯一性
2.无序行
3.允许null存在一个
4.不是线程安全(效率高)
import java.util.HashSet;import java.util.Set;public class SetTest { public static void main(String[] args) { Setset=new HashSet<>(); set.add("玉米"); set.add("花生"); set.add(null); set.add(null); System.out.println(set); }}
探究唯一性:
如果对象的hash值和equals都相等那么就是重复的对象。
import java.util.HashSet;public class SetTest1 { public static void main(String[] args) { HashSeth=new HashSet<>(); h.add(new Person("Bob",12)); h.add(new Person("Vob",12)); h.add(new Person("Sob",12)); h.add(new Person("Bob",12)); System.out.println(h); }}
(2)LinkedHashSet
有顺序但是应用的不多
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。注意,插入顺序不 受在 set 中重新插入的 元素的影响。(如果在 s.contains(e) 返回 true 后立即调用 s.add(e),则元素 e 会被重新插入到 set s 中。)
(3)TreeSet
字符串的比较规则是先按照第一个字符来比较,如果一个字符串的第一个字符比另一个字符串首字符大,那前者大。
compareTo方法返回的是整数即是前者大,返回负数是后者大,是0就是相等
类如果要实现比较的规则都会实现Comparable接口。可以重写compareTo方法自定义比较规则
public class Person implements Comparable{ private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Person(String name, Integer age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override public int compareTo(Object o) { int flag=1; if(o instanceof Person) { Person p=(Person)o; flag=this.age-p.age; if(flag==0){ flag=this.name.compareTo(p.name); } } return flag; }}
public class CompareToTest1 { public static void main(String[] args) { Person p=new Person("Abi",8); Person p1=new Person("Jinx",9); System.out.println( p.compareTo(p1)); }}
TreeSet的特点:
1.元素唯一性
2.可自定义排序的(所存储的对象必须实现Comparable接口覆写compareTo方法)
3.不允许null存在(每次添加都会作比较的)
4.不是线程安全
基于 TreeMap
的 NavigableSet
实现。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator
进行排序,具体取决于使用的构造方法。
此实现为基本操作(add
、remove
和 contains
)提供受保证的 log(n) 时间开销。
注意,如果要正确实现 Set
接口,则 set 维护的顺序(无论是否提供了显式比较器)必须与 equals 一致。(关于与 equals 一致 的精确定义,请参阅 Comparable
或 Comparator
。)这是因为 Set
接口是按照 equals
操作定义的,但 TreeSet
实例使用它的 compareTo
(或 compare
)方法对所有元素进行比较,因此从 set 的观点来看,此方法认为相等的两个元素就是相等的。即使 set 的顺序与 equals 不一致,其行为也是 定义良好的;它只是违背了 Set
接口的常规协定。
public class Student extends Person { public Student(String name, Integer age) { super(name, age); } private Integer stuNo; public Integer getStuNo() { return stuNo; } public void setStuNo(Integer stuNo) { this.stuNo = stuNo; } public Student(String name, Integer age, Integer stuNo) { super(name, age); this.stuNo = stuNo; } @Override public String toString() { return "Student{" + super.toString()+ "stuNo=" + stuNo + '}'; }}
import java.util.Set;import java.util.TreeSet;public class TreeSetTest { public static void main(String[] args) { Person p=new Person("Abi",8); Person p1=new Person("Jinx",10); Student s=new Student("Mia",9,2); Setset= new TreeSet<>(); set.add(p); set.add(p1); set.add(s); System.out.println(set); }}
75.可变参数
可变参数定义的语法:数据类型...变量名
可以代表数组或者单个数的传递
可变参数方法的语法:
修饰符 返回值类型 方法名(数据类型...变量名){
}
如果调用的时候发现有正好可以匹配的方法就不会调用可变参数方法,如果调用方法的时候不存在正好匹配的方法则调用可变参数方法
public class DynamicParam { public int add(int...a){ int s=0; for (int i = 0; i < a.length; i++) { s+=a[i]; } return s; }}
public class DynamicParamTest { public static void main(String[] args) { DynamicParam d=new DynamicParam(); int s=d.add(12); int s1=d.add(12,13,15,100); int s2=d.add(new int[]{12,13,15,100}); System.out.println(s); System.out.println(s1); System.out.println(s2); }}
76.数组工具类Arrays
import java.util.Arrays;public class ArraysTest { public static void main(String[] args) { int[] i={1,2,3,4,5,6}; String s= Arrays.toString(i); System.out.println(s); Person[] p = new Person[2]; p[0]=new Person("aa",3); p[1]=new Person("bb",4); String s1=Arrays.toString(p); System.out.println(s1); }}
import java.util.Arrays;public class ArraysTest1 { public static void main(String[] args) { Person[] p = new Person[4]; //注意:对数组中的对象排序,数组中的对象必须实现Comparable接口 p[0]=new Person("aa",3); p[1]=new Person("bb",5); p[2]=new Person("cc",1); p[3]=new Person("dd",4); Arrays.sort(p); System.out.println(Arrays.toString(p)); }}
注意不能把基本数据类型的数组转换成集合,如果传递了基本数据类型的集合,就会把数组的类型作为泛型,可以是包装类的数组,数组转换成的集合长度不可改变
import java.util.Arrays;import java.util.List;public class ArraysTest2 { public static void main(String[] args) { Integer[] i={1,2,3,4,5,6}; Listintegers = Arrays.asList(i); System.out.println(integers); //数组转换成集合的长度不可变UnsupportedOperationException //list.add(9); }}
77.集合工具类Collections
面试题:Collection是集合的接口;Collections是集合的工具类
import java.util.ArrayList;import java.util.Collections;import java.util.List;public class CollectionsTest { public static void main(String[] args) { Listlist = new ArrayList<>(); list.add(new Person("Bob",12)); list.add(new Person("Vob",8)); list.add(new Person("Sob",13)); list.add(new Person("Bob",5)); System.out.println("--------集合倒置---------"); Collections.reverse(list); System.out.println(list); System.out.println("--------集合顺序打乱---------"); Collections.shuffle(list); System.out.println(list); System.out.println("--------集合排序---------"); //可以排序的泛型的类必须实现Comparable接口或者使用外置的比较器 Collections.sort(list); System.out.println(list); //Collection中只有Vector是线程安全的 Collections.synchronizedList(list); }}
public class ComparatorDemo implements Comparator{ @Override public int compare(People o1, People o2) { int flag=o1.getAge()-o2.getAge(); if(flag==0){ flag=o1.getName().compareTo(o2.getName()); } return flag; }}
import java.util.ArrayList;import java.util.Collections;import java.util.List;public class CollectionsTest1 { public static void main(String[] args) { Listlist = new ArrayList<>(); list.add(new People("Bob", 12)); list.add(new People("Vob", 8)); list.add(new People("Sob", 13)); list.add(new People("Bob", 5)); //根据指定比较器产生的顺序对指定列表进行排序。sort(List list, Comparator c) Collections.sort(list,new ComparatorDemo()); System.out.println(list); }}