Java基础

canace
2023-03-03 / 0 评论 / 403 阅读 / 正在检测是否收录...

Java快速入门

Java基础语法

image-20230302203355420

image-20230302203451452

Java基础语法

类型转换

image-20230302203654398

运算符

image-20230302203744572

image-20230302203804452

键盘录入技术

image-20230302203831731

程序流程控制

程序流程控制是控制代码怎么去执行的

顺序结构

代码按照顺便正常执行

分支结构

image-20230302204059984

循环结构

image-20230302204214019

跳转关键字(break,continue)

image-20230302204323359

随机数Random类

image-20230302204401074

数组

作用

一个容器,用于在程序中存储一批同种类型的数据

定义

image-20230302204645042

遍历

image-20230302204704158

常见问题

image-20230302204712003

方法

作用

封装一段代码的语法结构,可以被重复调用,以此提高代码的复用性,提高开发效率,让程序逻辑更清晰

定义格式

修饰符 返回值类型 方法名(形参列表){
    方法体代码(需要执行的功能代码)
        return 返回值;
}
//如果方法没有返回结果,返回值类型申明为:void
//方法需要调用才能执行

注意事项

image-20230302205134451

方法重载

image-20230302205202138

return

跳出并立即结束当前方法的执行

面向对象编程(oop)

定义(思想)

java 万物皆对象

image-20230302210350561

创建对象

image-20230302210435446

构造器

image-20230302210535185

this关键字

image-20230302210604823

封装

image-20230302210624597

常用API(String、ArrayList)

String

image-20230302211234718

image-20230302211252203

ArrayList

image-20230302211322867

static

image-20230302212136883

image-20230302212211455

饿汉单例代码示例:

/**
   使用饿汉单例实现单例类
 */
public class SingleInstance {

    /**
      2、饿汉单例是在获取对象前,对象已经提前准备好了一个。
       这个对象只能是一个,所以定义静态成员变量记住。
     */
    public static SingleInstance instance = new SingleInstance();

    /**
       1、必须把构造器私有化。
     */
    private SingleInstance(){
    }
}

懒汉单例代码示例:

/**
   懒汉单例
 */
public class SingleInstance2 {

    /**
      2、定义一个静态的成员变量负责存储一个对象。
         只加载一次,只有一份。
       注意:最好私有化,这样可以避免给别人挖坑!
     */
    private static SingleInstance2 instance;

    /**
      3、提供一个方法,对外返回单例对象。
     */
    public static SingleInstance2 getInstance() {
        if(instance == null){
            // 第一次来拿对象 :此时需要创建对象。
            instance = new SingleInstance2();
        }
        return instance;
    }


    /**
       1、私有化构造器
     */
    private SingleInstance2(){
    }
}

继承

image-20230302212412792

image-20230302212431933

权限修饰符

image-20230302212823640

final

image-20230302212844962

常量

image-20230302212912202

枚举

image-20230302212935595

抽象类

image-20230302213006458

接口

image-20230302213030223

多态

定义

  • 多态是同一个行为具有不同的表现形式或形态的能力
  • 同一方法可以根据发送对象的不同而采用不同的行为方式
  • 多态就是事物的多种形态,一个对象在不同条件下所表现的不同形式

存在条件

  • 继承或实现:在多态中必须存在有继承或实现关系的子类和父类
  • 方法的重写:子类对父类中的某些方法进行重新定义(重写,使用@Override注解进行重写)
  • 基类引用指向派生类对象,即父类引用指向子类对象,父类类型:指子类对象继承的父类类型,或实现的父接口类型

格式

父类类型  变量名 = new 子类类型();
然后通过 变量名.方法名()调用在子类中重写的方法
多态体现为父类引用变量可以指向子类对象:定义了一个父类类型的引用,指向新建的子类类型的对象,由于子类是继承他的父类的,所以父类类型的引用是可以指向子类类型的对象的

特点

  • 多态情况下,子类和父类存在同名的成员变量时,访问的时父类的成员变量
  • 多态情况下,子父类存在同名的非静态成员方法时,访问的是子类中重写的方法
  • 多态情况下,子父类存在同名的静态成员变量成员方法时,访问的是父类的成员函数
  • 多态情况下,不能访问子类独由的方法

instanceof关键字

格式

变量名  instanceof   数据类型
//如果变量属于该数据类型或者其子类型,返回true
//如果变量不属于该数据类或者其子类型,返回false

代码示例

 
public class DemoApplication {
 
    public static void main(String[] args) {
 
        //向上转型
        //父类类型 对象 = new 子类类型()
        Animal animal = new Cat();
 
 
        //向下转型
        //子类类型 子类变量名 = (子类类型) 父类变量名
        if ( animal instanceof Cat){
            Cat cat = (Cat) animal;
            cat.sleep();
        }else if(animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.walk();
        }
 
    }
}

集合

  • 数组的长度是固定的。集合的长度是可变的。
  • 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。

Colloction

Colloction常用API

public boolean add(E e): 把给定的对象添加到当前集合中 。

public void clear():清空集合中所有的元素。

public boolean remove(E e): 把给定的对象在当前集合中删除。

public boolean contains(Object obj): 判断当前集合中是否包含给定的对象。

public boolean isEmpty(): 判断当前集合是否为空。

public int size(): 返回集合中元素的个数。

public Object[] toArray(): 把集合中的元素,存储到数组中

Iterator 迭代器

迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。

常用方法

public E next():返回迭代的下一个元素。
public boolean hasNext():如果仍有元素可以迭代,则返回 true。

代码示例

public class IteratorDemo {
      public static void main(String[] args) {
        // 使用多态方式 创建对象
        Collection<String> coll = new ArrayList<String>();

        // 添加元素到集合
        coll.add("串串星人");
        coll.add("吐槽星人");
        coll.add("汪星人");
        //遍历
        //使用迭代器 遍历   每个集合对象都有自己的迭代器
        Iterator<String> it = coll.iterator();
        //  泛型指的是 迭代出 元素的数据类型
        while(it.hasNext()){ //判断是否有迭代元素
            String s = it.next();//获取迭代出的元素
            System.out.println(s);
        }
      }
}
//注意,如果集合没有元素使用迭代器的next的方法会java.util.NoSuchElementException没有集合元素的错误。

删除元素

常用在集合Collection的remove方法无法根据条件删除

代码示例:

    @Test
    public void test02(){
        Collection<String> coll = new ArrayList<>();
        coll.add("陈琦");
        coll.add("李晨");
        coll.add("邓超");
        coll.add("黄晓明");
        
        //删除名字有三个字的
//        coll.remove(o)//无法编写
        
        Iterator<String> iterator = coll.iterator();
        while(iterator.hasNext()){
            String element = iterator.next();
            if(element.length()==3){
//                coll.remove(element);//错误的
                iterator.remove();
            }
        }
        System.out.println(coll);
    }

增强for

示例:

for(元素的数据类型  变量 : Collection集合or数组){ 
      //写操作代码
}

List

特点

  • List集合所有的元素是以一种线性方式进行存储的,例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)
  • 它是一个元素存取有序的集合。即元素的存入顺序和取出顺序一致。
  • 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
  • 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。

常用方法

1.添加元素
void add(int index, E ele)
boolean addAll(int index, Collection<? extends E> eles)
    
2、获取元素
E get(int index)
List subList(int fromIndex, int toIndex)
    
3、获取元素索引
int indexOf(Object obj)
int lastIndexOf(Object obj)
    
4、删除和替换元素
E remove(int index)
E set(int index, E ele)

实现类

ArrayList集合

java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList最常用的集合

代码示例
class Example2{
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("a");
        arrayList.add("b");
        arrayList.add("c");
        System.out.println("arrayList的元素为:"+arrayList);
        arrayList.set(0,"c");   //将索引为0的位置对象a修改为对象c
        System.out.println("arrayList的元素为"+arrayList);
        arrayList.add(1,"e");   //将对象e添加到索引为1的位置
        System.out.print("arrayList的元素为:");
        for (int i=0;i<arrayList.size();i++){
            System.out.print(arrayList.get(i));//for循环迭代arrayList集合元素
        }
        System.out.println("");
        System.out.println("arrayList指定元素c位置的索引为"+arrayList.indexOf("c"));
        //返回列表中指定元素c位置的索引
        System.out.println("arrayList指定元素c最后位置的索引为"+arrayList.lastIndexOf("c")); 
          //返回列表中指定元素c最后位置的索引
        System.out.println("arrayList的指定区域为"+arrayList.subList(1,2));
        //返回列表中指返回一个指定区域的List集合对象[1,2)
    }
}
LinkedList集合

java.util.LinkedList集合数据存储的结构是链表结构(双链表)。方便元素添加、删除的集合。

代码示例
public class Example3 {
    public static void main(String[] args) {
 
        LinkedList linkedList = new LinkedList();
        linkedList.add("a");
        linkedList.add("b");
        linkedList.add("c");
        linkedList.add("d");
        //获得并输入列表开头的对象
        System.out.println("列表开头元素为:"+linkedList.getFirst()+"列表结尾元素为:"+linkedList.getLast());
 
        linkedList.addFirst("rr");    //向列表开头添加一个对象
        System.out.println("列表中所有元素:"+linkedList);
        linkedList.removeLast();//移除列表结尾元素
        System.out.println("列表结尾元素为:"+linkedList.getLast());
         //获取并输出列表结尾的对象
    }
}
Listlterator

List 集合额外提供了一个 listIterator() 方法,该方法返回一个 ListIterator 对象, ListIterator 接口继承了 Iterator 接口,提供了专门操作 List 的方法:

代码示例
    public static void main(String[] args) {
        List<Student> c = new ArrayList<>();
        c.add(new Student(1,"张三"));
        c.add(new Student(2,"李四"));
        c.add(new Student(3,"王五"));
        c.add(new Student(4,"赵六"));
        c.add(new Student(5,"钱七"));
        
        //从指定位置往前遍历
        ListIterator<Student> listIterator = c.listIterator(c.size());
        while(listIterator.hasPrevious()){
            Student previous = listIterator.previous();
            System.out.println(previous);
        }
    }

Set

特点

  1. 特点:无序,不重复
  2. 遍历:foreach,迭代器
  3. 扩容: 初始容量16,负载因子0.75,扩容增量1倍

实现类

HsshSet
特点
  1. 它存储唯一元素并允许空值,依据对象的hashcode来确定该元素是否存在
  2. 由HashMap支持
  3. 不保持插入顺序(无序)
  4. 非线程安全
  5. 性能参数:初始容量,负载因子,默认值: 初始容量16,负载因子0.75,示例:new HashSet<>(20, 0.5f);
注意

HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。

HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。因此,存储到HashSet的元素要重写hashCode和equals方法。

LinkedHashSet

LinkedHashSet是HashSet的子类,它在HashSet的基础上,在结点中增加两个属性before和after维护了结点的前后添加顺序。

java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。(保持插入顺序)

TreeSet
特点
  1. 是一个包含有序的且没有重复元素的集合
  2. 作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序
  3. TreeSet是基于TreeMap实现的
代码示例
//演示两种自定义排序方法
//1. 较器通过构造函数传入比
TreeSet<Integer> tset = new TreeSet<Integer>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                // TODO Auto-generated method stub
                return o2 - o1;
            }
        });

//2.对象类中定义
@Override
    public int compareTo(Student o) {
        if (this.getAge() - o.getAge() == 0) {
            return this.getSid() - o.getSid();
        }
        return this.getAge() - o.getAge();
    }

Map

概述

现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射。Java提供了专门的集合类用来存放这种对象关系的对象,即java.util.Map<K,V>接口。

我们通过查看Map接口描述,发现Map<K,V>接口下的集合与Collection<E>接口下的集合,它们存储数据的形式不同。

  • Collection中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。
  • Map中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的值
  • Collection中的集合称为单列集合,Map中的集合称为双列集合。
  • 需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值(这个值可以是单个值,也可以是个数组或集合值)。

常用API

public class MapDemo {
    public static void main(String[] args) {
        //创建 map对象
        HashMap<String, String>  map = new HashMap<String, String>();

        //添加元素到集合
        map.put("黄晓明", "杨颖");
        map.put("文章", "马伊琍");
        map.put("邓超", "孙俪");
        System.out.println(map);

        //String remove(String key)
        System.out.println(map.remove("邓超"));
        System.out.println(map);

        // 想要查看 黄晓明的媳妇 是谁
        System.out.println(map.get("黄晓明"));
        System.out.println(map.get("邓超"));    
    }
}
//使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;
//若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。

遍历

public class TestMap {
    public static void main(String[] args) {
        HashMap<String,String> map = new HashMap<>();
        map.put("许仙", "白娘子");
        map.put("董永", "七仙女");
        map.put("牛郎", "织女");
        map.put("许仙", "小青");
        //单独遍历key和值
        System.out.println("所有的key:");
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            System.out.println(key);
        }
        
        System.out.println("所有的value:");
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);
        }
        //同时遍历key-value  entrySet()
        System.out.println("所有的映射关系");
        Set<Map.Entry<String,String>> entrySet = map.entrySet();
        for (Map.Entry<String,String> entry : entrySet) {
            System.out.println(entry.getKey()+"->"+entry.getValue());
        }
    }
}

实现类

HashMap

HashMap线程不安全,允许使用null键和null值;Hashtable是线程安全的,任何非 null 对象都可以用作键或值。

LinkedHashMap

维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。

TreeMap

基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

package com.atguigu.map;

import java.util.Comparator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import org.junit.Test;

public class TestTreeMap {
    @Test
    public void test1() {
        TreeMap<String,Integer> map = new TreeMap<>();
        map.put("Jack", 11000);
        map.put("Alice", 12000);
        map.put("zhangsan", 13000);
        map.put("baitao", 14000);
        map.put("Lucy", 15000);
        
        //String实现了Comparable接口,默认按照Unicode编码值排序
        Set<Entry<String, Integer>> entrySet = map.entrySet();
        for (Entry<String, Integer> entry : entrySet) {
            System.out.println(entry);
        }
    }
    @Test
    public void test2() {
        //指定定制比较器Comparator,按照Unicode编码值排序,但是忽略大小写
        TreeMap<String,Integer> map = new TreeMap<>(new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                return o1.compareToIgnoreCase(o2);
            }
        });
        map.put("Jack", 11000);
        map.put("Alice", 12000);
        map.put("zhangsan", 13000);
        map.put("baitao", 14000);
        map.put("Lucy", 15000);
        
        Set<Entry<String, Integer>> entrySet = map.entrySet();
        for (Entry<String, Integer> entry : entrySet) {
            System.out.println(entry);
        }
    }
}

Collections工具类

Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,而且支持自然排序
public static T max(Collection<? extends T> coll,Comparator<? super T> comp)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,按照比较器comp找出最大者
public static void reverse(List<?> list)反转指定列表List中元素的顺序。
public static void shuffle(List<?> list) List 集合元素进行随机排序,类似洗牌
public static <T extends Comparable<? super T>> void sort(List list)根据元素的自然顺序对指定 List 集合元素按升序排序
public static void sort(List list,Comparator<? super T> c)根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
public static void swap(List<?> list,int i,int j)将指定 list 集合中的 i 处元素和 j 处元素进行交换
public static int frequency(Collection<?> c,Object o)返回指定集合中指定元素的出现次数
public static void copy(List<? super T> dest,List<? extends T> src)将src中的内容复制到dest中
public static boolean replaceAll(List list,T oldVal,T newVal):使用新值替换 List 对象的所有旧值

Stream

Stream流是对集合(Collection)对象功能的增强,与Lambda表达式结合,可以提高编程效率、间接性和程序可读性。

特点

1、代码简洁:函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环

2、多核友好:Java函数式编程使得编写并行程序如此简单,就是调用一下方法

流程

创建流

Stream创建
Stream<Integer> stream1 = Stream.of(1,2,3,4,5);
Collection集合创建(应用中最常用的一种)
List<Integer> integerList = new ArrayList<>();
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);
        integerList.add(4);
        integerList.add(5);
        Stream<Integer> listStream = integerList.stream();
Array数组创建
int[] intArr = {1, 2, 3, 4, 5};
IntStream arrayStream = Arrays.stream(intArr);

通过Arrays.stream方法生成流,并且该方法生成的流是数值流【即IntStream】而不是 Stream

注:

使用数值流可以避免计算过程中拆箱装箱,提高性能。

Stream API提供了mapToInt、mapToDouble、mapToLong三种方式将对象流【即Stream 】转换成对应的数值流,同时提供了boxed方法将数值流转换为对象流

文件创建
try {
            Stream<String> fileStream = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
        } catch (IOException e) {
            e.printStackTrace();
        }
//把流创建在try(){}的()里可以在结束时自动关闭该流

通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行

函数创建

iterator

Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2).limit(5);

iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数

generator

Stream<Double> generateStream = Stream.generate(Math::random).limit(5);

generate方法接受一个参数,方法参数类型为Supplier ,由它为流提供值。generate生成的流也是无限流,因此通过limit对流进行了截断

操作流

中间操作符
//1、filter:输出ID大于6的user对象(过滤)
List<User> filetrUserList = userList.stream().filter(user -> user.getId() > 6).collect(Collectors.toList());
filetrUserList.forEach(System.out::println);

//2、map
List<String> mapUserList = userList.stream().map(user -> user.getName() + "用户").collect(Collectors.toList());
mapUserList.forEach(System.out::println);

//3、distinct:去重
//User::getCity() 完全写法为:user -> user.getCity()
List<String> distinctUsers =  userList.stream().map(User::getCity).distinct().collect(Collectors.toList());
distinctUsers.forEach(System.out::println);

//4、sorted:排序,根据名字倒序
userList.stream().sorted(Comparator.comparing(User::getName).reversed()).collect(Collectors.toList()).forEach(System.out::println);

//5、limit:取前5条数据
userList.stream().limit(5).collect(Collectors.toList()).forEach(System.out::println);

//6、skip:跳过第几条取后几条
userList.stream().skip(7).collect(Collectors.toList()).forEach(System.out::println);

//7、flatMap:数据拆分一对多映射
userList.stream().flatMap(user -> Arrays.stream(user.getCity().split(","))).forEach(System.out::println);

//8、peek:对元素进行遍历处理,每个用户ID加1输出
userList.stream().peek(user -> user.setId(user.getId()+1)).forEach(System.out::println);
终端操作符
//1、collect:收集器,将流转换为其他形式
Set set = userList.stream().collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("--------------------------");
List list = userList.stream().collect(Collectors.toList());
list.forEach(System.out::println);

//2、forEach:遍历流
userList.stream().forEach(user -> System.out.println(user));
userList.stream().filter(user -> "上海".equals(user.getCity())).forEach(System.out::println);

//3、findFirst:返回第一个元素
User firstUser = userList.stream().findFirst().get();
User firstUser1 = userList.stream().filter(user -> "上海".equals(user.getCity())).findFirst().get();

//4、findAny:将返回当前流中的任意元素
User findUser = userList.stream().findAny().get();
User findUser1 = userList.stream().filter(user -> "上海".equals(user.getCity())).findAny().get();

//5、count:返回流中元素总数
long count = userList.stream().filter(user -> user.getAge() > 20).count();
System.out.println(count);

//6、sum:求和
int sum = userList.stream().mapToInt(User::getId).sum();

//7、max:最大值
int max = userList.stream().max(Comparator.comparingInt(User::getId)).get().getId();

//8、min:最小值
int min = userList.stream().min(Comparator.comparingInt(User::getId)).get().getId();

//9、anyMatch:检查是否至少匹配一个元素
boolean matchAny = userList.stream().anyMatch(user -> "北京".equals(user.getCity()));

//10、allMatch:检查是否匹配所有元素
boolean matchAll = userList.stream().allMatch(user -> "北京".equals(user.getCity()));

//11、noneMatch:检查是否没有匹配所有元素,返回boolean
boolean nonaMatch = userList.stream().allMatch(user -> "云南".equals(user.getCity()));

//12、reduce:将流中元素反复结合起来,得到一个值
Optional reduce = userList.stream().reduce((user, user2) -> {
   return user;
});
if(reduce.isPresent()) System.out.println(reduce.get());

Collect收集

//1.toList() 将用户ID存放到List集合中
 List<Integer> idList = userList.stream().map(User::getId).collect(Collectors.toList()) ;

//2.toMap() 将用户ID和Name以Key-Value形式存放到Map集合中
Map<Integer,String> userMap = userList.stream().collect(Collectors.toMap(User::getId,User::getName));

//3.toSet() 将用户所在城市存放到Set集合中
Set<String> citySet = userList.stream().map(User::getCity).collect(Collectors.toSet());

//4.counting() 符合条件的用户总数
long count = userList.stream().filter(user -> user.getId()>1).collect(Collectors.counting());

//5.summingInt() 对结果元素即用户ID求和
Integer sumInt = userList.stream().filter(user -> user.getId()>2).collect(Collectors.summingInt(User::getId)) ;

//6.minBy() 筛选元素中ID最小的用户
User maxId = userList.stream().collect(Collectors.minBy(Comparator.comparingInt(User::getId))).get() ;

//7.joining() 将用户所在城市,以指定分隔符链接成字符串;
String joinCity = userList.stream().map(User::getCity).collect(Collectors.joining("||"));

//8.groupingBy() 按条件分组,以城市对用户进行分组;
Map<String,List<User>> groupCity = userList.stream().collect(Collectors.groupingBy(User::getCity));

异常

image-20230303152454680

try( 
    //此处使用如stream流之类的需要使用后关闭的
){
    //此处使用正常的主体代码
}catch(Exception e){
    //打印异常或写入日志
}finally{
    //不管程序是否异常,这里都会执行
}

File和IO流

File对象

创建File对象

 public static void main(String[] args) {
        //创建一个File对象 并指定文件得路径  \转移字符串
        //第一种Windows通用两种分隔符
        File file01 = new File("D:\\AAA\\aaa.txt");
       
        File file02 = new File("D:/AAA/bbb.txt");
 
 
        // 第二种 File.separator根据当前代码所在得系统自动获取相应得分割符 
 
        System.out.println(File.separator); // \因为我们当前在window下
        File file03 = new File("D:"+File.separator+"AAA"+File.separator+"ccc.txt");

添加文件

        //创建文件对象
        File file = new File("F:/AAA/a.txt");
        //添加文件操作
        file.createNewFile();
 
        File file2 = new File("F:/AAA/bbb");
        file2.mkdir();//创建单层文件夹
 
        File file3 = new File("F:/AAA/bbb/ccc");
        file3.mkdirs();//创建多层文件夹

删除操作

        //创建文件对象
        File file = new File("F:/AAA/a.txt");
        //删除操作
        file.delete();//删除文件,同时可以删除空的文件夹
        file3.deleteOnExit();//程序退出时删除文件

修改文件

        //创建文件对象
        File file = new File("F:/AAA/a.txt");
        //修改操作
        file.setReadable(false);//修改能否打开文件的权限
        file.setWritable(false);//修改能否修改文件中的内容的权限
        file.setReadOnly();//修改文件为只读
        file.renameTo(new File("D:/AAA/aaa.txt"));//给文件重命名

查询文件

        //创建文件对象
        File file = new File("F:/AAA/a.txt");       
        //查询操作
        String name = file.getName();//获取文件名称
        String parent = file.getParent();//获取父级的名称
        String path = file.getPath();//获取路径
        System.out.println(name + " "+ parent+" "+path);
        boolean f1 = file.isFile();//是否为文件类型
        boolean f2 = file.isDirectory();//是否为文件夹类型
        System.out.println(f1 + " "+f2);
遍历
public class test {
    public static void main(String[] args) {
        String[] s=new String[100];
        File f=new File("D:/个人文件");
        s=f.list(); //获取当前目录下所有的一级文件名称到一个字符串数组中返回
        for(String ss:s){
            System.out.println(ss);
        }
        
        File[] s1=new File[100];
        File f1=new File("D:/个人文件");
        s1=f1.listFiles();//获取当前目录下所有的一级文件对象到一个对象数组中返回(重点)
        for(File ss1:s1){
            System.out.println(ss1);
        }
    }
}       

IO流

IO流即输入输出流,用于处理数据的传输

字符集编码、解码操作

image-20230303190655656

字节流

字节流基类
字节输入流(InputStream)
 常用方法:
    // 从输入流中读取数据的下一个字节
    abstract int read()
    // 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中
    int read(byte[] b)
    // 将输入流中最多 len 个数据字节读入 byte 数组
    int read(byte[] b, int off, int len)
 
    // 跳过和丢弃此输入流中数据的 n个字节
    long skip(long n)
 
    // 关闭此输入流并释放与该流关联的所有系统资源
    void close()
字节输出流(OutputStream)
 常用方法:
    // 将 b.length 个字节从指定的 byte 数组写入此输出流
    void write(byte[] b)
    // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流
    void write(byte[] b, int off, int len)
    // 将指定的字节写入此输出流
    abstract void write(int b)
 
    // 关闭此输出流并释放与此流有关的所有系统资源
    void close()
 
    // 刷新此输出流并强制写出所有缓冲的输出字节
    void flush()
字节文件操作流
字节文件输入流(FileInputStream)
 构造方法:
    // 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File对象file指定
    FileInputStream(File file)
    // 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径name指定
    FileInputStream(String name)

     //示例(使用字节数组)
        //构造方法
        InputStream inputStream2 = new FileInputStream("f://hello/test.txt");
        // 字节数组
        byte[] b = new byte[2];
        int i2 = 0;
        //  一次读取一个字节数组
        while ((i2 = inputStream2.read(b)) != -1) {
            System.out.print(new String(b, 0, i2) + " ");// AB CD
        }
        //关闭IO流
        inputStream2.close();
字节文件输出流(FileOutputStream)
 构造方法:
    // 创建一个向指定File对象表示的文件中写入数据的文件输出流
    FileOutputStream(File file)
    // 创建一个向指定File对象表示的文件中写入数据的文件输出流
    FileOutputStream(File file, boolean append)
    // 创建一个向具有指定名称的文件中写入数据的输出文件流
    FileOutputStream(String name)
    // 创建一个向具有指定name的文件中写入数据的输出文件流
    FileOutputStream(String name, boolean append)
 
        OutputStream outputStream = new FileOutputStream(new File("test.txt"));
        // 写出数据
        outputStream.write("ABCD".getBytes());
        // 关闭IO流
        outputStream.close();
 
        // 内容追加写入
        OutputStream outputStream2 = new FileOutputStream("test.txt", true);
        // 输出换行符
        outputStream2.write("\r\n".getBytes());
        // 输出追加内容
        outputStream2.write("hello".getBytes());
        // 关闭IO流
        outputStream2.close();
字节缓冲流(高级流)
字节缓存输入流(BufferedInputStream)
     构造方法:
     // 创建一个 BufferedInputStream并保存其参数,即输入流in,以便将来使用。
     BufferedInputStream(InputStream in)
     // 创建具有指定缓冲区大小的 BufferedInputStream并保存其参数,即输入流in以便将来使用
     BufferedInputStream(InputStream in, int size)
         
         //示例
        InputStream in = new FileInputStream("test.txt");
        // 字节缓存流
        BufferedInputStream bis = new BufferedInputStream(in);
        byte[] bs = new byte[20];
        int len = 0;
        while ((len = bis.read(bs)) != -1) {
            System.out.print(new String(bs, 0, len));
        }
        // 关闭流
        bis.close();
字节缓存输出流(BufferedOutputStream)
     构造方法:
     // 创建一个新的缓冲输出流,以将数据写入指定的底层输出流
     BufferedOutputStream(OutputStream out)
     // 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流
     BufferedOutputStream(OutputStream out, int size)
 
     常用方法:
     // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流
     void write(byte[] b, int off, int len)
     // 将指定的字节写入此缓冲的输出流
     void write(int b)
     // 刷新此缓冲的输出流
     void flush()
         
        //示例
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test.txt", true));
        // 输出换行符
        bos.write("\r\n".getBytes());
        // 输出内容
        bos.write("Hello Android".getBytes());
        // 刷新此缓冲的输出流
        bos.flush();
        // 关闭流
        bos.close();

字符流

字符流基类
字符输入流(Reader)
  常用方法:
    // 读取单个字符
    int read()
    // 将字符读入数组
    int read(char[] cbuf)
    // 将字符读入数组的某一部分
    abstract int read(char[] cbuf, int off, int len)
    // 跳过字符
    long skip(long n)
 
    // 关闭该流并释放与之关联的所有资源
    abstract void close()
字符输出流(Write)
 常用方法:
    // 写入字符数组
     void write(char[] cbuf)
    // 写入字符数组的某一部分
    abstract void write(char[] cbuf, int off, int len)
    // 写入单个字符
    void write(int c)
    // 写入字符串
    void write(String str)
    // 写入字符串的某一部分
    void write(String str, int off, int len)
 
    // 将指定字符添加到此 writer
    Writer append(char c)
    // 将指定字符序列添加到此 writer
    Writer append(CharSequence csq)
    // 将指定字符序列的子序列添加到此 writer.Appendable
    Writer append(CharSequence csq, int start, int end)
 
    // 关闭此流,但要先刷新它
    abstract void close()
    // 刷新该流的缓冲
    abstract void flush()
字符转换流
InputStreamReader(字节流转字符流)
 构造方法:
    // 创建一个使用默认字符集的 InputStreamReader
    InputStreamReader(InputStream in)
    // 创建使用给定字符集的 InputStreamReader
    InputStreamReader(InputStream in, Charset cs)
    // 创建使用给定字符集解码器的 InputStreamReader
    InputStreamReader(InputStream in, CharsetDecoder dec)
    // 创建使用指定字符集的 InputStreamReader
    InputStreamReader(InputStream in, String charsetName)
 特有方法:
    //返回此流使用的字符编码的名称 
    String getEncoding() 
     
//代码示例
        //使用默认编码        
        InputStreamReader reader = new InputStreamReader(new FileInputStream("test.txt"));
        int len;
        while ((len = reader.read()) != -1) {
            System.out.print((char) len);//爱生活,爱Android
 
        }
        reader.close();
 
         //指定编码 
        InputStreamReader reader = new InputStreamReader(new FileInputStream("test.txt"),"utf-8");
        int len;
        while ((len = reader.read()) != -1) {
            System.out.print((char) len);//????????Android
        }
        reader.close();
OutputStreamWriter(字节流转字符流)
 构造方法:
    // 创建使用默认字符编码的 OutputStreamWriter
    OutputStreamWriter(OutputStream out)
    // 创建使用给定字符集的 OutputStreamWriter
    OutputStreamWriter(OutputStream out, Charset cs)
    // 创建使用给定字符集编码器的 OutputStreamWriter
    OutputStreamWriter(OutputStream out, CharsetEncoder enc)
    // 创建使用指定字符集的 OutputStreamWriter
    OutputStreamWriter(OutputStream out, String charsetName)
 特有方法:
    //返回此流使用的字符编码的名称 
    String getEncoding() 
字符缓冲流
BufferedReader
 构造方法:
    // 创建一个使用默认大小输入缓冲区的缓冲字符输入流
    BufferedReader(Reader in)
    // 创建一个使用指定大小输入缓冲区的缓冲字符输入流
    BufferedReader(Reader in, int sz)
 特有方法:
    // 读取一个文本行
    String readLine()
     
//代码示例
        //生成字符缓冲流对象
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("test.txt")));
        String str;
        //一次性读取一行
        while ((str = reader.readLine()) != null) {
            System.out.println(str);// 爱生活,爱Android
        }
 
        //关闭流
        reader.close();
BufferedWriter
 构造方法:
    // 创建一个使用默认大小输出缓冲区的缓冲字符输出流
    BufferedWriter(Writer out)
    // 创建一个使用给定大小输出缓冲区的新缓冲字符输出流
    BufferedWriter(Writer out, int sz)
 特有方法:
    // 写入一个行分隔符
    void newLine() 

线程

创建线程:

方式一

image-20230301135226053

image-20230301135428214

image-20230301135734637

方式二

image-20230301140126792

image-20230301140423157

匿名写法:image-20230301140955216

image-20230301140536563

方式三

image-20230301141244956

image-20230301141838502

image-20230301142154855

三种方式对比总结

image-20230301142219914

线程

Thread常用方法、构造器

image-20230301143151153

image-20230301143235256

线程安全问题

原因:多个线程同时访问同一个共享资源且存在修改该资源

解决方案:加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来

同步代码块:

synchronized(同步锁对象){
    操作共享资源的代码(核心代码)
}

锁对象规范要求:

image-20230301145518922

同步方法:

image-20230301145742200

同步代码块与同步方法:同步代码块锁的范围更小,同步方法锁的范围更大。

Lock锁:

image-20230301150508263

线程通信

image-20230301152127117

线程池(重点)

image-20230301152302217

image-20230301152728048

image-20230301152803384

image-20230301153258114

image-20230301153510935

image-20230301154538141

image-20230301155113185

定时器

Timer定时器:本身是一个单线程

image-20230301160613597

ScheduledExecutorService定时器:多线程,基于线程池

image-20230301160926479

并发、并行

image-20230301161810329

image-20230301161825061

并发:CPU分时轮询的执行线程

并行:同一时刻同时在执行

线程的生命周期

image-20230301162109859

image-20230301162344375

网络编程(通信)

实现网络编程关键的三要素

image-20230301193503953

IP

image-20230301194154524

image-20230301194225755

端口号

image-20230301194900581

协议

网络通信协议:连接和通信数据的规则

image-20230301195226237

image-20230301195352506

image-20230301195507369

image-20230301195627214

image-20230301195648572

UDP协议

image-20230301200111273

image-20230301200157795

代码示例(默认支持多个客户端)

//客户端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class ClientDemo1 {

    public static void main(String[] args) throws Exception {
        //1.创建发送端对象:发送端自带默认的端口号(人)
        DatagramSocket socket = new DatagramSocket();
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入发送的消息:");
            String msg = sc.nextLine();
            if ("exit".equals(msg)) {
                System.out.println("离线成功!");
                socket.close();
                break;
            }
            //2.创建一个数据包对象封装数据
            byte[] buffer = msg.getBytes();
            //封装发送的数据(字节)、发送数据的大小、服务端IP地址(本次使用的是本机)、服务端端口
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLoopbackAddress(), 8888);
            //3.发送数据
            socket.send(packet);
        }
    }
}

//服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class SercerDemo1 {
    public static void main(String[] args) throws Exception {
        //1.创建接收端对象:注册端口
        DatagramSocket socket = new DatagramSocket(8888);
        //2.创建一个数据包对象接收数据
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
        while (true) {
            //3.等待接收数据
            socket.receive(packet);
            //4.取出数据
            //读取多少取多少
            int len = packet.getLength();
            String rs = new String(buffer, 0, len);
            System.out.println("收到了来自:" + packet.getAddress() + ",对方端口是:" + packet.getPort() + "的消息:" + rs);
        }
    }
}

广播、组播

image-20230301203536017

image-20230301203605926

image-20230301203718089

TCP协议

代码示例(默认不支持多个客户端)

-->需要使用多线程去完成处理多个客户端消息(只需服务端进行多线程修改)

//客户端
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class ClientDemo1 {
    public static void main(String[] args) {
        try {
            //1.创建Socket通信管道请求服务端连接
            //服务端IP地址、服务端端口
            Socket socket = new Socket("127.0.0.1", 8888);
            //2.从socket通讯管道中得到一个字节输出流,负责发送
            OutputStream os = socket.getOutputStream();
            //3.把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);
            Scanner sc = new Scanner(System.in);
            while (true) {
                System.out.println("请输入你想要发送的消息:");
                String msg = sc.nextLine();
                //4.发送消息并刷新
                ps.println(msg); //注意这里必须至少要一行消息,所有需要使用println
                ps.flush();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

//服务端
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo1 {
    public static void main(String[] args) {
        //1.注册端口
        try {
            ServerSocket serverSocket = new ServerSocket(7777);
            //a.定义一个死循环由主线程负责不断地接收客户端的Socket管道连接
            while (true) {
                //2.必须调用accept方法:等待接受客户端的Socket连接请求,建立Socket通信管道
                Socket socket = serverSocket.accept();
                //用于客户端上线提醒
                System.out.println(socket.getRemoteSocketAddress() + "上线了!");
                //下面注释代码为不使用线程只能一个客户端使用的情况
//                //3.从socket通信管道中得到一个字节输入流
//                InputStream is = socket.getInputStream();
//                //4.把字节输入流1包装成缓冲字符输入流进行消息接收
//                BufferedReader br = new BufferedReader(new InputStreamReader(is));
//                //5.按照行读取消息
//                String msg;
//                while ((msg = br.readLine()) != null) {
//                    System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
//                }
                //3.开始创建独立线程处理Socket
                new ServerReaderThread(socket).start();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}

//线程类(ServerReaderThread.java)
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

public class ServerReaderThread extends Thread {
    private Socket socket;

    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4.把字节输入流1包装成缓冲字符输入流进行消息接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            //可以用于客户端下线了提醒
            System.out.println(socket.getRemoteSocketAddress() + "下线了!");
        }
    }
}

使用线程池代码示例

//客户端(和之前一样)
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class ClientDemo1 {
    public static void main(String[] args) {
        try {
            //1.创建Socket通信管道请求服务端连接
            //服务端IP地址、服务端端口
            Socket socket = new Socket("127.0.0.1", 7777);
            //2.从socket通讯管道中得到一个字节输出流,负责发送
            OutputStream os = socket.getOutputStream();
            //3.把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);
            Scanner sc = new Scanner(System.in);
            while (true) {
                System.out.println("请输入你想要发送的消息:");
                String msg = sc.nextLine();
                //4.发送消息并刷新
                ps.println(msg); //注意这里必须至少要一行消息,所有需要使用println
                ps.flush();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

//服务端(使用线程池,完成服务端可以同时处理多个客户端消息)
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;

public class ServerDemo1 {
    //使用静态变量记住一个线程池对象
    private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2),
            Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) {
        try {
            //1.注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            while (true) {
                //2.每接收到一个客户端的Socket管道
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress() + "上线了!");
                Runnable target = new ServerReaderRunnable(socket);
                pool.execute(target);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

//线程池类(ServerReaderRunnable.java)
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

public class ServerReaderRunnable implements Runnable {
    private Socket socket;

    public ServerReaderRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override

    public void run() {
        try {
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4.把字节输入流1包装成缓冲字符输入流进行消息接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            //可以用于客户端下线了提醒
            System.out.println(socket.getRemoteSocketAddress() + "下线了!");
        }
    }
}

使用线程池优点:

image-20230302101030936

实战案例-即时通信

//客户端
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class ClientDemo1 {
    public static void main(String[] args) {
        try {
            //1.创建Socket通信管道请求服务端连接
            //服务端IP地址、服务端端口
            Socket socket = new Socket("127.0.0.1", 7777);

            //创建一个独立的线程专门负责这个客户端的读消息(服务端随时可发消息过来)
            new ClientReaderThread(socket).start();

            //2.从socket通讯管道中得到一个字节输出流,负责发送
            OutputStream os = socket.getOutputStream();
            //3.把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);
            Scanner sc = new Scanner(System.in);
            while (true) {
                System.out.println("请输入你想要发送的消息:");
                String msg = sc.nextLine();
                //4.发送消息并刷新
                ps.println(msg); //注意这里必须至少要一行消息,所有需要使用println
                ps.flush();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

//客户端线程类(ClientReaderThread.java)
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

public class ClientReaderThread extends Thread {
    private Socket socket;

    public ClientReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4.把字节输入流1包装成缓冲字符输入流进行消息接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println("收到消息:" + msg);
            }
        } catch (Exception e) {
            //可以用于客户端下线了提醒
            System.out.println("服务端把你踢出去了");
        }
    }
}

//服务端
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class ServerDemo1 {
    //定义一个静态的List集合存储当前全部在线的socket管道
    public static List<Socket> allOnlineSockets = new ArrayList<>();

    public static void main(String[] args) {
        //1.注册端口
        try {
            ServerSocket serverSocket = new ServerSocket(7777);
            //a.定义一个死循环由主线程负责不断地接收客户端的Socket管道连接
            while (true) {
                //2.必须调用accept方法:等待接受客户端的Socket连接请求,建立Socket通信管道
                //注意,在这里等待客户端的socket管道连接
                Socket socket = serverSocket.accept();
                //用于客户端上线提醒
                System.out.println(socket.getRemoteSocketAddress() + "上线了!");
                allOnlineSockets.add(socket);
                //3.开始创建独立线程处理Socket
                new ServerReaderThread(socket).start();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

//服务端线程类(ServerReaderThread.java)
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

public class ServerReaderThread extends Thread {

    private Socket socket;

    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4.把字节输入流包装成缓冲字符输入流进行消息接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
                //把消息进行端口转发给全部客户端socket管道
                sendMsgToAll(msg);
            }
        } catch (Exception e) {
            //可以用于客户端下线了提醒
            System.out.println(socket.getRemoteSocketAddress() + "下线了!");
            ServerDemo1.allOnlineSockets.remove(socket);
        }
    }

    private void sendMsgToAll(String msg) throws Exception {
        for (Socket socket : ServerDemo1.allOnlineSockets) {
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println(msg);
            ps.flush();
        }
    }
}

大杂烩

单元测试

image-20230302105458682

image-20230302105611098

image-20230302105903076

*代码示例:

image-20230302110307046

常用注解

image-20230302110522583

image-20230302110749764

反射

image-20230302110930110

image-20230302111610870

image-20230302111940920

image-20230302112733775

image-20230302112817132

image-20230302113640675

image-20230302114345940

反射的作用

1.绕过编译阶段为集合添加数据

image-20230302152424570

2.通用框架的底层原理

image-20230302153508678

注解

自定义注解

image-20230302153930477

image-20230302154257553

元注解

用在自定义注解上面的注解,用于限制自定义注解

image-20230302154358201

image-20230302154600275

注解的解析

获取注解里的内容

image-20230302154843702

动态代理

代理:某些场景下对象会找一个代理对象,来辅助自己完成一些工作

image-20230302161553510

案例:通过代理实现方法性能统计

image-20230302163252328

优点

image-20230302163458421

XML

定义:可扩展标记语言,它是一种数据表示格式,可以描述非常复杂的数据结构,常用于传输和存储数据

XML解析

使用Dom4j解析XML

image-20230302171244154

Xpath检索出XML文件

image-20230302173350835

0

评论

博主关闭了所有页面的评论