Java学习笔记-StreamApi,类加载与反射机制

本文详细介绍了Java中的Stream流操作及类加载机制,并深入探讨了反射的概念及其应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、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);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值