泛型通配符>
任意类型,如果没有明确,那么就是Object以及任意的Java类了
? extends E
向下限定,E及其子类
? super E
向上限定,E及其父类
//任意类型,如果没有明确,那么就是Object以及任意的java类了 ArrayList> list4 = new ArrayList(); //? extends E 向下限定,E及其子类 ArrayList extends Animals> list7 = new ArrayList (); //? super E 向下限定,E及其父类 ArrayList super Animals> list11 = new ArrayList ();
泛型类的测试类泛型类
把泛型定义在类上
格式:public class 类名<泛型类型1,…>
注意:泛型类型必须是引用类型这里的<>里面的内容仅仅表示的使一种参数数据类型,参数类型是一种变量
泛型方法
把泛型定义再方法上
public <泛型类型> 返回类型 方法名(泛型类型.)泛型接口
把泛型定义在接口上
格式:public interface 接口名<泛型类型1…>
public class GenericTool1泛型方法的测试类{ private T obj; public T getObj() { return obj; } public void setObj(T obj) { this.obj = obj; } }
public泛型接口的测试类void show(F f){ System.out.println(f); }
public interface GenericTool3如果想要调用泛型接口,得重新定义一个类去实现接口的方法{ public abstract void show(W w); }
public class GenericTool3Impl可变参数的概述implements GenericTool3 { @Override public void show(W w) { System.out.println(w); } }
定义方法的时候不知道定义多少参数
格式
修饰符 返回值类型 方法名(数据类型…变量名)
注意
这里的变量其实是一个数组
如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个Arrays工具类中的一个方法
public static List asList(T… a)
public static void sum(String name, int... ints) {
int sum = 0;
for (int i : ints) {
sum += i;
}
System.out.println(name + "学生的总成绩为:" + sum);
}
增强for循环
JDK1.5之后出现的特性;
到目前为止,学过哪些知识使JDK1.5之后出现的?
泛型,增强for,包装类,Scanner,枚举增强for循环概述:简化数组和Collection集合的遍历
语句定义格式:
for(元素数据类型 变量名(自定义) : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}
好处:简化遍历
for(String string : strings){
System.out.println(string);
}
Set集合
当发现不明白的地方,可以追溯源码Set集合:元素是唯一的,并且元素的顺序是无序的集合
在Set集合中存储的元素为什么不会有重复的呢?
总结:
HashSet中的add的方法
先比较添加元素的hash值,如果hash值一样,则判断equals方法,如果相等则说明元素相同,不添加。Set接口,HashSet中add方法中源码分析
HashSet重写Set中的add方法:
//先将存入元素的哈希值与该位置上的元素的哈希值进行比较 //如果哈希值都不一样,继续走判断instanceof //如果哈希值都一样,会调用元素的equals(k)方法进行比较 //如果equals(k)方法比较的结果是false的话,继续向下执行最终会将元素添加到集合中或者不添加 //如果equals(k)方法比较的结果是true的话,表示哈希值和内容都一样,表示元素重复了 //就覆盖,从现象上来看,其实就是不赋值 //说到这里,我们就已经知道HashSet中add()方法实际上与hashCode()方法和equals()方法有关 //集合中会不会去重取决于元素类有没有重写hashCode()方法和equals()方法linkedHashSet
集合的小练习: 练习一:获取10个1-20之间的随机数,要求不能重复public class HashSet implements Set
public class linkedHashSet extends HashSet implements Set,linkedHashSet:
1、底层数据结构是哈希表和链表
2、哈希表保证元素的唯一
3、链表保证了元素的有序(存储和取出的顺序一致)
4、线程不安全,效率高
分析:
1、由于我们不确定获取随机数的次数,长度不好确定,所以我们选择集合
2、随机数生成的方式:Random类:nextInt(int num): 左闭右开
public class RandomTest {
public static void main(String[] args) {
//使用 ArrayList来进行存储
// //1、创建随机数对象
// Random random = new Random();
// //2、创建集合对象存储随机数
// ArrayList list = new ArrayList<>();
//
// int count = 0;
//
// while (count < 10) {
// //生成随机数
// int number = random.nextInt(20) + 1;
// if (!list.contains(number)) {
// list.add(number);
// count++;
// }
// }
// System.out.println(list);
//使用Set集合进行存储
Random random = new Random();
Set list = new HashSet<>();
while (list.size() < 10) {
int number = random.nextInt(20) + 1;
list.add(number);
}
System.out.println(list);
}
}
练习二:键盘录入 多个 数据,以0结束 ,要求再控制台输出这多个数据中
分析:
1、由于不知道输入多少查看i。所以用while循环进行输入
2、用集合存储数据
3、toArray()
4、Arrays.sort()
5、取最后一个元素就是最大值
public class ListTest {
public static void main(String[] args) {
//创建键盘录入对象
Scanner scanner = new Scanner(System.in);
//创建集合对象
ArrayList list = new ArrayList<>();
boolean flag = true;
while (flag) {
int number = scanner.nextInt();
if (number == 0) {
flag = false;
System.out.println("数据录入完毕!!");
} else {
list.add(number);
}
}
//将集合转换为数组
Object[] obj = list.toArray();
Arrays.sort(obj);
System.out.println("最大值为:" + obj[obj.length - 1]);
}
}
练习3:用Set集合存储学生对象(当学生的姓名和年龄都一样的时候,判定是同一个学生)
public class SetDemo2 {
public static void main(String[] args) {
//创建集合对象
Set student2s = new HashSet<>();
//创建学生对象
Student2 s1 = new Student2("明旺", 18);
Student2 s2 = new Student2("王宇", 17);
Student2 s3 = new Student2("周家祥", 19);
Student2 s4 = new Student2("明旺", 18);
//将学生对象添加到集合中
student2s.add(s1);
student2s.add(s2);
student2s.add(s3);
student2s.add(s4);
for(Student2 student2 : student2s){
System.out.println(student2);
}
}
}
练习4:了解静态导入是什么?
静态导入:
语句定义格式:import static 包名…类名.方法名;
可以直接导入到方法级别注意事项:
1、方法必须是静态的
import static java.lang.Math.abs;
import static java.lang.Math.pow;
import static com.shujia.yl.day19.StaticClass.fun;
import static com.shujia.yl.day19.StaticClass.show;
class StaticClass {
public static void fun(){
System.out.println("数加科技nb!");
}
public static void show(String s){
System.out.println(s);
}
}
public class StaticimportDemo {
public static void main(String[] args) {
//Math
System.out.println(Math.abs(-100));
System.out.println(Math.pow(2, 3));
System.out.println(Math.max(100, 200));
//有没有什么方法,不同写类名,直接写方法名
// System.out.println(abs(-200);
//这时候需要静态导入的技术
System.out.println(abs(-200));
System.out.println(abs(-200));
System.out.println(pow(2, 4));
fun();
show("spark");
//如果此时我就是想使用静态导入的方法,怎么办?
StaticClass.show("flink");
//将前缀路径写完整
com.shujia.yl.day19.StaticClass.show("flink");
//当静态导入的方法名与本类中的方法名冲突的时候,我们发现,直接通过类名调用的方式会更加简单
//所以根据实际情况,选择使用静态导入
}
public static void show(String s) {
System.out.println("这是在StaticimportDemo类中的show方法" + s);
}
}
练习5:集合的嵌套集合
集合的嵌套遍历
需求:目前,数加学院有十五期,十六期。每一期有很多学生,每个学生都是一个学生对象
可以用一个集合表示一个班的学生
十五期的学生:ArrayList classList15;
十六期的学生:ArrayList classList16;
无论是十五也好还是十六期,都是属于数加学院的班级
数加学院本身也可以通过集合表示:ArrayList shujia;这样的现象叫做集合嵌套
public class ListQianTaoTest {
public static void main(String[] args) {
//定义一个十五期的班级集合
ArrayList classList15 = new ArrayList<>();
//定义一个十六期的班级集合
ArrayList classList16 = new ArrayList<>();
//定义一个数加学院的集合
ArrayList> shujia = new ArrayList<>();
//将十五期和十六期添加到shujia集合中
shujia.add(classList15);
shujia.add(classList16);
//创建十五期的学生对象
Student s1 = new Student("小五", 18);
Student s2 = new Student("小六", 17);
Student s3 = new Student("小七", 16);
Student s4 = new Student("小八", 20);
//创建十六期的学生对象
Student s11 = new Student("小三", 18);
Student s12 = new Student("小四", 17);
Student s13 = new Student("小二", 19);
Student s14 = new Student("老大", 16);
//将15期的学生对象添加到十五集合中
classList15.add(s1);
classList15.add(s2);
classList15.add(s3);
classList15.add(s4);
//将16期的学生对象添加到十六集合中
classList16.add(s11);
classList16.add(s12);
classList16.add(s13);
classList16.add(s14);
//遍历
//增强for循环遍历
// for(ArrayList clazz : shujia){
// for(Student s : clazz){
// System.out.println(s);
// }
// }
//普通for循环遍历
// for (int i = 0; i < shujia.size(); i++) {
// if (i == 0) {
// System.out.println("=============十五期==============");
// for (int j = 0; j < shujia.get(i).size(); j++) {
// Student student = shujia.get(i).get(i);
// System.out.println(student);
//
// }
// } else if (i == 1) {
// System.out.println("=============十六期==============");
// for (int j = 0; j < shujia.get(i).size(); j++) {
// Student student = shujia.get(i).get(i);
// System.out.println(student);
//
// }
// }
// }
System.out.println("========================================================");
Iterator> iterator = shujia.iterator();
while(iterator.hasNext()){
ArrayList clazz = iterator.next();
Iterator iterator1 = clazz.iterator();
while(iterator1.hasNext()){
Student student = iterator1.next();
System.out.println(student);
}
}
}
}
TreeSet集合
TreeSet中add()源码分析TreeSet:元素唯一,元素可以按照某种规则进行排序
两种排序方式:
自然排序
比较器排序A NavigableSet实现基于TreeMap的元件使用其有序natural ordering ,或由Comparator集合创建时提供,这取决于所使用的构造方法。
为什么会进行去重以及排序呢?怎么排序呢?看源码。
public abstract class AbstractCollectionimplements Collection {} public abstract class AbstractSet extends AbstractCollection implements Set {} public class TreeSet extends AbstractSet implements NavigableSet { private transient NavigableMap m; private static final Object PRESENT = new Object(); TreeSet(NavigableMap m) { this.m = m; } public TreeSet() { this(new TreeMap ()); } public boolean add(E e) { //E -- Integer //e -- 20 return m.put(e, PRESENT)==null; } } public class TreeMap extends AbstractMap implements NavigableMap { private transient Entry root; public TreeMap() { comparator = null; } public V put(K key, V value) { //key -- 20,18 //value -- new Object() Entry t = root; //判断根有没有元素,如果没有根,把当前元素值作为根结点。 if (t == null) { compare(key, key); // type (and possibly null) check root = new Entry<>(key, value, null); size = 1; modCount++; return null; } int cmp; //0 Entry parent; //null // split comparator and comparable paths //由于我们使用的是无参构造方法,comparator的值是null Comparator super K> cpr = comparator; if (cpr != null) { do { parent = t; cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } else { //key -- 18 if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") //向下转型 //要想这里可以顺利进行向下转型,元素的数据类型必须要实现Comparable接口 Comparable super K> k = (Comparable super K>) key; do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } Entry e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; fixAfterInsertion(e); size++; modCount++; return null; } }
Student3类:如果TreeSet泛型是个自定义的引用类型,则会发生类型转换错误ClassCastException
按照正常的写法,我们一运行就报错了
java.lang.ClassCastException:类转换异常
由于我们这里TreeSet创建的时候使用的是无参构造构造方法,走的是自然排序
而这里底层源码中有一步是向下转型的
Comparable super K> k = (Comparable super K>) key;
报错了
原因是我们Student3类没有实现Comparable接口,无法进行向下转型,所以报错了。
public class Student3 implements Comparable{ private String name; private int age; public Student3() { } public Student3(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 "Student3{" + "name='" + name + ''' + ", age=" + age + '}'; } @Override public int compareTo(Student3 student3) { //这里返回什么,应该是根据我们自己定义的规则来排序 //比如说我想在去重的前提下,按照年龄进行排序。 // return this.age - o.age; //年龄一样,姓名不一定一样 //这里要区主次条件(主要条件是业务明确给出的,次要条件是我们自己分析得出的) int i = this.age - student3.age; //判断姓名是否一样(三目运算符) int i2 = i == 0 ? this.name.compareTo(student3.name) : i; return i2; } }
public class TreeSetDemo2 {
public static void main(String[] args) {
//创建TreeSet集合
TreeSet set = new TreeSet<>();
//创建学生对象
Student3 s1 = new Student3("theshy", 20);
Student3 s2 = new Student3("xiaohu", 24);
Student3 s3 = new Student3("uzi", 25);
Student3 s4 = new Student3("卡萨", 22);
Student3 s5 = new Student3("rookie", 23);
Student3 s6 = new Student3("姿态", 21);
Student3 s7 = new Student3("faker", 25);
Student3 s8 = new Student3("xiaohu", 24);
//将学生对象添加到集合中
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
set.add(s6);
set.add(s7);
set.add(s8);
for(Student3 s : set){
System.out.println(s);
}
}
}
TreeSet自然排序小练习:
Student4类:
public class Student4 implements Comparable{ private String name; private int age; public Student4() { } public Student4(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 "Student4{" + "name='" + name + ''' + ", age=" + age + '}'; } @Override public int compareTo(Student4 o) { int i = this.name.length() - o.name.length(); int i1 = i == 0 ? (this.name.compareTo(o.name)) : i; return i1; } }
import java.util.TreeSet;
public class TreeSetDemo3 {
public static void main(String[] args) {
//创建TreeSet集合对象
TreeSet set = new TreeSet<>();
//创建学生对象
Student4 s1 = new Student4("theshy", 20);
Student4 s2 = new Student4("xiaohu", 24);
Student4 s3 = new Student4("uzi", 25);
Student4 s4 = new Student4("卡萨", 22);
Student4 s5 = new Student4("rookie", 23);
Student4 s6 = new Student4("姿态", 21);
Student4 s7 = new Student4("faker", 25);
Student4 s8 = new Student4("xiaohu", 24);
//将学生对象添加到集合中
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
set.add(s6);
set.add(s7);
set.add(s8);
for(Student4 s : set){
System.out.println(s);
}
}
}
可以自定义一个比较器,也可以使用 匿名内部类来实现比较器排序 自定义比较器:比较器排序
利用TreeSet创建对象时的带参数的构造方法来进行比较器排序
TreeSet(Comparator super E> comparator)
构造一个新的,空的树集,根据指定的比较器进行排序。
import java.util.Comparator; public class MyComparator implements Comparator{ @Override public int compare(Student5 o1, Student5 o2) { int i = o1.getName().length() - o2.getName().length(); //如果长度一样,比较内容 int i1 = i == 0 ? o1.getName().compareTo(o2.getName()) : i; //姓名内容一样,年龄的大小不一定一样 int i2 = i1 == 0 ? o1.getAge() - o2.getAge() : i1; return i2; } }
public class TreeSetDemo4 {
public static void main(String[] args) {
// MyComparator myComparator = new MyComparator();
// //创建集合对象
// TreeSet set = new TreeSet<>(myComparator);
//也可以通过匿名内部类的形式去使用比较器
TreeSet set = new TreeSet<>(new Comparator() {
@Override
public int compare(Student5 o1, Student5 o2) {
int i = o1.getName().length() - o2.getName().length();
//如果长度一样,比较内容
int i1 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
//姓名内容一样,年龄的大小不一定一样
int i2 = i1 == 0 ? o1.getAge() - o2.getAge() : i1;
return i2;
}
});
//创建学生对象
Student5 s1 = new Student5("mingwang", 18);
Student5 s2 = new Student5("wangyu", 18);
Student5 s3 = new Student5("zhoujiaxiang", 17);
Student5 s4 = new Student5("zhangbaogui", 18);
Student5 s5 = new Student5("liuzhicheng", 18);
Student5 s6 = new Student5("wangyu", 20);
//将学生对象添加到集合中
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
set.add(s6);
for(Student5 Student5 : set){
System.out.println(Student5);
}
}
}



