硅基计划3.0 学习总结 反射&枚举&Lambada表达式

1750851495463



一、反射

反射的作用就是打破类的封装性,在运行时进行检查,从而能够动态的获取类的内部信息
我们知道,当一个Java文件编译后生成了Class文件,而这个Classs文件要进入JVM虚拟机中运行
因此必然要获取类的内部内容,那是怎么获得的呢
这就是我们要讲的第一个点,Class类的作用

1. Class类

我们先定义一个测试类,然后测试各种情况,有私有成员变量,构造方法,私有和公有方法测试

/**
 * @author pluchon
 * @create 2025-09-18-18:47
 * 作者代码水平一般,难免难看,请见谅
 */
public class TestReflection {
    int age = 10;
    double high = 15.5;

    public TestReflection() {
        this.age = 0;
        this.high = 50.0;
    }

    private TestReflection(int age) {
        this.age = age;
    }

    public TestReflection(int age, double high) {
        this.age = age;
        this.high = high;
    }
    
    //...测试...
    
    private void funA(){
        System.out.println("funA方法");
    }
    
    private void funB(int age){
        this.age = age;
        System.out.println("年龄变成"+age);
    }
    
    private void funC(int age,double high){
        this.age = age;
        this.high = high;
        System.out.println("年龄和升高变成"+age+" "+high);
    }

    private int funAA(){
        return 0;
    }

    private int funBB(int age){
        return age;
    }

    private double funCC(int age,double high){
        return high;
    }


    public void funa(){
        System.out.println("funA方法");
    }

    public void funb(int age){
        this.age = age;
        System.out.println("年龄变成"+age);
    }

    public void func(int age,double high){
        this.age = age;
        this.high = high;
        System.out.println("年龄和升高变成"+age+" "+high);
    }

    public int funaa(){
        return 0;
    }

    public int funbb(int age){
        return age;
    }

    public double funcc(int age,double high){
        return high;
    }
    
    @Override
    public String toString() {
        return "TestReflection{" +
                "age=" + age +
                ", high=" + high +
                '}';
    }
}

好,我们接着来测试Class类的功能,我们再定义一个新的测试类Test

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取类的三种方式
        Class<?> c1 =  Class.forName("TestReflection");//方法一
        Class<?> c2 = TestReflection.class;//方法二
        TestReflection testReflection = new TestReflection();
        Class<?> c3 = testReflection.getClass();
        System.out.println((c1==c2)+" "+(c2==c3)+" "+(c1==c3));//true true true
    }
}

我们可以看到通过这三种方法我们拿到的对象都是一致的,因为Class的对象只能是一个

2. 使用反射

既然我们拿到对象了,是不是就可以去访问类的内部方法了

public static void main(String[] args) {
        Class<?> c;
        try {
            c = Class.forName("TestReflection");//获取类
            TestReflection testReflection = (TestReflection) c.newInstance();//实例化对象
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

虽然这种实例化对象方法早已弃用,但还是很有研究的,通过源码分析我们可以知道c.newInstance()调用的不带参的构造方法

1. 反射私有构造方法

我们可以通过反射去获取类的私有构造方法
具体我们会使用getDeclaredConstructor方法

public static void main(String[] args) {
        Class<?> c;
        try {
            c = Class.forName("TestReflection");
            //使用getDeclaredConstructor方法,参数是这个私有构造方法的参数类型.class
            Constructor<?> constructor = c.getDeclaredConstructor(int.class);
            constructor.newInstance(99);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

当你满心欢喜运行代码时候,却爆出了异常,提示你没有这个权限
image-20250918193246371
其实这就是Java的安全,怎么办呢,只需要加一条认为确定的权限语句就好

public static void main(String[] args) {
        Class<?> c;
        try {
            c = Class.forName("TestReflection");
            //使用getDeclaredConstructor方法,参数是这个私有构造方法的参数类型.class
            Constructor<?> constructor = c.getDeclaredConstructor(int.class);
            constructor.setAccessible(true);//默认是false
            System.out.println(constructor.newInstance(99));//age=99,high=0.0
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
2. 反射获取类的私有属性

没听错,不光类的私有构造方法可以获取,就连私有属性都可以

public static void main(String[] args) {
        Class<?> c;
        try {
            TestReflection testReflection = new TestReflection();
            testReflection.age = 100;
            c = Class.forName("TestReflection");
            Field field = c.getDeclaredField("age");
            field.setAccessible(true);
            field.set(testReflection,5);
            System.out.println(testReflection.age);//5
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
3. 反射私有方法
public static void main(String[] args) {
        Class<?> c;
        try {
            c = Class.forName("TestReflection");
            Method method = c.getDeclaredMethod("funB");
            method.setAccessible(true);
            //method.invoke();//可修改方法参数
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

3. 总结

总之,反射虽好,能让程序更灵活,但是相对的频繁调用方法会使得效率降低,而且后期想维护也不好维护

二、枚举类

枚举类型目的就是把各个类型集合到一起,便于后续调用

public enum TestEnum {
    A,B,C;
}

1. 使用

//测试枚举类......
    public static void main(String[] args) {
        TestEnum testEnum = TestEnum.A;
        if(testEnum == A){
            System.out.println(true);//true
        }
    }

可以看到我们的确是实例化枚举类中的A类型

2. 常用的方法

//测试枚举类......
    public static void main(String[] args) {
        TestEnum testEnum = TestEnum.A;
        if(testEnum == A){
            System.out.println(true);//true
        }
        //使用数组得出枚举类中的所有类
        System.out.println(Arrays.toString(TestEnum.values()));//[A, B, C]
        //获取各个类型的下标位置,默认从0开始
        System.out.println(TestEnum.A.ordinal());//0
        //将普通字符串转换成枚举实例,生成已存在的枚举类的类型
        TestEnum.valueOf("A");
        //比较索引(默认)
        System.out.println(A.compareTo(B));//-1
    }

3. 构造方法默认私有

如果自定义类型带了参数,需要写构造方法,而且默认是私有构造放大,也就是说类外不可访问

(1),B(2),C(3);
private int a;

TestEnum(int a) {
    this.a = a;
}

但是我们是无法通过反射去访问其私有构造方法,这是JVM底层的限制

4. 总结

因此枚举类其在线程模式下非常安全,其单例模式可以做到真正只有一个对象,而普通的单例模式可以通过反射获取对象
但是枚举类因为其不可被继承性,因此其扩展性较差

三、Lambada表达式

这玩意可以说把简化代码做到了极致,使用->将参数和方法本身分开,达到了简化效果
而且使用这个表达式可以简化匿名内部类的代码编写,且对于函数式变成帮助很大

格式(参数)->表达式或者是(参数)->{代码块...;}
常见格式

()->666//无参数返回666
x->2*x;//接收一个参数x,返回其两倍  
(x,y)->x-y;//接受两个参数x和y,返回其差  
(String str)->System.out.println(str)//接受字符串参数并打印

要使用表达式,得要实现函数式接口

看看表达式是如何简化代码的

1. 不带参无返回值

public static void main(String[] args) {
        //不用表达式,需要使用匿名内部类重写方法
        TestLambada1 testLambada1 = new TestLambada1() {
            @Override
            public void test() {
                System.out.println("不用表达式重写完毕");
            }
        };
        testLambada1.test();
        //使用表达式重写方法
        TestLambada1 testLambada1s = ()->{
            System.out.println("使用表达式重写完毕");
        };
        testLambada1s.test();
    }

2. 带一个参无返回值

TestLambada2 testLambada2 = (age)->{
    System.out.println("岁数是"+age);
};
testLambada2.test(10);//10

3. 带两个参无返回值

TestLambada3 testLambada3 = (age,high)->{
    System.out.println("岁数是"+age+" 身高是"+high);
};
testLambada3.test(19,180.0);

4. 带一个参数有返回值

TestLambada11 testLambada11 = (age)->{return age*10;};
System.out.println(testLambada11.test(10));

5. 带两个参数有返回值

TestLambada22 testLambada22 = (age,high)->{
    return age*10+high/10.0;
};

6. 总结

使用Lambada表达式可以大大简化代码,像我们之前写的匿名内部类重写compareTo方法
使用表达式就可以假话代码至一行,大大提升效率


文章错误不可避免,期待您的指正,我们共同进步


END
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值