学习java-泛型,反射,常见lambda

207 阅读5分钟

1.方法泛型的结构

泛型声明:在方法签名的前面,使用尖括号<>来声明泛型类型。 例如 public static <T> void printElements(List<T> list) {}

1.1.方法泛型的机制和作用

生命周期

泛型在java中主要存在于两个生命周期

  1. 编译阶段:Java编译器会读取泛型代码,并将类型参数替换为具体的类型。例如,如果编译器推断T应该是String类型,那么编译后的代码会使用String类型替换泛型。
  2. 字节码生成阶段:在字节码生成阶段,Java编译器会将泛型代码转换成字节码。由于泛型擦除,这个阶段会将泛型信息从字节码中移除,只保留原始的类型信息。

泛型擦除(Generics Erasure)是Java泛型机制的一个特性,它指的是在Java编译器将泛型代码编译成字节码时,泛型信息会被从代码中移除。

作用

在使用时,我们只需要关注调用方法时,泛型被替换的具体类型.

通过这种方式,在保证传递参数规范的前提下,可以提供更高的方法灵活性和可复用性

以下来自ai

方法泛型在Java编程语言中具有以下作用:

  1. 类型安全:泛型方法在编译时执行类型检查,确保方法操作的参数和返回值类型是正确的。这有助于避免在运行时由于类型不匹配导致的错误。
  2. 代码复用:泛型方法可以接受多种类型的参数,从而避免了为每种类型编写重复的代码。这意味着你可以编写一个通用的方法来处理多种类型的数据,提高了代码的复用性。
  3. 明确意图:泛型方法的使用可以清楚地表明其意图,即该方法可以处理多种类型的对象。这有助于提高代码的可读性和可维护性。
  4. 灵活性:泛型方法允许你在不知道具体类型的情况下编写代码,这使得代码更加灵活和通用。
  5. 避免强制类型转换:泛型方法通常不需要进行强制类型转换,因为编译器已经确保了类型的匹配。这有助于减少代码中的类型转换错误。
  6. 类型推断:在某些情况下,编译器可以自动推断出泛型类型,这使得代码更加简洁。

总之,泛型方法在Java编程中是一种强大的工具,它提供了一种类型安全的、可重用的、灵活的方式来编写处理多种类型数据的代码。

1.2.举例

和class,list本身带有泛型的类使用

public static void main(String[] args) {
    List<String> stringList = new ArrayList<>();
    stringList.add("Hello");
    stringList.add("World");
    
    List<Integer> integerList = new ArrayList<>();
    integerList.add(1);
    integerList.add(2);

    String s = printElements(stringList, "nh", String.class);// 调用时提供String类型的参数
    Integer i = printElements(integerList, 123L,Long.class);// 调用时提供Integer类型的参数
}
public static <U,KK>   U  printElements(List<U> list,KK kk,Class<KK> demo) {
    for (U element : list) {
        System.out.println(element);
    }{
        return (U) kk;
}

这段代码中,第二次调用U为Integer,Class为Long,同时demo为Long.class 当使用这个方法时,参数之间会检查 会发生编译器报错 当我们用这种方法调用

Integer i = printElements(integerList, 123,Long.class);

image.png

1.3.举例

实现列表的转换

public class BeanUtil {
    public static <T,V>  List<V>   mad(List<T>source,Class<V> target) {
        List<V> collect = source.stream()
                .map(e -> {
                    try {
                        V v = cn.hutool.core.bean.BeanUtil.copyProperties(e, target);
                        return v;
                    } catch (Exception ex) {
                        // 处理异常,例如:打印日志或抛出自定义异常
                        throw new RuntimeException(ex);
                    }
                })
                .collect(Collectors.toList());
return collect;

    }
}

2.反射

反射把类抽象,可以调用类,构造方法,方法,成员变量,修饰符,注解等等

基础概念

常见的:构造方法,方法,成员变量的调用方式:通过类获取构造器 构造器参数:传入对象实例,传入可能参数

详细

获取类的三种方法 1.Class<?> cls = Class.forName("java.lang.String");

2.String str = "Hello, World!"; Class<?> cls = str.getClass();

3.对象实例 x.class

image.png

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
class Student {
    String name;

    int age;
  public void method(String msg){
      System.out.println(msg);
      System.out.println(this.getName());
  }


}

image.png

结合实践分析反射使用

package com.example.wing.client.minio;

import com.example.wing.project.commom.service.FileService;
import com.example.wing.project.sys.domain.User;
import liquibase.pro.packaged.T;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;

import static com.alibaba.fastjson2.util.BeanUtils.getterName;
import static com.alibaba.fastjson2.util.BeanUtils.setterName;

/**
 * <h3>wing</h3>
 * <p>泛型方法</p>
 *
 * @author : zlx
 * @date : 2024-07-19 11:12
 **/
@Component
public class UrlUtil {
    @Autowired
    private FileService fileUploadService;

    public <T> void updateMinioUrl(List<T> items, String urlFieldName) {
        if (items != null) {
            items.forEach(item -> {
                String minioUrl = null;
                try {
                    minioUrl = (String) item.getClass().getMethod(
                            //return "get" + first.toUpperCase() + last;
                            getterName(urlFieldName)).invoke(item);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                if (StringUtils.isNotBlank(minioUrl)) {
                    try {
                        String presignedUrl = fileUploadService.getPreSign(minioUrl);
//
                        item.getClass().getMethod(setterName(urlFieldName), String.class).invoke(item, presignedUrl);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            })
        ;}


    }
    private String getterName(String name) {
        String first = name.substring(0, 1);
        String last = name.substring(1);
        return "get" + first.toUpperCase() + last;
    }

    /**
     * 转化set方法名
     */
    private String setterName(String name) {
        String first = name.substring(0, 1);
        String last = name.substring(1);
        return "set" + first.toUpperCase() + last;
    }
}

这是一个工具类,作用是把指定对象的field转化

  1. 自定义构建get和set的方法,可以访问private成员变量
  2. 通过反射操作实例,实现一定的灵活性,实例的地址是唯一的,因此可以动态修改实例的数值
  3. 结合之前的限流文章,aop中获得的args参数也都是可以直接修改
Student student = new Student();
student.setAge(18);
student.setName("小明");
long l = VM.current().addressOf(student);
System.out.println(l);
Field name = student.getClass().getDeclaredField("name");
name.setAccessible(true);
System.out.println(name.get(student));

name.set(student,"小红");

long l1 = VM.current().addressOf(student);
System.out.println(l1);
System.out.println(l==l1);


System.out.println(student);

image.png

3.常见的labda对象

Function<T, R>

抽取方法

  • 用途:接受一个类型为 T 的参数,并返回一个类型为 R 的结果。

  • 调用方法apply(T t) - 用于执行函数操作并返回结果。

    Function<String, Integer> length = s -> s.length();
    Integer len = length.apply("Hello");
    

    空function,传入什么,传出什么

Function.identity() 

Consumer

  • 用途:接受一个类型为 T 的参数,无返回值。用于执行一个操作。

  • 调用方法accept(T t) - 用于执行操作。

    Consumer<String> print = s -> System.out.println(s);
    print.accept("Hello");
    

Supplier

aop中joint的传递

  • 用途:不接受参数,但提供一个 T 类型的结果。用于生成一个值。

  • 调用方法get() - 用于获取结果。

    Supplier<String> helloSupplier = () -> "Hello";
    String hello = helloSupplier.get();
    

BiFunction<T, U, R>

CF的链式调用

  • 用途:接受两个参数,分别为 T 和 U 类型,返回一个 R 类型的结果。

  • 调用方法apply(T t, U u) - 用于执行函数操作并返回结果。

    BiFunction<String, String, String> concatenate = (a, b) -> a + b;
    String result = concatenate.apply("Hello", "World");