【Java基础】Java的反射、注解、lambda表达式

发布于:2024-04-04 ⋅ 阅读:(74) ⋅ 点赞:(0)

1. 反射

1.1 反射演示

有一个猫类,如下:

public class Cat {

    private String name;
    private int age;

    public void speak(){
        System.out.println("猫不会说话");
    }
    
    public void climb(){
        System.out.println("猫会爬");
    }

    public Cat() {
    }

    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

假设我们配置属性文件re.properties:

className=Cat
methodName=speak

编写反射的主方法,首先先读取配置文件,然后根据配置文件写的类路径、类方法来获取类:

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class tmp {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, IOException {
//        读取配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("re.properties"));
//        加载配置文件中的属性
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");

        Class cls = Class.forName(className); // 根据类的路径获取类
        Object obj = cls.newInstance(); // 获取这个类的实例
        Method method = cls.getMethod(methodName); // 获取类里面的方法
        method.invoke(obj); // 调用类里面的方法
    }
}

根据目前的位置,输出是:

猫不会说话

反射的作用是,如果我们修改配置文件里面的方法名为climb,则可以使得输出为:

猫会爬

这样就可以使得我们只修改配置文件而无需修改源码,实现代码功能的改变。

1.2 反射原理

.java文件经过编译器编译后变成了.class字节码文件,.class文件里面编译了.java文件里面的所有东西,有类、属性、方法、构造方法等。

Java程序的加载就是加载.class文件,.class文件被加载进内存后,内存里边有一个.class文件对应的内存区域,内存中包含了.class文件中所有与.java对应的类、属性、方法、构造方法等

通过内存区域内的这些对应的东西进行反射加载,获得具体的类、方法等。

2. Class类

Class.forName(classPath)加载出来的两个结果属于同一个对象,HashCode相等

3. 注解

3.1 内置注解

@SuppressWarnings("all")可以注释在类、方法等上表示抑制编译器的所有类型警告,unchecked表示抑制单类型的警告,unchecked,rawtypes表示抑制多类型的警告

@Override是重载方法,比如用在toString()方法上

@Deprecated表示是一个过时的方法,不推荐使用,当使用这个方法时,方法上会被标记一个删除线

3.2 元注解

@Target表示在哪些位置上标记注解:@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER...})

@Retention:指定注解的声明周期,如:@Retention(RetentionPolicy.RUNTIME)

@Document:会在JavaDoc里出现

3.3 自定义注解

自定义注解的代码,使用元注解:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NodeU{
}

4. lambda表达式

通过lambda表达式自定义实现接口的方法,并调用打印结果

public class tmp {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, IOException {
        Dog d = (int a, int b) -> {
            return a + b;
        };
        System.out.println(d.add(3, 2));
    }
}

interface Dog{
    int add(int a, int b);
}

如果interface里面有多个方法:

interface Dog{
    int add(int a, int b);
    int sub(int a, int b); // 二义性
    int mul(int a, int b); // 二义性
}

则主方法里的写法就会有问题,因为(int a, int b)不知道具体指的是哪个。

5. lambda精简

void方法可以精简成:

public class tmp {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, IOException {
        Dog d = () -> System.out.println("aaa");
        d.add();
    }
}

interface Dog{
    void add();
}

精简4中的代码:

public class tmp {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, IOException {
        Dog d = (a,b)->(a + b);
        System.out.println(d.add(3, 2));
    }
}

interface Dog{
    int add(int a, int b);
}

又如:

public class tmp {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, IOException {
        Dog d = a-> System.out.println("a" + a);
        d.add("1");
    }
}

interface Dog{
    void add(String a);
}

单个参数可以不带括号,但是多个参数必须带括号。这个要求是Dog接口的方法里只有一个含一个参数的方法,否则会报错

  • 一个参数时,()可省略

  • 方法体只有一条语句时,{}可省略

  • 如果方法体是return,那省略同时return也要省略

  • 参数类型可以省略(String a)可以直接变为(a)

6. lambda调用方法

大概就是将类tmp中的method方法,作为接口Dog中类似方法的实现(method是以两个int为参数的方法,而Dog中恰好有两个int的方法)

public class tmp {

    public static void main(String[] args) {
        tmp _tmp = new tmp();
        Dog d = _tmp::method;

        System.out.println(d.add(1, 2));
        System.out.println(d.add(3, 4));
        System.out.println(d.add(6, 5));

    }
    public int method(int a, int b){
        return a+b;
    }
}

interface Dog{
    int add(int a, int b);
}

如果dog中多了一个也是两个int参数的方法,则Dog d = _tmp::met中就会报错。


网站公告

今日签到

点亮在社区的每一天
去签到