
文章目录
一、反射
反射的作用就是打破类的封装性,在运行时进行检查,从而能够动态的获取类的内部信息
我们知道,当一个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);
}
}
当你满心欢喜运行代码时候,却爆出了异常,提示你没有这个权限

其实这就是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方法
使用表达式就可以假话代码至一行,大大提升效率
1万+

被折叠的 条评论
为什么被折叠?



