前言

b站java课程学习笔记整理。

b站视频: 黑马程序员全套Java教程_Java基础入门视频教程,零基础小白自学Java必备教程

385. 体验Stream流

直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:生成流、过滤姓张、过滤长度为3、逐一打印。

真正的使用了函数式的编程思想。

386. Stream流常见生成方式

Stream流的使用

  • 生成流
    • 通过数据源(集合,数组等生成流)
    • list.stream()
  • 中间操作
    • 一个流后面可以跟随零个或者多个中间操作,其主要目的是打开流,做出某种程度的数据过滤、映射,然后返回一个新的流,交给下一个操作使用
    • filter()
  • 终结操作
    • 一个流只能有一个终结操作,当操作执行后,流就被用光了。所以必定是最后一个流执行forEach()

Stream流的生成方式

  • Collection体系的集合可以使用默认方法stream()生成流
    • default Stream<E> stream()
  • Map体系的集合间接的生成流
  • 数组可以通过Stream接口的静态方法of(T...values)生成流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package StreamDemo;

import java.util.*;
import java.util.stream.Stream;

public class StreamDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Stream<String> listStream = list.stream();

Set<String> set = new HashSet<>();
Stream<String> setStream = set.stream();

//间接生成流
Map<String,Integer>map = new HashMap<>();
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valueStream = map.values().stream();
Stream<Map.Entry<String,Integer>>entryStream = map.entrySet().stream();

String[] strArray = {"hello","world"};
Stream<String> strArrayStream = Stream.of(strArray);
Stream<String> stringStream2 = Stream.of("hello","world");
Stream<Integer> intStream = Stream.of(10,20,30);
}
}

387. Steam流之filter

用于对流中的数据进行过滤

  • Stream<T> filter(Predicate predicate): 用于对流中的数据进行过滤。

​ 使用的是Predicate接口中的方法 boolean test(T t)

用法举例:

1
list.stream.filter(s->s.startsWith("张")).forEach(System.out::println)

可以多个filter"串联"。

388. Steam流中间操作limit&skip

  • Stream<T> limit(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据。(取前几个)
  • Stream<T> skip(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流。(跳过几个)

389. Steam流中间操作concat&distinct

  • static <T> Stream <T> concat(Stream a,Stream b):将两个流合并。

用法:

1
Stream.concat(s1,s2).forEach(System.out::println);
  • Stream<T>distinct():返回由该流的不同元素(根据object.equals(Object))组成的流。(去掉重复的)

390.Steam流中间操作之sorted

  • Stream<T> sorted():返回由此流的元素组成的流,根据自然顺序排序。
  • Stream<T> sorted(Comparator comparator):返回由该流的元素组成的流,根据提供的Comparator进行排序。

比较器举例:

1
2
3
4
5
list.stream().sorted((s1,s2)->{
int num = s1.length()-s2.length();
int num2 = num ==0?s1.compareTo(s2):num;
return num2
}).forEach(System.out::println);

391. Steam流中间操作之map&mapToInt

  • <R> Stream<R> map(Function mapper):返回由给定函数应用于此流的元素的结果组成的流。
  • IntStream mapToInt(ToIntFunction mapper):返回一个IntStream其中包括将给定函数应用于此流的元素的结果。
    • IntStream:表示原始int流。

392. Steam流终结操作forEach&count

  • void forEach(Consumer action): 对此流的每个元素执行操作。
  • long count():返回流元素个数。

393. Stream流综合练习

现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下操作:

  • 男演员取名字为3个字的前三个人
  • 女演员只要姓林的,不要第一个
  • 把过滤后的男演员姓名和女演员姓名合并到一起
  • 把上一步操作后的元素作为构造方法的参数创建演员对象,并遍历。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package Stream案例;

import java.util.ArrayList;
import java.util.stream.Stream;

public class StreamTest {
public static void main(String[] args) {
ArrayList<String>manList = new ArrayList<>();
manList.add("周润发");
manList.add("成龙");
manList.add("刘德华");
manList.add("吴京");
manList.add("周星驰");
manList.add("李连杰");

ArrayList<String>womanList = new ArrayList<>();
womanList.add("林心如");
womanList.add("张曼玉");
womanList.add("林青霞");
womanList.add("柳岩");
womanList.add("林志玲");
womanList.add("王祖贤");

Stream<String> manStream = manList.stream().filter(s->s.length()==3).limit(3);
Stream<String> womenStream = womanList.stream().filter(s->s.startsWith("林")).skip(1);

Stream<String> stream = Stream.concat(manStream,womenStream);
//利用map,将此流中的字符串构建成Actor
stream.map(Actor::new).forEach(p->System.out.println(p.getName()));


}
}

394. Stream流的收集操作

Stream流的收集方法

  • R collect(Collector collector)
  • 但是这个收集方法的参数是一个Collector接口

工具类Collectors提供了具体的收集方式

  • public static <T> Collector toList(): 把元素收集到List集合中
  • Public static <T> Collector toSet(): 把元素收集到Set集合中
  • public static Collector toMap(Function keyMapper, Function valueMapper): 把元素收集到Map集合中

395. 类加载

当程序要使用某个类时,如果该类还未被加载到内存中,系统就会通过类的加载,类的链接,类的初始化这三个步骤来对类进行初始化。

  1. 类的加载

    • 就是指将class文件写入内存,并位置创建一个java.lang.Class对象。

    • 任何类被使用时,系统都会为之建立一个java.lang.Class对象。

  2. 类的连接

    • 验证阶段: 用于检验被加载的类是否有正确的内部结构,并和其他类协调一致。

    • 准备阶段: 负责为类的类变量分配内存,并设置默认初始化值。

    • 解析阶段: 将类的二进制数据中的符号引用替换为直接引用。

  3. 类的初始化:

    • 对类变量进行初始化

类初始化的步骤

  • 假如类还没有被加载和连接,则程序被加载并连接该类
  • 假如该类的直接父类还未被初始化,则先初始化其直接父类
  • 假如类中有初始化语句,则系统依次执行这些初始化语句。

注意: 在执行第二个步骤的时候,系统对直接父类的初始化步骤也遵循初始化步骤1-3.

396.类加载器

  • Bootstrap class loader
  • Platform class loader
  • System class loader

方法:

  • static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
  • ClassLoader getParent(): 返回父类加载器进行委派。
1
2
3
4
5
6
Classloader c = ClassLoader.getSystemClassLoader();
System.out.println(c);
Classloader c2 = c.getParent();
System.out.println(c2);
Classloader c3 = c2.getParent();
System.out.println(c3);

397. 反射概述

反射机制: 是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。由于这种动态性,可以极大地增强程序的灵活性。程序不用在编译期就完成确定,在运行期仍然可以扩展。

398. 获取class类的对象

我们想要通过反射去使用一个类,首先要获取到该类的字节码文件对象,也就是类型为class类型的对象。

三种方式:

  • 使用类的class属性来获取该类对应的class对象。
  • 调用对象的getClass()方法
  • 使用Class类中的静态方法forName(String className)

三种方式的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package 反射;

public class test {
public static void main(String[] args) throws ClassNotFoundException {
Class<Student> c1 = Student.class;
System.out.println(c1);

Class<Student> c2 = Student.class;
System.out.println(c1 == c2);
System.out.println("---------");
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c1==c3);
System.out.println("---------");
Class<?> c4 = Class.forName("反射.Student");

System.out.println(c4 == c1);



}
}

399. 反射获取构造方法并使用

  • Constructor<?> [] getConstructors():返回所有公共构造方法对象的数组
  • Constructor<?> [] getDeclaredConstructors():返回所有构造方法对象的数组
  • Constructor<?> [] getConstructor(Class<?>...parameterTypes):返回单个公共构造方法对象
  • Constructor<?> [] getDeclaredConstructor(Class<?>...parameterTypes)返回单个构造方法对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package 反射;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> c = Class.forName("反射.Student");
// 只能拿到公共的构造方法
Constructor<?>[] constructors1 = c.getConstructors();
for(Constructor constructor: constructors1){
System.out.println(constructor);
}
// 所有的构造方法
Constructor<?>[] constructors2 = c.getDeclaredConstructors();
for (Constructor constructor: constructors2){
System.out.println(constructor);
}
// 拿单个的构造方法
Constructor<?> con = c.getConstructor();

Object obj = con.newInstance();
System.out.println(obj);


}
}

400. 反射获取构造方法并使用练习1

通过反射实现:

  • Student s = new Student("林青霞",30);
  • System.out.println(s);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package 反射;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> c = Class.forName("反射.Student");
// 只能拿到公共的构造方法

Constructor<?> constructor = c.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("林青霞",30);
System.out.println(obj);

}
}

401. 反射获取构造方法并使用练习2

通过反射实现:

  • Student s = new Student("林青霞");
  • System.out.println(s);
  • 注意,只以名字的构造方法是private的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package 反射;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> c = Class.forName("反射.Student");
// 只能拿到公共的构造方法

Constructor<?> constructor = c.getDeclaredConstructor(String.class);
// 暴力反射,值为true取消访问检查
constructor.setAccessible(true);
Object obj = constructor.newInstance("林青霞");
System.out.println(obj);

}
}

402. 反射获取成员变量并使用

  • Field[] getField():返回所有公共成员变量对象的数组
  • Field[] getDeclaredField():返回所有成员变量对象的数组
  • Field[] getField(String name):返回单个公共成员变量对象
  • Field getDeclaredField(String name):返回单个成员变量对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package 反射;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
Class<?> c = Class.forName("反射.Student");
// 只能拿到公共的成员变量
Field[] fields = c.getFields();
for(Field field: fields){
System.out.println(field);
}
// 所有的成员变量
Field[] fields2 = c.getDeclaredFields();
for(Field field: fields2){
System.out.println(field);
}
// 只拿单个的
Field nameField = c.getField("name");
Constructor<?> constructor = c.getConstructor();
Object obj = constructor.newInstance();

nameField.set(obj,"好人"); //给对象obj的成员变量nameField赋值为好人。
System.out.println(obj);

}
}

403. 反射获取成员变量并使用练习

跟上集一样

404. 反射获取成员方法并使用

  • Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
  • Method[] gerDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
  • Method getMethod(String name, Class<?>... parameterTypes):返回单个公共成员方法对象
  • Method getDeclaredMethod(String name,Class<?> ... parameterTypes): 返回单个成员方法对象
  • invoke(obj)在具有指定参数的指定对象上调用上述得到的method。

405. 反射获取成员方法并使用练习

和前面一样

406. 反射练习:越过泛型检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package 反射;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
ArrayList<Integer> array = new ArrayList<>();

array.add(10);
array.add(20);

Class<? extends ArrayList> c = array.getClass();

Method m = c.getMethod("add", Object.class);

m.invoke(array,"hello");
System.out.println(array);

}
}

407. 通过配置文件运行指定方法

1
2
3
4
5
6
7
8
package 反射配置练习;

public class Student {
public void study(){
System.out.println("好好学习");
}
}

1
2
3
4
5
6
7
8
package 反射配置练习;

public class Teacher {
public void teach(){
System.out.println("教书");
}
}

1
2
3
className=反射配置练习.Student
methodName=study

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package 反射配置练习;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Properties prop = new Properties();
FileReader fr = new FileReader("java.txt");
prop.load(fr);
fr.close();

String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");

Class<?> aClass = Class.forName(className);

Constructor<?> constructor = aClass.getConstructor();
Object obj = constructor.newInstance();

Method m = aClass.getMethod(methodName);
m.invoke(obj);
}
}

408. 模块化

可以加载指定模块(就是模块下新建好一个包,包下新建好一个类的那个模块),而不是整个虚拟机。

409. 模块的基本使用

在模块的src目录下新建一个名为module-info.java的描述性文件,该文件专门定义模块名,访问权限,模块依赖等信息,描述性文件中使用模块导出和模块依赖来进行配置使用。

Module-info.java

某个包的导出:

1
2
3
module idea.test {
exports 集合到文件;
}
1
2
3
module imp.test {
requires idea.test;
}

410. 模块服务的使用

步骤

  • 在X模块下创建一个包a,在包a下提供一个接口,接口中定义了一个抽象方法
1
2
3
public interface MyService{
void service();
}
  • 在包a下创建一个包impl,在该包impl下提供接口的两个实现类b和c
  • 在X模块下的描述文件中添加如下配置
    • 模块导出: exports a
    • 服务提供:provides Myservice with b //指定服务的实现类是服务b

总结:源码

完结了!作业源码地址是:这里