JDK8新特性详解

☆* o(≧▽≦)o *☆嗨~我是小奥🍹
📄📄📄个人博客:小奥的博客
📄📄📄CSDN:个人CSDN
📙📙📙Github:传送门
📅📅📅面经分享(牛客主页):传送门
🍹文章作者技术和水平有限,如果文中出现错误,希望大家多多指正!
📜 如果觉得内容还不错,欢迎点赞收藏关注哟! ❤️

文章目录

  • JDK8新特性详解
    • 1、接口
    • 2、Lambda表达式
    • 3、函数式接口
    • 4、引用
      • (1) 方法引用
      • (2) 构造器引用
      • (3) 数组引用
    • 5、Stream API
      • (1) 什么是Stream
      • (2) 创建
      • (3) 筛选/ 切片
      • (4) 映射
      • (5) 排序
      • (6) 查找 / 匹配
      • (7) 归约 / 收集
      • (8) 并行流
    • 6、Optional
    • 7、新时间日期API
      • (1) 安全问题
      • (2) 本地时间 / 日期
      • (3) 时间戳
      • (4) 时间/日期差
      • (5) 时间校正器
      • (6) 时间格式化
      • (7) 时区
    • 8、Annotations注解
      • (1) 类型注解
      • (2) 重复注解

JDK8新特性详解

1、接口

Java8对接口做了进一步的增强。

  • 在接口中添加使用default关键字修饰的非抽象方法,即:默认方法。
  • 接口中可以声明静态方法,并且可以实现 。

默认方法和静态方法:

Java8 允许我们通过default关键字对接口中定义的抽象方法提供一个默认的实现。

    public interface MyInterface {// 一个普通的方法void method(int var);// 一个默认的方法default void defaultMethod(int var) {System.out.println("执行接口的 default 方法");}// 一个静态方法static void staticMethod() {System.out.println("执行接口的 static 方法");}}

在上面这个接口中,我们除了定义了一个抽象方法 calculate,还定义了一个带有默认实现的方法 sqrt。 我们在实现这个接口时,可以只需要实现 calculate 方法,默认方法 sqrt 可以直接调用即可,也就是说我们可以不必强制实现 sqrt 方法。

通过default关键字的特性,我们可以很方便的对之前的接口进行扩展,而此接口的实现类不必做出任何改动。

	public static void main(String[] args) {MyInterface anInterface = new MyInterface() {@Overridepublic void method(int a) {System.out.println("");}};anInterface.method(0);anInterface.defaultMethod(1);}

接口默认方法的类优先原则:

若一个接口中定义了一个默认方法,而另外一个父类或者接口中又定义了一个同名的方法时:

  • **选择父类中的方法。**如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
  • **接口冲突。**如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突。

2、Lambda表达式

Lambda是一个匿名函数(没有函数名的函数),直接对应于其中的Lambda抽象,Lambda 表达式可以表示闭包。

可以理解为一段可以传递的代码(将代码像数据一样传递),可以写出更简洁、更灵活的代码;作为一种更紧凑的代码风格,是Java语言表达能力得到提升。

Lambda表达式允许把函数作为一个方法的参数,基本表达如下:

 (parameters) -> expression 或 (parameters) -> {statements;}

(1)无参数,无返回值

例如,Runnable接口:

		Runnable r1 = new Runnable() {@Overridepublic void run() {System.out.println("java8之前");}};Runnable r2 = () -> {System.out.println("Lambda表达式写法");};

(2)有一个参数,无返回值

		Consumer<String> con1 = (a) -> System.out.println(a);con1.accept("lambda");// 小括号可以省略不写Consumer<String> con1 = a -> System.out.println(a);con1.accept("lambda");

(3)有两个及以上的参数,有返回值

		Comparator<Integer> com1 = (a, b) -> {System.out.println("lambda 比较");return Integer.compare(a, b);};// 方法体内部只有一条语句的时候,大括号可以省略Comparator<Integer> com2 = (a, b) -> Integer.compare(a, b);

3、函数式接口

Lambda表达式是用过函数式接口(只有一个方法的普通接口)来实现的,函数式接口可以被隐式转换为Lambda表达式,为了与普通的接口区分开,JDK1.8新增加了一种特殊的注解@FunctionalInterface 如下:

@FunctionalInterface
public interface Function<T, R> {/*** Applies this function to the given argument.** @param t the function argument* @return the function result*/R apply(T t);
}

(1)四大核心函数式接口

函数式接口参数类型返回类型用途
Consumer消费型接口Tvoid对类型为T的对象应用操作:viod accept(T t)
Supplier提供型接口T返回类型为T的对象:T get()
Function<T, R>函数型接口TR对类型为T的对象应用操作,并返回结果为R类型的对象:R apply(T t)
Predicate断言型接口Tboolean确定类型为T的对象是否满足某约束,并返回boolean值:boolean test(T t)

(2)Consumer消费型接口

		Consumer<Integer> consumer = x -> System.out.println("消费型接口" + x);consumer.accept(1);

(3)Supplier提供型接口

        Supplier<Integer> supplier = () -> (int)(Math.random() * 10);System.out.println(supplier.get());

(4)Function函数型接口

        String str = "123xyz";Function<String, String> function = s -> s.substring(1, 5);System.out.println(function.apply(str));

(5)Predicate断言型接口

        Integer age = 30;Predicate<Integer> predicate = i -> i >= 35;if (predicate.test(age)) {System.out.println("退休");} else {System.out.println("继续加油");}

4、引用

(1) 方法引用

若Lambda表达式中的内容已经有方法实现,则我们可以使用方法引用。

语法格式:

	对象::实例方法类::静态方法类::实例方法

注意:Lambda表达实体中调用的方法参数列表,返回类型必须和函数式接口中抽象方法保持一致。

① 对象::实例方法

		Consumer<String> con1 = s -> System.out.println(s);con1.accept("123");Consumer<String> con2 = System.out::println;con2.accept("456");

② 类::静态方法

		Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);com1.compare(1, 2);Comparator<Integer> com2 = Integer::compare;com2.compare(3, 4);

③ 类::实例方法

		BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);bp1.test("a", "b");BiPredicate<String, String> bp2 = String::equals;bp2.test("a", "b");

(2) 构造器引用

格式:

	ClassName::New
		Supplier<List> sup1 = () -> new ArrayList<>();Supplier<List> sup2 = ArrayList::new;

(3) 数组引用

		Function<Integer, String[]> fun1 = count -> new String[count];Function<Integer, String[]> fun2 = String[]::new; 

5、Stream API

(1) 什么是Stream

流(Stream)是数据渠道,是用于操作数据源(集合、数组等 )所生成的元素序列。、

简单来说,就是我们对一个包含一个或者多个元素的集合做各种操作。

注意:

  • Stream不会存储元素 。
  • Stream不会改变源对象,会返回一个持有结果的新的Stream。
  • Stream的操作是延迟执行的。需要返回结果的时候才会执行。

Stream的操作过程如下:

(1)**创建Stream。**一个数据源(如:数组、集合),获取一个流。

(2)**中间操作。**一个中间操作链,对数据源的数据进行处理。

(3)终止操作(终端操作)。一个终止操作,执行中间操作链,并产生结果。

(2) 创建

创建流的几种方式如下:

    // 1、通过集合获取流        ArrayList<Object> list = new ArrayList<>();Stream<Object> s1 = list.stream();// 2、通过数组获取流String[] strings = new String[10];Stream<String> s2 = Arrays.stream(strings);// 3、通过Stream的静态方法获取Stream<Integer> s3 = Stream.of(1, 2, 3);// 4、通过迭代获取流Stream<Integer> s4 = Stream.iterate(0, i -> i++);// 5、生成流Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println);

(3) 筛选/ 切片

中间操作:

  • filter:接收lambda,从流中排除元素。
  • limit:截断流,使其元素不超过给定数量。
  • skip(n):跳过元素,返回一个舍弃前n个元素的流;若流中元素不足n个,则返回一个空流。
  • distinct:筛选,通过流生成的hashCode()和equals()去除重复元素。
import java.util.Arrays;
import java.util.List;public class Main {public static void main(String[] args) {List<Person> list = Arrays.asList(new Person(1, "a", 20),new Person(2, "b", 21),new Person(3, "c", 22),new Person(4, "d", 23),new Person(5, "e", 24),new Person(6, "f", 25));list.stream().filter(x -> x.getAge() > 20)  // 条件过滤.limit(3) // 限制条数.distinct() // 去除重复.skip(1) // 跳过指定的条数.forEach(System.out::println); // 循环打印}
}class Person {private int id;private String name;private int age;public Person(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}// getter and setter
}

多个中间操作可以连接起来形成一个流水线,除非流水线上的操作触发终止操作,否则中间操作 不会 执行任何的处理。而在终止操作时一次性全部处理,称为“惰性求值”。

(4) 映射

  • map:接收lambda,将元素转换为其他形式或者提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • flatMap:接收一个函数作为参数,将流中每一个值都转换成另一个流,然后把所有流重新连接成一个流。
 		List<String> list = Arrays.asList("a", "b", "c");list.stream().map(str -> str.toUpperCase()) .forEach(System.out::println);
    public class Main {public static void main(String[] args) {List<String> list = Arrays.asList("a", "b", "c");list.stream().flatMap(Test::filterCharacter).forEach(System.out::println);}}class Test {public static Stream<Character> filterCharacter(String str) {List<Character> list = new ArrayList<>();for (char c : str.toCharArray()) {list.add(c);}return list.stream();}}

(5) 排序

  • sorted():自然排序
  • sorted(Comparator c):自定义排序

(6) 查找 / 匹配

终止操作:

  • allMatch:检查是否匹配所有元素
  • anyMatch:检查是否至少匹配一个元素
  • noneMatch:检查是否没有匹配所有元素
  • findFirst:返回第一个元素
  • findAny:返回当前流中的任意元素
  • count:返回流中元素的总个数
  • max:返回流中的最大值
  • min:返回流中的最小值
import java.util.Arrays;
import java.util.List;
import java.util.Optional;public class Main {public static void main(String[] args) {List<Status> list = Arrays.asList(Status.FREE, Status.BUSY, Status.VOCATION);// 匹配所有元素System.out.println(list.stream().allMatch(s -> s.equals(Status.BUSY)));// 至少匹配一个元素System.out.println(list.stream().anyMatch(s -> s.equals(Status.BUSY)));//  所有元素都不匹配System.out.println(list.stream().noneMatch(s -> s.equals(Status.BUSY)));//  返回第一个元素Optional<Status> first = list.stream().findFirst();// 避免空指针异常,如果Optional、为空,则找一个替换的对象Status status = first.orElse(Status.BUSY);System.out.println(status);// 返回任意一个元素Optional<Status> any = list.stream().findAny();System.out.println(any);// 返回流中元素的总个数System.out.println(list.stream().count());}
}enum Status {FREE, BUSY, VOCATION;
}

(7) 归约 / 收集

  • reduce(T identity, BinaryOperator) / reduce(BinaryOperator):归约,可以将流中的数据反复结合起来,得到一个值。
  • collect:收集,将流转换成其他形式;接收一个Controller接口实现,用于给流中元素做汇总的方法。
		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);System.out.println(list.stream().reduce(0, (x, y) -> x + y));		
import java.util.*;
import java.util.stream.Collectors;public class Main {public static void main(String[] args) {List<Person> persons = Arrays.asList(new Person(1, "a", 20),new Person(2, "b", 21),new Person(3, "c", 22),new Person(4, "d", 23),new Person(5, "e", 24),new Person(6, "f", 25));// 放入listList<String> list = persons.stream().map(Person::getName).collect(Collectors.toList());list.forEach(System.out::println);// 放入setSet<String> set = persons.stream().map(Person::getName).collect(Collectors.toSet());set.forEach(System.out::println);// 放入LinkedHashLinkedHashSet<String> linkedHashSet = persons.stream().map(Person::getName).collect(Collectors.toCollection(LinkedHashSet::new));linkedHashSet.forEach(System.out::println);// 总数System.out.println(persons.stream().collect(Collectors.counting()));// 平均值System.out.println(persons.stream().collect(Collectors.averagingInt(Person::getAge)));// 总和System.out.println(persons.stream().collect(Collectors.summingInt(Person::getId)));// 最大值System.out.println(persons.stream().collect(Collectors.maxBy((a, b) -> Integer.compare(a.getAge(), b.getAge()))));// 最小值System.out.println(persons.stream().collect(Collectors.minBy((a, b) -> Integer.compare(a.getAge(), b.getAge()))));// 分组Map<Integer, List<Person>> map = persons.stream().collect(Collectors.groupingBy(Person::getId));System.out.println(map);// 多级分组Map<Integer, Map<String, List<Person>>> mapMap = persons.stream().collect(Collectors.groupingBy(Person::getId, Collectors.groupingBy(e -> {if (e.getAge() > 20) {return "符合条件";} else {return "不符合条件";}})));System.out.println(mapMap);// 分区Map<Boolean, List<Person>> listMap = persons.stream().collect(Collectors.partitioningBy(e -> e.getAge() > 21));System.out.println(listMap);// 总结IntSummaryStatistics collect = persons.stream().collect(Collectors.summarizingInt(Person::getAge));System.out.println(collect.getMax());System.out.println(collect.getMin());System.out.println(collect.getSum());System.out.println(collect.getAverage());System.out.println(collect.getCount());// 连接String connect = persons.stream().map(Person::getName).collect(Collectors.joining("-"));}
}class Person {private int id;private String name;private int age;public Person(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}// getter and setter// toString
}

(8) 并行流

并行流:就是把一个内容分成几个数据块,并用不同的线程分别处理每个数据块的流。

Java8中将并行流进行了优化,我们可以很容易的对数据进行操作;Stream API可以声明性地通过parallel()与sequential()在并行流与串行流之间切换。

    // 串行流(单线程):切换为并行流parallel()// 并行流(多线程):切换为串行流sequential()LongStream.rangeClosed(0, 10000000L).parallel() // 底层使用的是Fork/Join框架.reduce(0, Long::sum);

6、Optional

Optional类是一个容器类,代表一个值存在或者不存在,原来使用null表示一个值不存在,现在可以用Optional可以更好的表达这个概念,并且可以避免空指针异常。

常用方法:

  • Optional.of(T t):创建一个Optional实例。
  • Optional'empty(T t):创建一个空的Optional实例。
  • OpTional.OfNullable(T t):若t不为null,则创建Optional实例,否则空实例。
  • isPresent():判断是否包含某值。
  • orElse(T t):如果调用对象包含值,返回该值,否则返回t。
  • orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取的值。
  • map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()。
  • flatmap(Function mapper):与map相似,要求返回值必须是Optional。

7、新时间日期API

(1) 安全问题

Java之前的Date时间类,存在很多的缺点 。

(1)最开始的时候,Date既要承载日期信息,又要做日期之间的转换,还要做不同日期格式的显示,职责较繁杂,从JDK1.1开始,这三项职责分开了:

  • 使用Calendar类实现日期和时间字段之间转换
  • 使用DateFormat类来格式化和分析日期字符串
  • Date只用来承载日期和时间信息

(2)对year和month的表达。

    Date date = new Date(2012,1,1);System.out.println(date);//输出Thu Feb 01 00:00:00 CST 3912

观察输出结果,year是2012 + 1900,而month是 1+1,如果要设置日期,我们应该使用java.util.Calendar,如下:

		Calendar calendar = Calendar.getInstance();calendar.set(2013, 8, 2);// 输出 Mon Sep 02 17:11:58 CST 2013System.out.println(calendar.getTime());calendar.set(2013, Calendar.AUGUST, 2);// 输出 Fri Aug 02 17:13:53 CST 2013System.out.println(calendar.getTime());

不过这样,month的表示还是从0开始的,除非我们直接使用枚举类型表示月份。

(3)java.util.Datejava.util.Calendar中的所有属性都是可变的。

(4)SimpleDateTimeFormat是非线程安全的。

基于上述问题,在 Java 8 对日期进行了优化,首先是将日期和时间设计为不可变类型,就像String类型一样,这样就避免了多线程下对日期的修改导致的线程安全问题,每次对日期的操作都会生成一个新的日期对象;另外还把功能进一步细化了,对日期的运算更加便利,输出也更加人性化。

(2) 本地时间 / 日期

LocalDate、LocalTime、 LocalDateTime类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。

常用方法:

方法名返回值类型解释
now()static ,LocalDate Time从默认时区的系统时钟获取当前日期
of(int year, int month, int dayOfMonth, int hour, int minute, int second)static,LocalDateTime从年月日时分秒获得LocalDATe Time的实例,将纳秒设置为零
plus(long amountToAdd, TemporalUnit unit)LocalDateTime返回此日期时间的副本,并添加指定的数量
get(TemporaField field)int从此日期时间获取指定字段的值为int
 		// 获取当前时间System.out.println(LocalDateTime.now());// 获取指定时间LocalDateTime of = LocalDateTime.of(2023, 3, 27, 17, 30, 18);System.out.println(of);// 加 plusSystem.out.println(of.plusMonths(1));// 减 minusSystem.out.println(of.minusMonths(3));// 获取指定给的年月日时分秒System.out.println(of.getDayOfMonth());System.out.println(of.getHour());

(3) 时间戳

时间戳是以Unix元年1970-01-01 00:00:00到某个时间之间的毫秒数。

		// 默认获取UTC时区(UTC:世界协调时间)Instant now = Instant.now();System.out.println(now);// 带偏移量的时间日期(如: UTC + 8)System.out.println(now.atOffset(ZoneOffset.ofHours(1)));// 转换成对应的毫秒值System.out.println(now.toEpochMilli());// 构建时间戳System.out.println(Instant.ofEpochSecond(60));

(4) 时间/日期差

  • Duration:计算两个时间之间的间隔
  • Period:计算两个日期之间的间隔
		Instant ins1 = Instant.now();Instant ins2 = Instant.now();Duration d = Duration.between(ins1, ins2);System.out.println(d.getSeconds()); // 秒System.out.println(d.getUnits()); // 时间戳LocalDate ld1 = LocalDate.of(2023, 9, 1);LocalDate ld2 = LocalDate.now();Period p = Period.between(ld2, ld1);System.out.println(p.getYears()); // 年System.out.println(p.toTotalMonths()); // 月

(5) 时间校正器

  • TemporalAdjuster:时间校正器。有时我们可能需要获取例如:将日期调整到下个周日等操作。
  • TemporalAdjusters:该类通过静态方法提供了大量的常用 TemporalAdjuster的实现

例如:获取下个周日

 LocalDate nextSunday = LocalDate.now().with(TemporaAdjusters.next(DayOfWeek.SUNDAY));

一些时间校正器的使用如下:

 		LocalDateTime t1 = LocalDateTime.now();System.out.println(t1);// 指定日期时间中的年月日LocalDateTime t2 = t1.withDayOfMonth(10);System.out.println(t2);// 指定时间校正器LocalDateTime t3 = t1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));System.out.println(t3);// 自定义时间矫正器LocalDateTime t5 = t1.with(ta -> {LocalDateTime t4 = (LocalDateTime) ta;DayOfWeek dow = t4.getDayOfWeek();if (dow.equals(DayOfWeek.MONDAY)) {return t4.plusDays(6);} else {// 其他时间逻辑...return t4;}});System.out.println(t5);

(6) 时间格式化

  • DateTimeFormatter:格式化日期或时间
		//默认格式化DateTimeFormatter dtf1 = DateTimeFormatter.ISO_DATE_TIME;LocalDateTime ldt1 = LocalDateTime.now();String str1 = ldt1.format(dtf1);System.out.println(str1);//自定义格式化 ofPatternDateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime ldt2 = LocalDateTime.now();String str2 = ldt2.format(dtf2);System.out.println(str2);//解析LocalDateTime newDate = LocalDateTime.parse(str1, dtf1);System.out.println(newDate);

(7) 时区

  • ZonedDate
  • ZonedTime
  • ZonedDateTime
		//查看支持的时区Set<String> set = ZoneId.getAvailableZoneIds();set.forEach(System.out::println);//指定时区LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));System.out.println(ldt1);//在已构建好的日期时间上指定时区LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));ZonedDateTime zdt1 = ldt2.atZone(ZoneId.of("Europe/Tallinn"));System.out.println(zdt1);

8、Annotations注解

在Java8中,对注解的改进主要有两点:类型注解和重复注解。

(1) 类型注解

新增ElementType.TYPE_USEElementType.TYPE_PARAMETER(在Target上)

新增的两个注释的程序元素类型 ElementType.TYPE_USEElementType.TYPE_PARAMETER 用来描述注解的新场合 。
ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中。
ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中(eg:声明语句、泛型和强制转换语句中的类型)。

类型注解的作用:

类型注解被用来支持在Java的程序中做强类型检查。配合第三方插件工具Checker Framework(注:此插件so easy,这里不介绍了),可以在编译的时候检测出runtime error(eg:UnsupportedOperationException; NumberFormatException;NullPointerException异常等都是runtime error),以提高代码质量。这就是类型注解的作用。

Note:

使用Checker Framework可以找到类型注解出现的地方并检查。

import checkers.nullness.quals.*;
public class TestDemo{void sample() {@NonNull Object my = new Object();}
}

编译上面的类,上面编译是通过的,但若修改代码:

@NonNull Object my = null;

但若不想使用类型注解检测出来错误,则不需要processor,正常javac TestDemo.java是可以通过编译的,但是运行时会报 NullPointerException 异常。

为了能在编译期间就自动检查出这类异常,可以通过类型注解结合 Checker Framework 提前排查出来错误异常。

注意java 5,6,7版本是不支持注解@NonNull,但checker framework 有个向下兼容的解决方案,就是将类型注解@NonNull 用/**/注释起来。

import checkers.nullness.quals.*;
public class TestDemo{void sample() {/*@NonNull*/ Object my = null;}
}

这样javac编译器就会忽略掉注释块,但用checker framework里面的javac编译器同样能够检测出@NonNull错误。
通过 类型注解 + checker framework 可以在编译时就找到runtime error。

(2) 重复注解

允许在同一声明类型(类,属性,或方法)上多次使用同一个注解。

Java8以前的版本使用注解有一个限制是相同的注解在同一位置只能使用一次,不能使用多次。Java 8 引入了重复注解机制,这样相同的注解可以在同一地方使用多次。重复注解机制本身必须用 @Repeatable 注解。

实际上,重复注解不是一个语言上的改变,只是编译器层面的改动,技术层面仍然是一样的。

(1)定义一个注解:

@Repeatable(MyAnnotations.class)
// TYPE_PARAMETER 类型参数
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {String value() default "java";
}

(2)定义一个注解容器

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {MyAnnotation[] value();
}

(3)使用

	@MyAnnotation("hello")@MyAnnotation("java")public static void show(@MyAnnotation("abc") String str) {System.out.println(str);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/643100.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ZYNQ入门】第九篇、双帧缓存的原理

目录 第一部分、基础知识 1、HDMI视频撕裂的原理 2、双帧缓存的原理 第二部分、代码设计原理 1、AXI_HP_WR模块 2、AXI_HP_RD模块 3、Block design设计 第三部分、总结 1、写在最后 2、更多文章 第一部分、基础知识 1、HDMI视频撕裂的原理 在调试摄像头的时候&#xf…

pikachu_ssrf攻略

ssrf&#xff08;curl&#xff09;&#xff1a; 打开pikachu靶场&#xff1a; http://127.0.0.1/pikachu-master/vul/ssrf/ssrf_curl.php?urlhttp://127.0.0.1/pikachu-master/vul/ssrf/ssrf_info/info1.php 发现URL地址最后面是info1.php 猜测一下有没有可能存在info2.php?…

Socket实现服务器和客户端

Socket 编程是一种用于在网络上进行通信的编程方法&#xff0c;以下代码可以实现在不同主机之间传输数据。 Socket 编程中服务器端和客户端的基本步骤&#xff1a;服务器端步骤&#xff1a; 1.创建 Socket&#xff1a; int serverSocket socket(AF_INET, SOCK_STREAM, 0);…

npm i 报一堆版本问题

1&#xff0c;先npm cache clean --force 再下载 插件后缀加上 --legacy-peer-deps 2&#xff0c; npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request to https://registry.npm.taobao.org/yorkie/download/yorkie-2.0.0.tgz failed, reason…

《PCI Express体系结构导读》随记 —— 第I篇 第2章 PCI总线的桥与配置(27)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第I篇 第2章 PCI总线的桥与配置&#xff08;26&#xff09; 2.5 非透明PCI桥 本回将结合实例说明直接地址翻译过程。 2.5.2 通过非透明桥片进行数据传递 下文以图2-16中处理器x访问处理器y存储器地址空间的实…

【IEEE会议征稿】2024年第九届智能计算与信号处理国际学术会议(ICSP 2024)

2024年第九届智能计算与信号处理国际学术会议&#xff08;ICSP 2024&#xff09; 2024年第八届智能计算与信号处理国际学术会议&#xff08;ICSP 2024&#xff09;将在西安举行&#xff0c; 会期是2024年4月19-21日&#xff0c; 为期三天, 会议由西安科技大学主办。 欢迎参会&…

Python笔记11-闭包、装饰器和设计模式

文章目录 闭包装饰器设计模式 闭包 在函数嵌套的前提下&#xff0c;内部函数使用了外部函数的变量&#xff0c;并且外部函数返回了内部函数&#xff0c;我们把这个使用外部函数变量的内部函数称为闭包。 示例 def outer(logo):def inner(msg):#logo"<"logo&quo…

【Redis】网络模型

前言 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的高性能键值对存储系统&#xff0c;广泛用于各种网络应用中作为数据库、缓存和消息代理。Redis的网络模型是其高性能的关键因素之一&#xff0c;它涉及到多个方面&#xff0c;包括内存管理、事件处理、…

MySQL:提示:The server quit without updating PID file问题的解决办法

[rootizuf62598fraqjv0qztcczxz ~]# service mysql restart MySQL server PID file could not be found![失败] Starting MySQL...The server quit without updating PID file (/usr/local/mysql/data/snsgou.pid).[失败] 具体什么原因最好的办法是先查看下错误日志&#xff1…

数灵通可以让抖音跳转企业微信并回传

抖音作为一款热门的短视频应用&#xff0c;吸引了大量用户的关注和参与。 对于企业而言&#xff0c;如何有效地将其他平台的客户引入企业微信成为了一个重要的课题。本文以利用抖音渠道进行引流&#xff0c;跳转到企业微信为例&#xff0c;介绍一种高效的方法。 在抖音上直接…

Dart/Flutter工具模块:the_utils

Flutter笔记 Dart/Flutter工具模块&#xff1a;the_utils 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/detail…

java基础内容

1.聊一聊Java平台的理解&#xff01; java本身是一种面向对象的语言&#xff0c;最显著的特性有两个方面&#xff1a;一是书写一次&#xff0c;到处运行&#xff0c;也就是跨平台的特性&#xff1b;另外就是垃圾回收机制&#xff1a;java通过垃圾收集器回收分配内存&#xff0…

WPF多值转换器

背景&#xff1a;实现Slider拖动可以调整rgb 单转换器&#xff1a;WPF中数据绑定转换器Converter-CSDN博客 在View中&#xff1a; <StackPanel Orientation"Vertical"><Slider x:Name"slider_R" Minimum"0" Maximum"255" Wi…

深度学习技巧应用33-零门槛实现模型在多个GPU的分布式流水线训练的应用技巧

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下深度学习技巧应用33零门槛实现模型在多个GPU的分布式流水线训练的应用技巧&#xff0c;本文将帮助大家零门槛的实现模型在多个GPU的并行训练&#xff0c;如果你手头上没有GPU资源&#xff0c;根据本文的介绍也可实现…

dhcp服务器的ip池的待分配ip地址是否冲突的检测机制

看到有的资料说&#xff0c;dhcp服务器在分配ip地址时&#xff0c;要检测是否待分配的ip地址是否存在冲突&#xff0c;会向广播域发出&#xff0c;对应ip发出icmp的ping消息来验证是否冲突。特地用自己的公司的交换机验证一下&#xff0c;在交换机上镜像抓包观察一下。 wiresha…

机器学习实验4——CNN卷积神经网络分类Minst数据集

文章目录 &#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1; 原理&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;CNN实现分类Minst&#x1f9e1;&#x1f9e1;代码数据预处理&#xff1a;设置基本参数&#xff1a; &#x1f9e…

接口文档swagger2的使用

Spring-接口文档swagger2 1、swagger/knife4j 接口文档配置 ​ knife4j是swagger的增强版本&#xff0c;更加的小巧、轻量&#xff0c;功能也是更加的完善&#xff0c;UI也更加的清晰&#xff1b;可以从swagger到knife4j无缝切换。 1.1 引入相关依赖 <!--接口文档的开发:…

神经网络:表述(Neural Networks: Representation)

1.非线性假设 无论是线性回归还是逻辑回归&#xff0c;当特征太多时&#xff0c;计算的负荷会非常大。 案例&#xff1a; 假设我们有非常多的特征&#xff0c;例如大于 100 个变量&#xff0c;我们希望用这 100 个特征来构建一个非线性的多项式模型&#xff0c;结果将是数量非…

Win10 如何用powershell写个WOL开机脚本

环境&#xff1a; Win10 专业版 问题描述&#xff1a; Win10 如何用powershell写个WOL开机脚本 解决方案&#xff1a; 1.脚本内容 $mac b1-10-18-52-11-12 $macBytes $mac -split - | ForEach-Object { [byte](0x $_) } $broadcastAddress [byte[]](1..6 | ForEach-O…

springboot导出数据到excel模板,使用hutool导出数据到指定excel,java写入数据到excel模板

最近遇到一个需求&#xff0c;需要从数据库查询数据&#xff0c;写入到对应的excel导入模板中。再把导出的数据进行修改&#xff0c;上传。 我们项目用的是easyExcel&#xff0c;一顿百度搜索&#xff0c;不得其法。 主要是要把数据填充到指定单元格中&#xff0c;跟平时用到的…