java SE_4

1. java泛型

1. 怎么理解java泛型

  • 指定创建的集合中只能存放的类型。

  • 泛型是java 1.5引入的新特性,泛型的本质是参数类型化。在类,接口和方法的定义过程中,所操作的数据类型被传入的参数指定。

  • java泛型机制广泛低应用于集合中,所有集合类型都带有泛型, 在创建集合对象的时候,指定集合中元素的类型。

  • java编译器根据泛型的类型,对集合中元素进行类型检查,减少运行的时候错误。

泛型应用场景
  • 泛型类
// class 类名<泛型--泛型代表一种类型,相当于是一个参数.类定义的时候,不知道具体的类型.使用类来创建对象的时候,在指定具体类型.
class MyDog<D> {
   D d;
   public MyDog(D d) {
      this.d = d;
   }
}
  • 使用类型
public static void main(String[] args) {
    MyDog<String> m = new MyDog<>("dd");
    System.out.println(m.d);
    MyDog<D> k = new MyDog<D>(new Date()); // 编译错误 -- 作为一个类型使用的时候,泛型必须指定为某个具体存在的类型.
}
  • 泛型接口
interface MyCat<E>{
    public E getE();
    public void setE(E e);
}
  • 类实现接口的时候, 需要指定具体的类型
class AA implements MyCat<String> {
    @Override
        public String getE() {
        return null;
    } @
    Override
    	public void setE(String o) {
    }
}
  • 泛型方法
class BB{
	// <T> -- 定义方法的发返回值前,代表方法要使用泛型
    public <T> void fun1(T t){
    } 
    public <T> T fun2(T t){
    return t;
    } 
    public <T> String fun3(T t){
        return "hello";
    }
}	
  • 通配符
// <?> 无界通配符,即不确定类型,可以是任意类型
class CC<Z>{
}
// <? extends T> ,上边界通配符, 即?是继承自T的任意子类型 , 遵守只读不写(只能作为返回
值类型)
class DD<T1 extends CC>{
    public void get(T1 t){
    }
}
  • 使用
public class TPFTest {// 通配符测试
   public static void main(String[] args) {
      //限制元素是Number或者Number的子类.
      List<? extends Number> list1 = new ArrayList<>();
      list1.add(null);
      // Number的子类有Integer , Double ,编译器没有办法确定add时的子类对象,所以添加不成功
      Integer i = 100;
      //list1.add( i);编译错误:? extend T 上界类型通配符,只读,不能写. add函数受限制.
      Number number = list1.get(0);//可以取出来使用﹒
      //限制元素是Intger或其父类.
      List<? super Integer> list2 = new ArrayList<>();
      list2.add(100);
      //Integer object = list2.get(0);//编译错误: ? super T下界类型通配符﹐因为没有办法确定父类是谁,只能写,不能读.
      //结论:又要写,又要读,写指定的泛型:
      List<Integer> list = new ArrayList<>();
      list.add(100);
      Integer integer = list.get(0);
   }
}

2. Collection(集合)

2.1 List

(有序(添加元素是有顺序的),可以重复)

  1. List集合的方法——subList
    • List的subList方法用于获取子list
    • subList获取的子list和原来的list占有相同的存储空间,对subList进行操作会影响原来的list. (删除、修改sublist的元素后,list中的对应位置元素也会被修改)

image-20230808133352799

ArrayList

(动态数组,方便获取元素)

public class ListDemo {
   public static void main(String[] args) {
      List<Integer> list = new ArrayList<Integer>();
      //给list赋值0~9
      for(int i = 0; i < 10; i++) {
         list.add(i);
      }
      //截取子串:,[4,8) -- 包含4, 不包含8
      List<Integer> sublist = list.subList(4,8);
      System.out.println(sublist);
      //把list中[4,8)的元素扩大10倍, 输出list
      for(int i = 0; i < sublist.size(); i++) {
         sublist.set(i, sublist.get(i)*10);
      }
      System.out.println("元素扩大10倍:"+list);
      
      //删除
      Iterator iter = list.iterator();
      int index = 0;
      while (iter.hasNext()) {
         if(index++ % 2 != 0) { //奇数
            iter.next();
            iter.remove();
         }

         if (index >= list.size()) {break;}
      }
      System.out.println("删除后:"+list);
   }
}
LinkedList

(链表,方便插入和删除元素)

// LinkedList中的方法和ArrayList中的方法大部分相同。
public class LinkedListDemo {
   public static void main(String[] args) {
      // 1. 创建对象
      LinkedList<Point> ps = new LinkedList<>(); // ps能调用到LinkedList中的所有方法
      List<Point> ps1 = new LinkedList<>(); //ps1能调用到List中的所有方法。
      Collection<Point> ps2 = new LinkedList<>();//说明ps2这个引用只能调用到Collection接口中定义的方法
      // 2. LinkedList的方法
      ps.add(new Point(1, 2)); //增加
      ps.add(new Point(2, 3));
      ps.add(new Point(3, 4));
      Point point = ps.get(2);//根据索引位置找system . out. println(point . x+"-” + point. y );//插入
      ps.add(1, new Point(10, 10));
      System.out.println(ps);

      //插入
      ps.add(1, new Point(10, 10));//有序system . out.println(ps ) ;
      ps.add(point); //可以重复
      System.out.println(ps);
      ps.remove(ps.size() - 1);//删除最后一个元素
      System.out.println(ps);

      //最后一个和第一个交换位置
      Point temp = ps.get(0);
      ps.set(0, ps.get(ps.size() - 1));
      ps.set(ps.size() - 1, temp);
      System.out.println(ps);

      //循环遍历集合 -- 迭代器
      Iterator<Point> iterator = ps.iterator();
      while (iterator.hasNext()) {
         System.out.print(iterator.next() + "\t");
      }
      System.out.println();
      // lambda -- forEach方法
      ps.forEach((one) -> {
         System.out.print(one + "\t");
      });

      //清除集合中的元素
      ps.clear();

      System.out.println(ps.isEmpty());


   }
}

class Point {
   int x, y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }

   @Override
   public String toString() {
      return "Point{" +
            "x=" + x +
            ", y=" + y +
            '}';
   }
}

2.2 Set集合(无序,不可以重复)

  • Set 用于存储不重复的对象集合, set集合中存储的对象,不存在两个对象的equals相等。
  • HashSet 和 TreeSet是Set集合的两个常用实现类。
  • HashSet 用hash表实现了Set集合。
  • TreeSet 用排序二叉树实现了Set集合。
HashSet
  • 通过hash算法实现,频率较大
TreeSet
  • Tree的各种算法,频率一般

  • 测试:

// Set extends Collectoin
public class SetDemo {
   public static void main(String[] args) {
      Set<String> sets = new HashSet<String>();
      // Set 无序: 添加的元素,在集合中没有顺序
      // Set 不重复:
      sets.add("A");
      sets.add("C");
      sets.add("D");
      sets.add("B");
      sets.add("D");
      sets.add("B");
      System.out.println(sets);
      // 其他方法
      System.out.println(sets.size());
      sets.addAll(sets);
      System.out.println(sets);
      sets.remove("A");
      System.out.println(sets);
      //遍历
      for (String s : sets) {
         System.out.println(s);
      }

      sets.forEach(x -> {
         System.out.println(x);
      });
      //简写
      sets.forEach(System.out::println);
      //练习:在集合中存储20个不重复的100以内的整数
      Random r = new Random();
      Set<Integer> set = new HashSet<>();
      int count = 0;
      while (set.size() < 20) {
         count++;
         set.add(r.nextInt(100));
      }
      System.out.println("count: " + count);
      System.out.println("长度:" + set.size() + " \n" + set);

      //产生6个红球。
      Set<Integer> redSet = new HashSet<>();
      while (redSet.size() < 6) {
         redSet.add(r.nextInt(32) + 1);
      }
      System.out.println("红球:" + redSet);

      //练习:数组元素去重
      int[] arr = {1, 2, 32, 3, 43, 2, 1};
      Set<Integer> newArr = new HashSet<>();
      for (int i : arr) {
         newArr.add(i);
      }
      System.out.println("不重复的数组:" + newArr);
   }
}

2.3 Map集合(key-value)

Entry:Map中的一个键值对就是一个Entry。

  • Map集合主要用于存储“key-value”键值对的数据,key可以看作是value的索引,通过key,查找到value值, key不能重复。
  • Map是一个interface , 有多种实现类,比如hash表实现的HashMap ,排序二叉树实现的TreeMap等
  • HashMap是Map比较常用的实现类。
  • Map接口中常用的get,put方法
  • Map测试:
//方法调用
public class MapDemo {
   public static void main(String[] args) {
      //存储数据:语文-80 ,数学-70,英语-50. ( key-value)
      Map<String, Integer> map = new HashMap<>();
      //增加数据
      map.put("语文", 80);
      map.put("语文", 80);
      map.put("数学", 70);
      map.put("英语", 60);
      System.out.println(map); // {数学 = 70,语文 = 80,英语 = 60}//是否包含
      System.out.println(map.containsKey("语文")); //true
      System.out.println(map.containsValue(70)); //ture

      //元素个数
      System.out.println(map.size());
      map.put("语文", 90); // ** key不存在,则添加,key不存在就修改。
      System.out.println(map);

      //根据key找到value
      System.out.println(map.get("语文"));
      System.out.println(map.get("数学"));

      //根据key删除集合中的元素
      Integer 语文 = map.remove("语文");  // 删除成功的返回值是该key对应的value值

      //key的Set集合
      Set<String> keys = map.keySet();
      System.out.println(keys);
      //values的Collection集合
      Collection<Integer> values = map.values();
      System.out.println(values);
   }
}

//Map的遍历:
class MapDemo3 {
	public static void main(String[] args) {
		//存储数据:语文-80 ,数学-70,英语-50 . ( key-value)
		Map<String, Integer> map = new HashMap<>();
		//增加数据
		map.put("语文", 80);
		map.put("数学", 70);
		map.put("英语", 60);
		map.put("物理", 70);
		map.put("化学", 60);
		//遍历(把键值对都获取到)
		Set<Map.Entry<String, Integer>> entries = map.entrySet(); //把Map转换位Set.
		for (Map.Entry<String, Integer> entry : entries) {
			// entry就是一个键值对的数
			System.out.println(entry.getKey() + "----" + entry.getValue());
		}
		System.out.println("---------------------");
		//根据key ,找到value
		Set<String> strings = map.keySet();
		for (String key : strings) {
			System.out.println(key + "----" + map.get(key));
		}
		System.out.println("---------------------");
		map.forEach((k, v) ->
				System.out.println(k + ":" + v)
		);
	}
}

2.4 集合的遍历

terator

迭代器类:迭代器,遍历集合

  • 所有Collection的实现类,都实现了iterator方法, 该方法返回一个Iterator接口类型的对象,用于对于集合中的元素进行迭代遍历。
  • Iterator中有三个方法:
    boolean hasNext(); // 判断是否还有下一个元素
    E next(); // 取出下一个元素
    default void remove();//删除元素

image-20230808161315348

增强for循环
  • jdk1.5中,推出了增强型for循环的语法,适用于遍历数组和集合中的元素。

image-20230808161440014

2.5 集合的排序(针对有序集合)

Collections

操作集合的工具类(可以通过类名直接使用方法的类)

**Collections类中提供了一些对集合操作的方法,其中比较常用的有对List的排序方法。如果要使用Collections.sort()方法进行对集合中的元素排序,那么要求集合中的元素是实现类Comparable接口的,即对象可以比较大小。 **

Comparable

类实现这个接口,就可以比较大小。

  • 针对对象数组或者集合中的元素进行排序的时候,首先需要确定元素的比较逻辑,制定比较的比较规则。
  • jdk中的Comparable接口 , 定义了对象间大小比较的方法, 需要大小比较的类,可以实现该接口。
// Comparable -是接口,
//- compareTo (o) , 比较大小
public class ComparableDemo {
   public static void main(String[] args) {
      String s = "tome";
      String s1 = "Jack";
      int i = s.compareTo(s1); // i>0表示s大 , i==0,表示相等,i<o ,表示s小.
      System.out.println(i); // 42
      if (i > 0) {
         System.out.println("tom 比 Jack 大");
      } else {
         System.out.println("tom 比 Jack 小");
      }

      Student tom = new Student("tom", 19);
      Student jack = new Student("jack", 21);
      int a = tom.compareTo(jack);
      if (a > 0) {
         System.out.println("tom大");
      } else if (a == 0) {
         System.out.println("一样大");
      } else {
         System.out.println("jack大");
      }

      //练习:创建5个学生,保存到List中,然后按年龄排序
      Student stu1 = new Student("A", 21);
      Student stu2 = new Student("B", 20);
      Student stu3 = new Student("C", 19);
      Student stu4 = new Student("D", 18);
      Student stu5 = new Student("E", 17);
      List<Student> list = new LinkedList<>();
      list.add(stu1);
      list.add(stu2);
      list.add(stu3);
      list.add(stu4);
      list.add(stu5);
      System.out.println("原集合顺序:" + list);
      Collections.sort(list); // Collections -- 操作集合的工具类,提供sort方法。
      System.out.println("排序后:" + list);
   }
}

//判断两个学生的年龄大小
class Student implements Comparable<Student> {
   String name;
   int age;

   public Student(String name, int age) {
      this.name = name;
      this.age = age;
   }

   @Override
   public int compareTo(Student o) {
      return this.age - o.age;
   }

   @Override
   public String toString() {
      return "Student{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
   }
}
Comparator

函数式接口。排序的时候,通过工具类Collections.sort(集合,Comparator(重写大小比较规则))方法,可以实现这个接口(lambda表达式),然后自定义比较规则。

  • 比较规则:

    public int compareTo(T o);
    返回正数: this > o
    返回负数: this < o
    返回0 : this == o

public class ComparatorDemo {
   public static void main(String[] args) {
      List<String> strs = new ArrayList<>();
      strs.add("hello");
      strs.add(" tom");
      strs.add("nice to meet you .");
      strs.add("hi");
      strs.add("hanmeimei");
      Collections.sort(strs); // 采用字符串的默认排序规则: 按字母表顺序
      System.out.println(strs);
      /* 使用匿名内部类,代码太长
      Collections.sort(strs, new Comparator<String>() {
         @Override
         public int compare(String o1, String o2) {
            return o1.length() - o2.length();
         }
      });
      */
      // 使用lambda表达式简化代码
      Collections.sort(strs, (o1, o2) -> {
         return o1.length() - o2.length();//修改大小比较规则:按字符串长度
      });
      System.out.println(strs);
   }
}

2.6 队列和栈

Queue–队列
  • 队列是常用的数据结构,可以将队列堪称是特殊的线性表,队列只能从一端添加元素(offer),另一端取出元素(poll)
  • 队列遵循先进先出的原则(FIFO, first in first out)
  • Queue是jdk中的接口, LinkedList是Queue的实现类。
  • Queue接口中的主要方法:
boolean offer(E e);将一个对象添加至队尾,如果添加成功则返回true
E poll0;从队首删除并返回一个元素。
E peek);返回队首的元素(但并不删除)。
  • 测试:
public class QueueDemo {
   public static void main(String[] args) {
      Queue<String> queue = new LinkedList<>();
      //元素入队
      queue.offer("A");
      queue.offer("B");
      queue.offer("C");
      queue.offer("D");
      //元素出队
      System.out.println("对首元素:" + queue.peek()); //"A"最先进入.所有A是队首元素

      //循环出队
      while (queue.peek() != null) {
         System.out.println(queue.poll()); //出队
      }

      String poll = queue.poll();//如果队列中没有元素了了.返回值是null.
      queue.offer("E");
      System.out.println("对首:" + queue.peek());
   }
}
Deque–栈
  • Deque是Queue的子接口, 被称为双端队列,即可以从队列的两端入队(offer),出队

    (poll),LinkedList实现了该接口。

  • 将Deque限定为为只能从一端出队和入队,就可以模拟栈的数据结构,栈数据结构,入栈为push,出栈为pop.

  • 栈遵循先进后出的原则FILO(first int last out)

image-20230808181029786

  • 测试
// 使用Deque -双端队列模拟出栈的数据结构:控制元素从一端进出.
// -- push(压入) , pop(弹出)
public class StatckDemo {
   public static void main(String[] args) {
      Deque<String> statck = new LinkedList<>();
      statck.push("小A");
      statck.push("小A");
      statck.push("小A");
      statck.push("小A");
      //栈最先出的元素:
      System.out.println("最先出栈的元素:" + statck.peek());//出栈操作
      statck.pop(); //出去小D
      statck.pop();//出去小C
      System.out.println("即将要出去的元素:" + statck.peek());
      statck.push("小E");
      statck.push("小F");
      System.out.println("即将要出去的元素:" + statck.peek());

      statck.pop(); //小F
      statck.pop(); //小E
      statck.pop(); //小B;
      statck.pop(); //小A;
      System.out.println("即将要出去的元素:" + statck.peek());
      //空栈,继续弹出元素,抛出异常
      statck.pop(); // java.util.NoSuchElementException
   }
}

3. 练习:

  • 定义一个人类(id ,name , 升高, 体重) , 然后创建5个人,添加到集合中, 按bmi指数升序排序。
public class home {
   public static void main(String[] args) {
      List<Person> list = new ArrayList<>();
      list.add(new Person(10082,"小红",1.59,60));
      list.add(new Person(10083,"小绿",1.87,61));
      list.add(new Person(10084,"小蓝",1.45,64));
      list.add(new Person(10085,"小青",1.63,68));
      list.add(new Person(10086,"小紫",1.71,69));
      System.out.println("原集合:"+list);
      Collections.sort(list);
      System.out.println("排序后:"+list);
      //输出id, height ,bmi
      list.forEach(p->{
         System.out.println(p.getId()+"---"+p.getHeight()+"---"+p.getBMI());
      });
      System.out.println("按身高排序");
      Collections.sort(list,(x1, x2)->{
         if (x1.getHeight() - x2.getHeight() > 0) {
            return 1;
         }
         if (x1.getHeight() - x2.getHeight() < 0){
            return -1;
         }
         return 0;
      });
      //输出id, high
      list.forEach(p ->{
         System.out.println(p.getId() + "---" + p.getHeight());
      });
   }
}
class Person implements Comparable<Person>{
   private int id;
   private String name;
   private double height;
   private double weight;

   public Person(int id, String name, double height, double weight) {
      this.id = id;
      this.name = name;
      this.height = height;
      this.weight = weight;
   }

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public double getHeight() {
      return height;
   }

   public void setHeight(double height) {
      this.height = height;
   }

   public double getWeight() {
      return weight;
   }

   public void setWeight(double weight) {
      this.weight = weight;
   }

   public double getBMI(){
      //BMI即体质指数,是指体重除以身高的平方。
      return weight / height * height;
   }

   @Override
   public String toString() {
      return "Person{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", height=" + height +
            ", weight=" + weight +
            '}';
   }

   @Override
   public int compareTo(Person o) {
      if (this.getBMI() - o.getBMI() > 0){
         return 1;
      }
      if (this.getBMI() - o.getBMI() < 0){
         return -1;
      }
      return 0;
   }

   @Override
   public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;
      Person person = (Person) o;
      return id == person.id;  // id相等就表示两个对象相等。
   }

   @Override
   public int hashCode() {
      return Objects.hash(id, name, height, weight);
   }
}

ArrayList 和 LinkedList区别

  1. List接口的两个实现类分别用ArrayList , LinkedList 。
  2. ArrayList & LinkedList都是有序可重复的集合。
  3. ArrayList用动态数组实现,适合于随机访问
  4. LinkedList用链表实现,适合于插入和删除。
  5. ArrayList和LinkedList的方法一样,但是性能不同。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值