当前位置: 代码迷 >> 综合 >> Java:泛型,set集合,增强for循环、TreeSet、静态导入、可变参数
  详细解决方案

Java:泛型,set集合,增强for循环、TreeSet、静态导入、可变参数

热度:19   发布时间:2023-12-06 08:21:15.0

泛型:

把明确的数据类型工作提前到编译时期,在创建集合的时候明确存储元素的类型。这样的做法有点像把数据类型当参数一样传递,所以泛型还有一个叫法:参数化类型

泛型语句的定义格式:

<引用数据类型>:注意尖括号里的数据类型只能是引用数据类型;

泛型的好处:

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>{@Overridepublic 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) {//MathSystem.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;}@Overridepublic 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;}@Overridepublic int hashCode() {int result = name != null ? name.hashCode() : 0;result = 31 * result + age;return result;}@Overridepublic 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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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> {@Overridepublic 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>() {@Overridepublic 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;}@Overridepublic String toString() {return "Student2{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic 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;}@Overridepublic 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]}
}

  相关解决方案