泛型:
把明确的数据类型工作提前到编译时期,在创建集合的时候明确存储元素的类型。这样的做法有点像把数据类型当参数一样传递,所以泛型还有一个叫法:参数化类型
泛型语句的定义格式:
<引用数据类型>:注意尖括号里的数据类型只能是引用数据类型;
泛型的好处:
1、将我们运行时出现的问题提前到编译时期;
2、不需要做强制类型的转换;
3、优化了代码。消除了黄色警戒线,使代码看起来更简洁;
import java.util.ArrayList;
import java.util.Iterator;
public class Generic1 {
public static void main(String[] args) {
//创建一个List集合对象
//在JDK1.7之后,泛型会进行自动类型推断
ArrayList<String> list = new ArrayList<>();
//向集合中添加元素
list.add("hello");
list.add("hello");
list.add("hello");
list.add("hello");
list.add("hello");
// list.add(20);
// list.add(12.34);
// list.add(new Student());
//遍历
// Iterator iterator = list.iterator();
// while (iterator.hasNext()) {
// Object next = iterator.next();
//
// String s = (String) next; //ClassCastException
//
// System.out.println(next);
// }
//遍历
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
}
}
}
泛型类:
把泛型定义在类上
格式:public class 类名<泛型类型1,,,,>
注意:泛型类型必须是引用类型
这里的<>里面的内容仅仅表示的是一种参数数据类型,参数类型是一种变量,既然是一种变量就要符合变量的命名规则,可以是任意符合标识符起名规则的名字。一般情况下在定义的时候,习惯用一个大写字符表示。
public class GenericTool1<T> {
private T obj;
public T getObj(){
return obj;
}
public void setObj(T obj){
this.obj = obj;
}
}
class GenericTest1 {
public static void main(String[] args) {
//如果不加泛型,默认使Object类型
// GenericTool1 gt1 = new GenericTool1();
//
// gt1.setObj("hello");
// gt1.setObj(20);
// gt1.setObj(12.34);
GenericTool1<String> gt2 = new GenericTool1<>();
gt2.setObj("hello");
// gt2.setObj(20);
String obj = gt2.getObj();
}
}
泛型方法:
把泛型定义在方法上
格式:public <泛型类型> 返回类型 方法名(泛型类型....)
public class GenericTool2 {
// public void show(String s){
// System.out.println(s);
// }
//
// public void show(int i){
// System.out.println(i);
// }
//
// public void show(double d){
// System.out.println(d);
// }
//用泛型方法改进,将来不确定要传入什么类型的数据
public <F> void show(F f){
System.out.println(f);
}
}
class GenericTest2 {
public static void main(String[] args) {
GenericTool2 genericTool2 = new GenericTool2();
genericTool2.show("hello");
genericTool2.show(10);
genericTool2.show(12.34);
}
}
泛型接口:
把泛型定义在接口上;
格式:public interface 接口名<泛型类型>
public interface GenericTool3<W> {
public void show(W w);
}
class GenericTool3Impl<W> implements GenericTool3<W>{
@Override
public void show(W w) {
System.out.println(w);
}
}
class GenericTest3 {
public static void main(String[] args) {
GenericTool3Impl<String> stringGenericTool3 = new GenericTool3Impl<>();
stringGenericTool3.show("hello");
// stringGenericTool3.show(20);
}
}
泛型通配符<?>:
任意类型,如果没有明确,那么就是Object以及任意的java类了。
?extends E:向下限定,及其子类
?super E:向上限定,及其父类
public class GenericDemo1 {
public static void main(String[] args) {
ArrayList<Animal> list1 = new ArrayList<Animal>();
ArrayList<Dog> list2 = new ArrayList<Dog>();
ArrayList<Object> list3 = new ArrayList<Object>();
//泛型通配符<?>
//任意类型,如果没有明确,那么就是Object以及任意的Java类了
ArrayList<?> list4 = new ArrayList<Animal>();
ArrayList<?> list5 = new ArrayList<Dog>();
ArrayList<?> list6 = new ArrayList<Object>();
//? extends E 向下限定,E及其子类
ArrayList<? extends Animal> list7 = new ArrayList<Animal>();
ArrayList<? extends Animal> list8 = new ArrayList<Dog>();
ArrayList<? extends Animal> list9 = new ArrayList<Cat>();
// ArrayList<? extends Animal> lis10 = new ArrayList<Object>();
//? super E 向上限定,E及其父类
ArrayList<? super Animal> list11 = new ArrayList<Animal>();
ArrayList<? super Animal> list13 = new ArrayList<Object>();
// ArrayList<? super Animal> list12 = new ArrayList<Dog>();
}
}
class Animal{ }
class Dog extends day19.Animal {}
class Cat extends day19.Animal {}
静态导入:
语句定义格式:import static 包名,类名.方法名;
可直接导入到方法级别;
注意:方法必须是静态的;
import static java.lang.Math.abs;
import static java.lang.Math.pow;
import static com.shujia.wyh.day19.StaticClass.fun;
import static com.shujia.wyh.day19.StaticClass.show;
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(pow(2,4));
fun();
//当静态导入的方法名与本类中的方法名冲突的时候,调用的是本类中的方法
show("spark");
//如果此时我就是想使用静态导入的方法,怎么办?
// StaticClass.show("flink");
//将前缀路径写完整
com.shujia.wyh.day19.StaticClass.show("flink");
//当静态导入的方法名与本类中的方法名冲突的时候,我们发现,直接通过类名调用的方式会更加简单
//所以根据实际情况,选择使用静态导入
}
public static void show(String s){
System.out.println("这是在StaticImportDemo类中的show方法"+s);
}
}
public class StaticClass {
public static void fun(){
System.out.println("数加科技,yyds");
}
public static void show(String s){
System.out.println(s);
}
}
set集合:
元素是唯一的,并且元素的顺序是无序的集合。
import java.util.HashSet;
import java.util.Set;
public class SetDemo1 {
public static void main(String[] args) {
Set<String> set1 = new HashSet<>();
//向集合中添加元素
set1.add("hello");
set1.add("world");
set1.add("java");
set1.add("bigdata");
set1.add("hadoop");
set1.add("world");
set1.add("java");
set1.add("hello");
set1.add("spark");
set1.add("spark");
set1.add("hbase");
set1.add("flink");
set1.add("java");
set1.add("hello");
//遍历
for(String s : set1){
System.out.println(s);
}
//flink
hallo
world
java
bigdata
spark
hadoop
hello
hbase
}
}
用set集合存储学生对象(当姓名和年龄一样时判断为同一个学生)
import java.util.Set;
import java.util.HashSet;
public class Set2 {
public static void main(String[] args) {
Set<student1> student1s = new HashSet<>();
student1 s1 = new student1("小飞", 18);
student1 s2= new student1("小白", 17);
student1 s3 = new student1("小祥", 19);
student1 s4 = new student1("小飞", 18);
student1s.add(s1);
student1s.add(s2);
student1s.add(s3);
student1s.add(s4);
for (student1 s:student1s){
System.out.println(s);
}
//student1{name='小白', age=17}
//student1{name='小祥', age=19}
//student1{name='小飞', age=18}
}
}
class student1{
private String name;
private int age;
public student1(){}
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;
}
public student1(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
student1 student1 = (student1) o;
if (age != student1.age) return false;
return name != null ? name.equals(student1.name) : student1.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "student1{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
可变参数
格式:
修饰符 返回值类型 方法名(数据类型... 变量名){}
注意:这里的变量其实是一个数组,如果一个方法有可变参数,并且有多个参数,可变参数一定是最后一个参数。
即若使用可变参数定义方法时,有其他数据类型参与的时候,将可变参数的定义放在最后。
Arrays工具类中的一个方法:public static <T> List<T> asList(T... a)
该方法其实就是将数组转变为一个集合
代码举例:
import java.util.Arrays;
import java.util.List;
public class ChangeDemo {
public static void main(String[] args) {
int a=1;
int b=2;
int c=4;
sum(a,b);
sum(a,b,c);
sum("赵云",45,20,30);
// Arrays工具类中的一个方法
List<String> list = Arrays.asList("这是", "数组", "转变", "集合");
for(String s : list){
System.out.println(s);
}
}
// public static void sum(int a,int b){//求两个数的和
// System.out.println(a+b);
// }
// public static void sum(int a,int b,int c){//求三个数的和
// System.out.println(a+b+c);
// }
// 使用可变参数改进:含有多个参数,将可变参数放在最后
public static void sum(String s,int... ints){
int sum=0;
for (int i : ints){
sum+=i;
}
System.out.println(s+"的成绩总分为:"+sum);
}
// 使用可变参数改进求几个数的和
public static void sum(int... ints){
int sum=0;
for(int i : ints){
sum+=i;
}
System.out.println(ints.length+"个数的和为:"+sum);
}
}
注意:同一个方法定义中,可变参数只能出现一次:即不会出现如下代码行:
public static void sum(int... ints,int... ints2){}
LinkedHashSet:
public class HashSet<E> implements Set<E>
public class LinkedHashSet<E> extends HashSet<E> implemtents<E>
1、底层数据结构是哈希表和链表
2、哈希表保证元素的唯一
3、链表保证了元素的有序(存储和取出的顺序一致)
4、线程不安全,效率高
import java.util.LinkedHashSet;
public class LinkedHashed1 {
public static void main(String[] args) {
LinkedHashSet<String> set1 = new LinkedHashSet<>();
set1.add("hallo");
set1.add("hello");
set1.add("world");
set1.add("java");
set1.add("bigdata");
set1.add("hadoop");
set1.add("world");
set1.add("java");
set1.add("hello");
set1.add("spark");
set1.add("spark");
set1.add("hbase");
set1.add("flink");
set1.add("java");
set1.add("hello");
for (String s:set1){
System.out.println(s);
}
// hallo
//hello
//world
//java
//bigdata
//hadoop
//spark
//hbase
//flink
}
}
TreeSet:
底层结构是红黑树
元素唯一,元素可以按照某种规则进行排序
1、自然排序;
2、比较器排序;
A NavigableSet实现基于TreeMap的元件使用其有序natural,ordering,或由Comparator创建时提供,这取决于所使用的构造方法。
import java.util.TreeSet;
public class TreeSet1 {
public static void main(String[] args) {
//创建TreeSet集合
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(20);
treeSet.add(18);
treeSet.add(24);
treeSet.add(23);
treeSet.add(88);
treeSet.add(16);
treeSet.add(12);
treeSet.add(18);
treeSet.add(20);
treeSet.add(23);
treeSet.add(1);
treeSet.add(2);
//遍历
for(Integer i : treeSet){
System.out.println(i);
}
// 1
// 2
// 12
// 16
// 18
// 20
// 23
// 24
// 88
// String s1 = "hello";
// String s2 = "hello";
// System.out.println(s1.compareTo(s2));
}
}
存储学生对象并遍历:
由于我们这里TreeSet创建的时候,使用的是无参构造方法,走的是自然排序,而这里底层源码中有一步是向下转型的,Comparable<? super K>K=(Comparable<? super K>)key;
报错了
原因是我们Studeng3类没有实现Comparable接口,无法向下转型。
import java.util.Objects;
public class Student1 implements Comparable<Student1> {
private String name;
private int age;
public Student1() {
}
public Student1(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 "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student1 o) {
// 这里的返回值具体返回什么应该由我们自己来定义
int i = this.age - o.age;
int i2 = i == 0 ? this.name.compareTo(o.name) : i;
return i2;
}
}
测试类:
import java.util.TreeSet;
public class Ttest2 {
public static void main(String[] args) {
TreeSet<Student1> students = new TreeSet<Student1>();
Student1 s1 = new Student1("云", 19);
Student1 s2 = new Student1("赵云", 18);
Student1 s3 = new Student1("赵子龙", 20);
Student1 s4 = new Student1("常山赵子龙", 21);
Student1 s5 = new Student1("赵子龙", 20);
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
students.add(s5);
for (Student1 s : students){
System.out.println(s);
}
}
}
这里是按年龄大小来排序的;
需求:使用TreeSet存储学生对象并以姓名的长度来排序
学生类:
import java.util.Objects;
public class Student3 implements Comparable<Student3> {
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 int compareTo(Student3 o) {
// 比较姓名的长度是否相等
int i = this.name.length() - o.name.length();
// 若相等,比较姓名的内容是否相同
int i2 = i == 0 ? this.name.compareTo(o.name) : i;
// 若相同,比较年龄是否相等
int i3 = i2 == 0 ? this.age - o.age : i2;
return i3;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.util.TreeSet;
public class Ttest3 {
public static void main(String[] args) {
TreeSet<Student3> students3 = new TreeSet<>();
Student3 s1 = new Student3("yun", 19);
Student3 s2 = new Student3("zhaoyun", 18);
Student3 s3 = new Student3("zhaozilon", 20);
Student3 s4 = new Student3("changshanzhaozilon", 21);
Student3 s5 = new Student3("yun", 22);
students3.add(s1);
students3.add(s2);
students3.add(s3);
students3.add(s4);
students3.add(s5);
for(Student3 sc : students3){
System.out.println(sc);
}
}
}
比较器排序:
利用TreeSet创建对象时的带参数的构造方法来进行比较器排序
TreeSet(Comparator<? super E> comparator)
构造一个新的,空的数集,根据指定的比较器进行排序
这里需要实现Comparator接口,重写compare()方法
代码举例:
实现Comparator接口的实现类ComparatorImpl:
import java.util.Comparator;
public class ComparatorImpl implements Comparator<Student4> {
@Override
public int compare(Student4 o1, Student4 o2) {
// 比较姓名的长度
int i = o1.getName().length() - o2.getName().length();
// 比较姓名的内容
int i2 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
// 比较年龄的大小
int i3 = i2 == 0 ? o1.getAge() - o2.getAge() : i2;
return i3;
}
}
import java.util.TreeSet;
public class Ttest4 {
public static void main(String[] args) {
ComparatorImpl comparator = new ComparatorImpl();
TreeSet<Student4> student4s = new TreeSet<>(comparator);//使用带参构造
// 创建学生对象
Student4 s1 = new Student4("yun", 19);
Student4 s2 = new Student4("zhaoyun", 18);
Student4 s3 = new Student4("zhaozilon", 21);
Student4 s4 = new Student4("chanshangzhaozilon", 20);
Student4 s5 = new Student4("chanshangzhaoyun", 20);
Student4 s6 = new Student4("zhaoyun", 22);
Student4 s7 = new Student4("yun", 19);
// 添加到集合
student4s.add(s1);
student4s.add(s2);
student4s.add(s3);
student4s.add(s4);
student4s.add(s5);
student4s.add(s6);
student4s.add(s7);
// 遍历
for(Student4 student4 : student4s){
System.out.println(student4);
}
}
}
总结:
自然排序使用无参构造创建对象,需要在元素类中实现Comparable接口,重写compareTo()方法
比较器排序使用带参构造创建对象,需要在元素类中实现Comparator接口,重写Compare()方法
比较器排序这里还可以使用匿名内部类进行comparator接口的实现:
import java.util.Comparator;
import java.util.TreeSet;
public class Ttest4 {
public static void main(String[] args) {
// ComparatorImpl comparator = new ComparatorImpl();
// TreeSet<Student4> student4s = new TreeSet<>(comparator);
// 使用匿名内部类改进:
TreeSet<Student4> student4s = new TreeSet<>(new Comparator<Student4>() {
@Override
public int compare(Student4 o1, Student4 o2) {
// 比较姓名的长度
int i = o1.getName().length() - o2.getName().length();
// 比较姓名的内容
int i2 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
// 比较年龄的大小
int i3 = i2 == 0 ? o1.getAge() - o2.getAge() : i2;
return i3;
}
});
Student4 s1 = new Student4("yun", 19);
Student4 s2 = new Student4("zhaoyun", 18);
Student4 s3 = new Student4("zhaozilon", 21);
Student4 s4 = new Student4("chanshangzhaozilon", 20);
Student4 s5 = new Student4("chanshangzhaoyun", 20);
Student4 s6 = new Student4("zhaoyun", 22);
Student4 s7 = new Student4("yun", 19);
student4s.add(s1);
student4s.add(s2);
student4s.add(s3);
student4s.add(s4);
student4s.add(s5);
student4s.add(s6);
student4s.add(s7);
for(Student4 student4 : student4s){
System.out.println(student4);
}
}
}
集合的嵌套遍历:
需求:现在有某校有两个班的学生,每个班都有许多学生,每个学生都是一个对象
可以用一个集合表示一个班的学生
15班:ArrayList<Student> classList15
16班:ArrayList<Student> classList16
学校:ArrayList<ArrayList<Student>> school
import java.util.ArrayList;
import java.util.Iterator;
public class ListQianTaotest {
public static void main(String[] args) {
ArrayList<Student2> classList15 = new ArrayList<>();
ArrayList<Student2> classList16 = new ArrayList<>();
ArrayList<ArrayList<Student2>> school = new ArrayList<>();
school.add(classList15);
school.add(classList16);
Student2 s1 = new Student2("小白", 18);
Student2 s2 = new Student2("小辉", 17);
Student2 s3 = new Student2("小青", 16);
Student2 s4 = new Student2("小芳", 20);
//创建十六期的学生对象
Student2 s11 = new Student2("小王", 18);
Student2 s12 = new Student2("小李", 17);
Student2 s13 = new Student2("小刘", 19);
Student2 s14 = new Student2("小杨", 16);
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 (ArrayList<Student2> clazz:school){
System.out.println(clazz);
}
System.out.println("=========================================");
for(int i = 0;i<school.size();i++){
if(i==0){
System.out.println("=============十五班:===================");
for(int j =0 ;j<school.get(i).size();j++){
Student2 student = school.get(i).get(j);
System.out.println(student);
}
}else if(i==1){
System.out.println("=============十六班:===================");
for(int j =0 ;j<school.get(i).size();j++){
Student2 student = school.get(i).get(j);
System.out.println(student);
}
}
}
System.out.println("========================================================");
//迭代器遍历
Iterator<ArrayList<Student2>> iterator = school.iterator();
while (iterator.hasNext()){
ArrayList<Student2> clazz = iterator.next();
Iterator<Student2> iterator1 = clazz.iterator();
while (iterator1.hasNext()){
Student2 student = iterator1.next();
System.out.println(student);
}
}
}
}
class Student2{
private String name;
private int age;
public Student2(){}
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;
}
public Student2(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student2{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student2 student2 = (Student2) o;
if (age != student2.age) return false;
return name != null ? name.equals(student2.name) : student2.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
测试自己定义的集合类底层是Linkedlist:
public class MyStackTest {
public static void main(String[] args) {
//创建自己定义的集合类
MyStack myStack = new MyStack();
//添加元素到集合
myStack.myAdd("hello");
myStack.myAdd("world");
myStack.myAdd("java");
myStack.myAdd("bigdata");
// System.out.println(myStack.myGet());
// System.out.println(myStack.myGet());
// System.out.println(myStack.myGet());
// System.out.println(myStack.myGet());
// System.out.println(myStack.myGet()); //NoSuchElementException
//应该在获取元素之前判断集合中还有没有元素
while (!myStack.myIsEmpty()){
Object o = myStack.myGet();
System.out.println(o);
}
}
}
import java.util.LinkedList;
public class MyStack {
private LinkedList linkedList;
MyStack(){
linkedList = new LinkedList();
}
public void myAdd(Object obj){
linkedList.addFirst(obj);
}
public Object myGet(){
// return linkedList.getFirst();
return linkedList.removeFirst();
}
增强for循环:
概述:简化数组和collection的概述;
格式:for(元素数据类型 变量名:数组或者collection){
使用变量即可,该变量就是元素
}
import java.util.ArrayList;
import java.util.ListIterator;
public class For {
public static void main(String[] args) {
//定义一个数组
int[] arr = {1,2,3,4,5};
//普通for循环遍历
// for(int i=0;i<arr.length;i++){
// System.out.println(arr[i]);
// }
// System.out.println("使用增强for循环遍历数组:");
// for(int num : arr){
// System.out.println(num);
// }
System.out.println("=======================================");
ArrayList<String> strings = new ArrayList<>();
strings.add("hello");
strings.add("world");
strings.add("java");
strings.add("bigdata");
strings.add("hadoop");
for(String string : strings){
System.out.println(string);
// hello
// world
// java
// bigdata
// hadoop
}
// strings = null;
// for(String string : strings){ //NullPointerException
// System.out.println(string);
// }
//我们应该在遍历之前判断一下是不是null
// if(strings!=null){
// for(String string : strings){
// System.out.println(string);
// }
// }else {
// System.out.println("该集合为null");
// }
//其实增强for循环就是用来替代迭代器的
//怎么去验证它就是用来替代迭代器的呢?
//使用并发修改异常去验证
// for(String s : strings){
// //ConcurrentModificationException
// if("java".equals(s)){
// strings.add("spark");
// }
// }
ListIterator<String> iterator = strings.listIterator();
while (iterator.hasNext()){
String next = iterator.next();
if("java".equals(next)){
iterator.add("spark");
}
}
System.out.println(strings);
// [hello, world, java, spark, bigdata, hadoop]
}
}