一、Stream流
//生成流
static stream(T[] array) //根据数组生成流
default stream() //根据引用该方法的集合生成流
static of(T...values) //根据给定的各个元素生成有序的流
static of(T t) //生成包含单个元素的流
//中间操作(对流进行)
//一个流的后面可以跟若干中间操作,目的是打开流,对其中数据进行过滤/映射,然后返回一个新的流,交给下一个操作使用
filter(Predicate<? super T> predicate) //过滤
limit(long maxSize) //截取前n个元素
skip(long n) //跳过前n个元素
sorted() //对流中元素排序
sorted(Comparator<? super T> comparator)
peek(Consumer<? super T> action) //
map(Function<? super T,? extends R> mapper)//对流中元素执行特定操作
mapToDouble mapToInt mapToLong
concat(Stream<? extends T> a, Stream<? extends T> b)//合并
distinct() //返回由该流的不同元素(根据 [Object.equals(Object)])组成的流 -去重
//终止操作
//一个流只能有一个终结操作,当这个流执行了终结操作时,此时流就会被关闭。无法进行后续操作
count() 返回此流中的元素数
forEach(Consumer<? super T> action) //对此流的每个元素执行操作
注意:中间操作是lazy操作,不会立刻启动,需要等待终止操作才会执行
例如
Stream<String> stream = Stream.of("one", "two", "three","four");
stream.peek(System.out::println);
//结果不会输出任何数据
peek接收一个Consumer,map接收一个Function,Consumer是没有返回值,它对流中元素进行某些操作
但操作后的元素无法返回到流中。所以peek对String和基本类型操作无法改变流,而对对象引用的操作可以
改变对象的属性(peek一般用于Debug)
二、类加载
当某一个程序在运行时,需要使用某一个类,如果该类还未被加载到内存中,则系统会通过类的加载,类的链接,类的初始化三个步骤来完成对类的初始化
类的加载:
- 就是指将class文件读入内存,并位置创建一个java.lang.Class对象。
- 任何类被使用时,系统都会为之建立一个java.lang.Class对象
类的链接: - 验证阶段:用户检验被加载的类是否有完整的结构,并和其他的类协调一致
- 准备阶段: 负责为类的变量分配内存,并设置默认初始值
- 解析阶段: 将类的二进制数据中的符号引用替换为直接引用
类的初始化:
主要就是对类的变量进行初始化
类的初始化步骤:
假如类还未被加载和链接,则程序先加载并链接该类
假如该类的直接父类还未被加载,则先初始化其直接父类
假如类中具有初始化语句,则系统将一次执行这些初始化语句
类的初始化时机:
创建类的实例,
调用类的类方法,
访问类或者接口的类变量或者为该类变量赋值(不为final)
使用反射方式来强制创建某个类或者接口对应的Class对象,
初始化某个类的子类,
直接使用java.exe命令来运行某个主类
1.类加载器
作用:负责将class文件加载到内存中,并为之生成对应的Class,虽然我们不用过分的关心类的加载机制,但是了解这个机制就能更好的理解程序的运行
jvm的类加载机制:
<1>全盘负责:就是说当一个类加载器负责加载某个Class的时候,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,
除非显式使用另外一个 类加载器来实现载入
<2>父类委托**:意思是先让父类加载器试图加载该Class,只有父类加载器无法加载该类是才尝试从自己的路径中加载该类
<3>缓存机制:缓存机制将会保证所有被加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存中搜索该Class,只有
当缓存中不存在该Class对象 时,系统才重新读取该类对应的二进制数据。这就是为什么我们修改Class后,JVM必须重新启动,修改才生效的原因
java中的内置类加载器
Bootstrap class Load: 这是jvm的内置类加载器 通常表示为null,并且没有父类
Paltform class load: 平台类加载器 可以看到所有的平台,包括平台类加载器或其祖先定义的JAVASE平台的API
System class load 应用程序类加载器 与平台类加载器不同,系统类加载器加载通常用于定义应用程序类路径和模块路径和jdk特定工具类
System的父加载器为Platform 而platform的父加载器为Bootstrap
public static void main(String[] args) {
ClassLoader loader = ClassLoader.getSystemClassLoader(); //返回用于委托的系统类加载器
System.out.println(loader);//AppClassLoader
ClassLoader loader1 = loader.getParent();
System.out.println(loader1);//PlatformClassLoader
System.out.println(loader1.getParent());// null BootstrapClassLoader
}
三、反射
反射指的就是在运行时获取一个类的属性和方法信息,然后通过获取到的信息来创建对象,调用方法的一种机制
优点:动态绑定,使得不用重新编译整个java程序,就可以修改程序的某些功能特性
//获取Class对象的方式
Class<Student> c1 = Student.class 1.类的class属性
Student stu = new Student();
Class<? extends Student> c3 = stu.getClass() 2.对象的getClass方法
Class<?> c4 = Class.forName("cn.lanqiao.clazz.Student") 3.类的forName静态方法
//注意:一个类的类对象在内存中永远只有一份,所以以上三种方法获得的类对象是同一个
//获取类的构造方法
getConstructor(参数...) //获取指定的公共构造器
getConstructors() //获取所有公共构造器
getDeclaredConstructor(参数...) //可获取私有的
getDeclaredConstructors() //可获取私有的
//使用Constructor创建对象
newInstance(Object... initargs) //须传参数
//若要使用私有构造器创建对象,则要设置该构造器的可访问性(暴力反射)
c4.setAccessible(true);
//获取成员变量
getField(String name) //获取指定的公共字段属性
getFields() //获取所有公共字段属性
getDeclaredField(String name) //可获取私有
getDeclaredFields() //可获取私有
//私有字段的访问
field.setAccessible(true) field.set(stu,"李四")
//获取成员方法
getMethod("setName", String.class) //返回方法名为setName,形参为String的公共方法类对象
getMethods()
getDeclaredMethod()
getDeclaredMethods()
//使用方法 (对私有方法的访问要暴力破解)
方法类对象.invoke(实际对象)
``
反射的应用
反射对泛型的检查
```java
@Test
public void reflectTest01() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
// 利用反射 在运行期给list添加元素 发现泛型检查已经失效 泛型擦除
Class<? extends List> c = list.getClass();
Method addMethod = c.getMethod("add",Object.class);
addMethod.invoke(list,"aaaa");
addMethod.invoke(list,true);
System.out.println(list);
}
运行配置文件中指定类和方法
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 加载配置文件 读取配置数据
Properties prop = new Properties();
FileReader fr = new FileReader("day_16/resources/myClass.properties");
prop.load(fr);
fr.close();
//获取配置数据
String className = (String) prop.get("className");
System.out.println(className);
String methodName = (String) prop.get("methodName");
System.out.println(methodName);
// 通过反射创建累的对象
Class<?> c = Class.forName(className);
Constructor<?> constructor = c.getConstructor();//在以后的开发中 类中 至少要保证无参构造
Object obj = constructor.newInstance();
Method method = c.getMethod(methodName);
method.invoke(obj);
}