1、泛型
下面是泛型的举例:
package com.itheima.generics;
import java.util.ArrayList;
public class GenericsDemo1 {
/**
* 泛型介绍:JDK5引入的,可以在编译阶段约束操作的数据类型,并进行检查
*
* 注意:泛型默认的数据类型时Object
*
* 泛型的好处:
* 1、统一数据类型
* 2、将运行期的错误提升到编译器
*
* 泛型需要掌握:
* 1、泛型类
* 2、泛型方法
* 3、泛型接口
* 4、泛型通配符
* 5、泛型的限定
*/
public static void main(String[] args) {
//ArrayList如果定义类型为String,则就规定此list装的是String类型的对象(统一数据类型)
ArrayList<String> list = new ArrayList<>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
// list.add(111);//编译就会报错(将运行期的错误提升到编译器)
}
}
了解了什么是泛型之后,接下来看下:上述介绍的泛型类、泛型方法 、泛型接口、泛型通配符,以及泛型的限定等。
1.1 泛型类
package com.itheima.generics;
public class GenericsDemo2 {
/**
* 泛型类演示:
*
* 常见的泛型标识符: E V K T
* E:Element
* T:Type
* K:Key(键)
* V:Value(值)
*
* 清楚不同的泛型,在什么时机能确定到具体的类型
* 泛型类在创建对象的时候就会确定具体的类型
*/
public static void main(String[] args) {
//指定为String类型
Student<String> s = new Student<>();
//指定为Integer类型
Student<Integer> s2 = new Student<>();
}
}
class Student<E>{
/**
* 泛型类的好处是:里面的方法和属性在定义类时不指定,在创建对象时再指定即可
*/
private E name;
}
1.2 泛型方法
package com.itheima.generics;
public class GenericsDemo3 {
/**
* 泛型方法:
* 1、非静态的方法:内部的泛型,会根据类的泛型去匹配
* - 时机:在创建对象时,确定到具体的类型
* 2、静态的方法:静态方法中如果加入泛型,必须声明出自己独立的泛型
* -时机:在调用方法,传入实际参数的时候,确定到具体的类型
*/
public static void main(String[] args) {
String[] arr1 = {"1", "2", "3"};
Integer[] arr2 = {1, 2, 3};
Double[] arr3 = {1.0, 2.0, 3.0};
printArray(arr1);
printArray(arr2);
printArray(arr3);
}
/**
* 2、静态的方法:静态方法中如果加入泛型,必须声明出自己独立的泛型
* -时机:在调用方法,传入实际参数的时候,确定到具体的类型
*/
public static <T> void printArray(T[] arr) {
System.out.println("[");
for (int i = 0; i < arr.length - 1; i++) {
System.out.println(arr[i] + ",");
}
System.out.println(arr[arr.length - 1] + "]");
}
}
class Teacher<E> {
private E name;
/**
* 1、非静态的方法:内部的泛型,会根据类的泛型去匹配
* - 时机:在创建对象时,确定到具体的类型
* @param e
*/
public void show(E e) {
}
}
1.3 泛型接口
package com.itheima.generics;
public class GenericsDemo4 {
/**
* 泛型接口:
* 1、实现类,实现接口的时候,确定到具体的类型
* 2、实现类实现接口,没有指定具体类型,就让接口的泛型,跟着类的泛型去匹配
*/
public static void main(String[] args) {
}
}
interface Inter<T>{
void show(T t);
}
/**
* 1、实现类,实现接口的时候,确定到具体的类型
*/
class InterAImpl implements Inter<String>{
@Override
public void show(String s) {
}
}
/**
* 2、实现类实现接口,没有指定具体类型,就让接口的泛型,跟着类的泛型去匹配
*/
class InterBImpl<T> implements Inter<T>{
@Override
public void show(T t) {
}
}
1.4 泛型通配符
package com.itheima.generics;
import java.util.ArrayList;
import java.util.Objects;
public class GenericsDemo5 {
/**
* 泛型通配符:
* ?:任意类型
* ? extends E:可以传入的是E,或者是E的子类
* ? super E:可以传入的是E,或者是E的父类
*/
public static void main(String[] args) {
//第一个ArrayList定义为 Coder 类型
ArrayList<Coder> list1 = new ArrayList<>();
list1.add(new Coder());
//第二个ArrayList定义为 Manager 类型
ArrayList<Manager> list2 = new ArrayList<>();
list2.add(new Manager());
//调用同一个方法时,可以使用泛型通配符
method(list1);
method(list2);
}
/**
* 使用泛型通配符?来表示任意类型
*
*/
public static void method(ArrayList<? extends Employee> list){
for(Object b : list){
//强转为抽象类类型
Employee e = (Employee)b;
e.work();
}
}
}
abstract class Employee{
abstract void work();
}
class Coder extends Employee{
@Override
void work() {
System.out.println("我是程序员!!!");
}
}
class Manager extends Employee{
@Override
void work() {
System.out.println("我是项目经理!!!");
}
}
1.5 总结
2、数据结构(树)
2.1 树的基本介绍
2.2 二叉树的介绍
2.2.1 概念:
2.2.2 二叉查找树的介绍:
2.2.3 二叉查找树添加节点:
2.2.4 二叉查找树查找节点:
2.2.5 二叉查找树的弊端:
2.2.6 平衡二叉树:
(1)左旋转:
- 案例一:
- 案例二:
(2)右旋转:
- 案例一:
- 案例二:
(3)平衡二叉树需要旋转的四种情况:
-
左左:
-
左右:
先把左子树左旋:
再整体右旋:
-
右右:
-
右左:
先对右子树做一次右旋转,如下:
再整体做一次左旋转:
2.3 红黑树
2.3.1 概念:
2.3.2 规则:
2.3.3 红黑树添加节点:
3、TreeSet集合
TreeSet集合的特点:去重、排序。
TreeSet的两种排序
3.1 自然排序
package com.itheima.set;
import java.util.TreeSet;
public class TreeSetDemo1 {
/**
* TreeSet集合的特点:排序、去重
*
*/
public static void main(String[] args) {
//1、存字符串类型
TreeSet<String> ts1 = new TreeSet<>();
ts1.add("b");
ts1.add("c");
ts1.add("a");
ts1.add("a");
ts1.add("x");
ts1.add("b");
//排序并去重
System.out.println(ts1);//[a, b, c, x]
/**
* 2、存自定义类型:需要 Student 继承 Comparable并实现他的 compareTo 方法
* compareTo方法返回值:
* 0:相等,因此只有第一条数
* 1:正序排列
* -1:倒叙排列
*/
TreeSet<Student> ts2 = new TreeSet<>();
ts2.add(new Student("张三", 12));
ts2.add(new Student("李四", 23));
ts2.add(new Student("王五", 23));
ts2.add(new Student("赵六", 11));
System.out.println(ts2);//[Student{name='赵六', age=11}, Student{name='张三', age=12}, Student{name='李四', age=23}, Student{name='王五', age=23}]
}
}
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Student o) {
/**
* this.xxx - o.xxx 正序
* o.xxx - this.xxx 降序
*/
//根据年龄做主要排序
int ageResult = this.age - o.age;
//要是年龄相等,则使用姓名做次要排序
int result = ageResult == 0 ? this.name.compareTo(o.name) : ageResult;
return result;
}
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 "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.2 比较器排序
package com.itheima.set;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo2 {
/**
* 如果同时具备比较器和自然排序,会优先按照比较器的规则,进行排序操作
* @param args
*/
public static void main(String[] args) {
//使用匿名内部类重写compare方法,即比较器,自定义比较规则
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int ageResult = o2.getAge() - o1.getAge();
int nameResult = ageResult ==0 ? o1.getName().compareTo(o2.getName()) : ageResult;
return nameResult;
}
});
ts.add(new Student("张三", 12));
ts.add(new Student("李四", 23));
ts.add(new Student("王五", 23));
ts.add(new Student("赵六", 11));
System.out.println(ts);//[Student{name='李四', age=23}, Student{name='王五', age=23}, Student{name='张三', age=12}, Student{name='赵六', age=11}]
}
}