泛型
package MyGenerics;
import java.util.ArrayList;
import java.util.Iterator;
public class GenericsTest1 {
public static void main(String[] args) {
//没有泛型的情况
ArrayList list = new ArrayList();
//所有数据都被认为是Object类型,都可以加入集合中
list.add(123);
list.add("string");
list.add('a');
Iterator it = list.iterator();
while (it.hasNext()){
//遍历取出的也是Object类型,由于多态的性质,所以子类中特有的方法无法使用。造成不便
Object next = it.next();
System.out.println(next);
}
}
}
泛型的细节
泛型的应用范围
泛型类
package MyGenerics;
import java.util.Arrays;
/*
这是我写的第一个泛型类
*/
public class Myarraylist<E> {
Object[] obj;
int size;
public Myarraylist() {
//定义一个Object数组
obj = new Object[10];
size = 0;
}
//添加数据
public boolean add(E e){
obj[size] = e;
size++;
return true;
}
//取出数据
public E get(int n){
return (E)obj[n];
}
//toString方法
@Override
public String toString() {
return Arrays.toString(obj);
}
}
package MyGenerics;
public class GenericsTest2 {
public static void main(String[] args) {
// Myarraylist<String> myarraylist = new Myarraylist<>();
// myarraylist.add("wwwe");
// myarraylist.add("qqq");
// myarraylist.add("aaa");
//
// System.out.println(myarraylist.get(1));
//
// System.out.println(myarraylist);
Myarraylist<Integer> myarraylist = new Myarraylist<>();
myarraylist.add(111);
myarraylist.add(222);
myarraylist.add(333);
System.out.println(myarraylist.get(1));
System.out.println(myarraylist);
}
}
泛型方法
练习一:泛型方法的练习
package MyGenerics;
import java.util.ArrayList;
public class ListUtil {
//工具类,私有化无参构造
private ListUtil() {
}
//传入一个要添加的集合,和多个数据
/*
<E> 泛型方法中要放在修饰符后面
*/
public static<E> boolean addAll(ArrayList<E> arrayList,E e1,E e2,E e3,E e4){
arrayList.add(e1);
arrayList.add(e2);
arrayList.add(e3);
arrayList.add(e4);
return true;
}
//可以传入多个要添加的数据\
/*
E...e 为可变参数
可以传入一个或者多个变量,
可变参数必须在形参列表的最后面
*/
public static<E> boolean addAll2(ArrayList<E> arrayList,E...e){
for (E element : e) {
arrayList.add(element);
}
return true;
}
}
package MyGenerics;
import java.util.ArrayList;
public class GenericsTest3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
ListUtil.addAll(list,"qqq","aaa","zzz","www");
System.out.println(list);
//使用可变参数
ArrayList<String> list2 = new ArrayList<>();
ListUtil.addAll2(list2,"qqq","aaa","zzz","www","sss");
ListUtil.addAll2(list2,"eee","ddd","ccc");
System.out.println(list2);
}
}
泛型接口
//实现List接口并指定泛型类,可以使用的类型确认
public class Myarraylist2 implements List<String> {
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return false;
}
}
}
package MyGenerics;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
//实现List接口不指定泛型类,延续接口的泛型,在调用类时在确定
//即方法二
public class Myarraylist3<E> implements List<E> {
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<E> iterator() {
return null;
}
@Override
public Object[] toArray() {
return new Object[0];
}
@Override
public <T> T[] toArray(T[] a) {
return null;
}
@Override
public boolean add(E e) {
return false;
}
@Override
public boolean remove(Object o) {
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
return false;
}
@Override
public boolean addAll(Collection<? extends E> c) {
return false;
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
return false;
}
@Override
public boolean removeAll(Collection<?> c) {
return false;
}
@Override
public boolean retainAll(Collection<?> c) {
return false;
}
@Override
public void clear() {
}
@Override
public E get(int index) {
return null;
}
@Override
public E set(int index, E element) {
return null;
}
@Override
public void add(int index, E element) {
}
@Override
public E remove(int index) {
return null;
}
@Override
public int indexOf(Object o) {
return 0;
}
@Override
public int lastIndexOf(Object o) {
return 0;
}
@Override
public ListIterator<E> listIterator() {
return null;
}
@Override
public ListIterator<E> listIterator(int index) {
return null;
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return null;
}
}
泛型的继承和统配符
泛型不具备继承性但数据具备继承性。
* 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据。
* 弊端:
* 利用泛型方法有一个小弊端,此时他可以接受任意的数据类型
* Ye Fu Zi Student
*
* 希望:本方法虽然不确定类型,但是以后我希望只能传递Ye Fu Zi
*
* 此时我们就可以使用泛型的通配符:
* ?也表示不确定的类型
* 他可以进行类型的限定
* ? extends E: 表示可以传递E或者E所有的子类类型
* ? super E:表示可以传递E或者E所有的父类类型
*
* 应用场景:
* 1.如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
* 2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以泛型的通配符
* 泛型的通配符:
* 关键点:可以限定类型的范围。
package com.itheima.a04mygenerics;
import java.util.ArrayList;
public class GenericsDemo5 {
public static void main(String[] args) {
/*
泛型不具备继承性,但是数据具备继承性
*/
//创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
//调用method方法
//method(list1);
//method(list2);
//method(list3);
list1.add(new Ye());
list1.add(new Fu());
list1.add(new Zi());
}
/*
* 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据。
* */
public static void method(ArrayList<Ye> list) {
}
}
package com.itheima.a04mygenerics;
import java.util.ArrayList;
public class GenericsDemo6 {
public static void main(String[] args) {
/*
* 需求:
* 定义一个方法,形参是一个集合,但是集合中的数据类型不确定。
*
* */
//创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
ArrayList<Student2> list4 = new ArrayList<>();
method(list1);
method(list2);
//method(list3);
//method(list4);
}
/*
* 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据。
* 弊端:
* 利用泛型方法有一个小弊端,此时他可以接受任意的数据类型
* Ye Fu Zi Student
*
* 希望:本方法虽然不确定类型,但是以后我希望只能传递Ye Fu Zi
*
* 此时我们就可以使用泛型的通配符:
* ?也表示不确定的类型
* 他可以进行类型的限定
* ? extends E: 表示可以传递E或者E所有的子类类型
* ? super E:表示可以传递E或者E所有的父类类型
*
* 应用场景:
* 1.如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
* 2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以泛型的通配符
* 泛型的通配符:
* 关键点:可以限定类型的范围。
*
* */
public static void method(ArrayList<? super Fu> list) {
}
}
class Ye {
}
class Fu extends Ye {
}
class Zi extends Fu {
}
class Student2{}
练习一:
package Test1;
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
public String toString() {
return "Animal{name = " + name + ", age = " + age + "}";
}
}
package Test1;
public abstract class Cat extends Animal{
//1.继承抽象类,重写里面所有的抽象方法
//2.本身Cat也是一个抽象的,让Cat的子类再重写重写方法
//此时采取第二种处理方案
//因为猫的两个子类中eat的方法体还是不一样的。
}
package Test1;
public abstract class Dog extends Animal{
}
package Test1;
public class HuskyDog extends Dog {
@Override
public void eat() {
System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的哈士奇,正在吃骨头,边吃边拆家");
}
}
package Test1;
public class LiHuaCat extends Cat {
@Override
public void eat() {
System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的狸花猫,正在吃鱼");
}
}
package Test1;
public class PersianCat extends Cat {
@Override
public void eat() {
System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的波斯猫,正在吃小饼干");
}
}
package Test1;
public class TeddyDog extends Dog{
@Override
public void eat() {
System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的泰迪,正在吃骨头,边吃边蹭");
}
}
package com.itheima.a05test;
import java.util.ArrayList;
public class Test1 {
public static void main(String[] args) {
/*
需求:
定义一个继承结构:
动物
| |
猫 狗
| | | |
波斯猫 狸花猫 泰迪 哈士奇
属性:名字,年龄
行为:吃东西
波斯猫方法体打印:一只叫做XXX的,X岁的波斯猫,正在吃小饼干
狸花猫方法体打印:一只叫做XXX的,X岁的狸花猫,正在吃鱼
泰迪方法体打印:一只叫做XXX的,X岁的泰迪,正在吃骨头,边吃边蹭
哈士奇方法体打印:一只叫做XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家
测试类中定义一个方法用于饲养动物
public static void keepPet(ArrayList<???> list){
//遍历集合,调用动物的eat方法
}
要求1:该方法能养所有品种的猫,但是不能养狗
要求2:该方法能养所有品种的狗,但是不能养猫
要求3:该方法能养所有的动物,但是不能传递其他类型
*/
ArrayList<PersianCat> list1 = new ArrayList<>();
ArrayList<LiHuaCat> list2 = new ArrayList<>();
ArrayList<TeddyDog> list3 = new ArrayList<>();
ArrayList<HuskyDog> list4 = new ArrayList<>();
keepPet(list1);
keepPet(list2);
keepPet(list3);
keepPet(list4);
}
//该方法能养所有的动物,但是不能传递其他类型
public static void keepPet(ArrayList<? extends Animal> list){
//遍历集合,调用动物的eat方法
}
/* // 要求2:该方法能养所有品种的狗,但是不能养猫
public static void keepPet(ArrayList<? extends Dog> list){
//遍历集合,调用动物的eat方法
}*/
/*//要求1:该方法能养所有品种的猫,但是不能养狗
public static void keepPet(ArrayList<? extends Cat> list){
//遍历集合,调用动物的eat方法
}*/
}
泛型总结
数据结构(树)
二叉查找树
二叉查找树添加节点规则:
小的存左边,大的存右边,一样的不存。
二叉树的遍历
前序遍历
中序遍历
后序遍历
层序遍历
遍历方式小结
二叉树小结
二叉查找树的弊端
如果数据插入的顺序与数据的大小顺序一致则会退化为链表,查询速度下降。
平衡二叉树
规则:任意节点左右字数高度差不超过1.
树的演变
保证二叉树平衡的机制
左旋和右旋。
左旋
旋转之后
右旋
旋转之后
需要旋转的四种情况
左左:根节点左子树的左子树上发生不平衡。
左右:根节点左子树的右子树上发生不平衡。
右右:根节点右子树的右子树上发生不平衡。
右左:根节点右子树的左子树上发生不平衡。
红黑树
红黑规则
添加节点的规则
红黑树增删改查性能都很好。
Set系列集合
无序、不重复、无索引。
无序:存和取的顺序不同。
不重复:可以去重。
无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引获取元素。
实现类:
HashSet:无序、不重复、无索引
LinkHashSet:有序、不重复、无索引
TreeSet:可排序、不重复、无索引
Set中的方法基本和Collection的API一致。
练习一:存储字符串并遍历
package MySetDemo;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test1 {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("aaa");
set.add("bbb");
set.add("ccc");
set.add("ddd");
set.add("eee");
boolean b = set.add("eee");
//不重复
System.out.println(b);//false
//无序
System.out.println(set);
//遍历
//迭代器
Iterator<String> it = set.iterator();
while (it.hasNext()){
String str = it.next();
System.out.println(str);
}
System.out.println("==============================");
//增强for
for (String s : set) {
System.out.println(s);
}
System.out.println("==============================");
//Lambda表达式
set.forEach(s-> System.out.println(s));
}
}
HashSet
底层原理
哈希值:
package MySetDemo;
public class hashtest {
public static void main(String[] args) {
//创建两个对象
Student s1 = new Student("zhansan",21);
Student s2 = new Student("zhansan",21);
//未重写之前不同对象的哈希值是不同的
// System.out.println(s1.hashCode());//990368553
// System.out.println(s2.hashCode());//1096979270
//重写hashcode,由于属性相同所以哈希值也相同
System.out.println(s1.hashCode());//-1432263087
System.out.println(s2.hashCode());//-1432263087
//哈希碰撞
String st1 = "abc";
String st2 = "acD";
System.out.println(st1.hashCode());//96354
System.out.println(st2.hashCode());//96354
}
}
底层原理
总结:
1.由数组、链表、红黑树组成
2.查询对象的哈希值根据哈希值判断存储数组的位置,如果数组位置为空则直接存入,如果位置不为空则链表链接在该对象下面。
3.存储为数组链表红黑树结合无法确定顺序。
4.与三的原因相同
5哈希值和equse方法结合进行。
案例一:利用hashSet去重
package MySetDemo;
import java.util.HashSet;
public class hashtestDemo2 {
public static void main(String[] args) {
//创建两个对象
Student s1 = new Student("zhansan",21);
Student s2 = new Student("wanger",21);
Student s3 = new Student("lisi",21);
Student s4 = new Student("wangwu",21);
Student s5 = new Student("zhaoliu",21);
Student s6 = new Student("zhansan",21);
//创建HashSet对象利用其不重复的特性进行去重
HashSet<Student> hashSet = new HashSet<>();
System.out.println(hashSet.add(s1));
System.out.println(hashSet.add(s2));
System.out.println(hashSet.add(s3));
System.out.println(hashSet.add(s4));
System.out.println(hashSet.add(s5));
System.out.println(hashSet.add(s6));
for (Student student : hashSet) {
System.out.println(student);
}
}
}
LinkedHashSet
package MySetDemo;
import java.util.HashSet;
import java.util.LinkedHashSet;
public class LinkHashsetdemo {
public static void main(String[] args) {
//创建对象
Student s1 = new Student("zhansan", 21);
Student s2 = new Student("wanger", 21);
Student s3 = new Student("lisi", 21);
Student s4 = new Student("wangwu", 21);
Student s5 = new Student("zhaoliu", 21);
Student s6 = new Student("zhansan", 21);
//LinkedHashSet
LinkedHashSet<Student> hashSet = new LinkedHashSet<>();
System.out.println(hashSet.add(s1));
System.out.println(hashSet.add(s2));
System.out.println(hashSet.add(s3));
System.out.println(hashSet.add(s4));
System.out.println(hashSet.add(s5));
System.out.println(hashSet.add(s6));
System.out.println(hashSet);
}
}
LinkedHashSet小结
TreeSet
特点
练习一:TreeSet对象排序练习题
import java.util.Iterator;
import java.util.TreeSet;
import java.util.function.Consumer;
public class MyTreeSetdemo {
public static void main(String[] args) {
//创建TreeSet对象
TreeSet<Integer> ts = new TreeSet<>();
//添加元素
ts.add(5);
ts.add(2);
ts.add(4);
ts.add(3);
ts.add(1);
//输出
System.out.println(ts);//[1, 2, 3, 4, 5]
System.out.println("---------------------------------");
//进行遍历
//迭代器遍历
Iterator<Integer> it = ts.iterator();
while (it.hasNext()){
Integer next = it.next();
System.out.println(next);
}
System.out.println("=================================");
//增强for
for (Integer t : ts) {
System.out.println(t);
}
System.out.println("--------------------------------------");
//lambda表达式
// ts.forEach(new Consumer<Integer>() {
// @Override
// public void accept(Integer integer) {
// System.out.println(integer);
// }
// });
ts.forEach( integer-> System.out.println(integer));
}
}
TreeSet集合的默认的规则
练习一:TreeSet对象排序练习题
Student类需要实现 接口并重写方法,才可以存入TreeSet中。
package MySetDemo.TreeSetDemo1;
import java.util.TreeSet;
public class TreeSetDemo1 {
public static void main(String[] args) {
//创建Stuent对象
Student s1 = new Student("xiaozhao",22);
Student s2 = new Student("wangwu",23);
Student s3 = new Student("zhangsan",24);
//创建一个TreeSet对象
TreeSet<Student> ts = new TreeSet<>();
//添加数据
ts.add(s1);
ts.add(s3);
ts.add(s2);
System.out.println(ts);
}
}
package MySetDemo.TreeSetDemo1;
public class Student implements Comparable<Student>{
private String name;
private int age;
@Override
public int compareTo(Student o) {
//实现此方法才可以添加进TreeSet中
/*
实现implements Comparable<Student>接口
返回 负数 红黑数认为这个对象比已经在树上的小
整数 认为大
0 认为已经存在
*/
return this.age-o.getAge();
}
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
TreeSet的两种比较方式
练习二:TreeSet对象排序练习题
package MySetDemo.TreeSetDemo2;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo2 {
public static void main(String[] args) {
//由于排序规则与源码定义的不同则使用比较器排序
TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
/*
o1 :为要加入的元素
o2 :为已经加入的元素
规则与第一种相同
*/
@Override
public int compare(String o1, String o2) {
//先判断长度
int i = o1.length() - o2.length();
//如长度相同则调用原本的判定规则即被String重写的compareTo方法
i = i == 0?o1.compareTo(o2):i;
return i;
}
});
//添加元素
ts.add("ab");
ts.add("c");
ts.add("df");
ts.add("qwer");
System.out.println(ts);
}
}
练习三:TreeSet对象排序练习题
package MySetDemo.TreeSetdemo3;
import java.util.TreeSet;
public class TreeSetDemo3 {
public static void main(String[] args) {
Student s1 = new Student("xiaoli",20,80,80,80);
Student s2 = new Student("laozhao",21,80,88,80);
Student s3 = new Student("zhangsan",20,85,85,85);
Student s4 = new Student("lisi",23,87,80,80);
Student s5 = new Student("xiaoli",20,80,80,80);
TreeSet<Student> st = new TreeSet<>();
st.add(s1);
st.add(s2);
st.add(s3);
st.add(s4);
st.add(s5);
System.out.println(st);
}
}
package MySetDemo.TreeSetdemo3;
public class Student implements Comparable<Student>{
private String name;
private int age;
private int Chinese;
private int Math_scores;
private int Englich_scores;
//总分
private int sum;
//将无参构造私有化,创建对象必须赋值
private Student() {
}
public Student(String name, int age, int Chinese, int Math_scores, int Englich_scores) {
this.name = name;
this.age = age;
this.Chinese = Chinese;
this.Math_scores = Math_scores;
this.Englich_scores = Englich_scores;
sum = Chinese+Math_scores+Englich_scores;
System.out.println(sum);
}
@Override
public int compareTo(Student o) {
//实现此方法才可以添加进TreeSet中
/*
实现implements Comparable<Student>接口
返回 负数 红黑数认为这个对象比已经在树上的小
整数 认为大
0 认为已经存在
*/
int i = o.sum - this.sum ;
//判断i的值
//总分相同则判断语文分数,并赋值给i
i = i == 0 ? o.Chinese -this.Chinese : i;
//语文分数是否相同,判断数学
i = i == 0 ? o.Math_scores-this.Math_scores : i;
i = i == 0 ? o.Englich_scores -this.Englich_scores : i;
i = i == 0 ? o.age -this.age : i;
//判断字母所以调用String中重写的compareTo方法
i = i == 0?this.name.compareTo(o.name):i;
return i;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
* @return Chinese
*/
public int getChinese() {
return Chinese;
}
/**
* 设置
* @param Chinese
*/
public void setChinese(int Chinese) {
this.Chinese = Chinese;
}
/**
* 获取
* @return Math_scores
*/
public int getMath_scores() {
return Math_scores;
}
/**
* 设置
* @param Math_scores
*/
public void setMath_scores(int Math_scores) {
this.Math_scores = Math_scores;
}
/**
* 获取
* @return Englich_scores
*/
public int getEnglich_scores() {
return Englich_scores;
}
/**
* 设置
* @param Englich_scores
*/
public void setEnglich_scores(int Englich_scores) {
this.Englich_scores = Englich_scores;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + ", Chinese = " + Chinese + ", Math_scores = " + Math_scores + ", Englich_scores = " + Englich_scores+","+sum +"}";
}
}
TreeSet小结
单列集合的使用场景
HashSet、LinkedHashSet、TreeSet的源码都是各自的Map。