前言:
🌟🌟本期讲解关于反射以及枚举,希望能帮到屏幕前的你。
🌈上期博客在这里:http://t.csdnimg.cn/7D225
🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客
目录
📚️1.反射
1.1反射的定义
1.2反射的用途
1.3反射的相关类
1.4class类(放射机制的起源)
1.5Class类的相关的方法:
1.6获取反射对象的三种方法
1.7反射的总结
📚️2.枚举
2.1背景以及定义
2.2枚举的常用方法
2.3枚举的总结
📚️3.反射和枚举的关系
📚️4.总结
📚️1.反射
1.1反射的定义
对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息;
这种动态获取信息以及动态调用对象方法的功能称为java语言的反射(reflection)机制
1.2反射的用途
小编这里总结:
1.对于某些类中,存在私有的变量或者方法只能供自己类或者系统使用,我们就可以使用Java反射机制获取这些私有的属性,方法。
2. 反射最重要的用途就是开发各种通用框架。
1.3反射的相关类
1.4class类(放射机制的起源)
Java文件被编译后,生成了.class文件,JVM此时就要去解读.class文件 ,被编译后的Java件.class也被JVM解析为一个对象,这个对象就是 java.lang.Class .这样当程序在运行时,每个jav文件就最终变成了Class类对象的一个实例
1.5Class类的相关的方法:
1.获得类的相关方法:
代码实例:
Class<?> c1 = Class.forName("Fmlambda.Student"); //拿到对象
Student student = (Student) c1.newInstance(); //进行实例化
这里小编列举了两个列子
2.获得类中属性的相关方法:
getField(String name)
|
获得某个公有的属性对象
|
getFields()
| 获得所有公有的属性对象 |
getDeclaredField(String name)
|
获得某个属性对象
|
getDeclaredFields()
|
获得所有属性对象
|
代码实例:
public static void reflectPrivateField() {
try {
Class<?> c3 = Class.forName("Fmlambda.Student");
Field field = c3.getDeclaredField("name");
field.setAccessible(true);
Student student = (Student) c3.newInstance();
field.set(student, "idontlovejava");
System.out.println(student);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
注解:拿到反射的类的Class对象,并且获取这个名字私有属性对象,由于name为私有属性所以得“授权”,然后进行实例化,改变这个私有属性对象的内容,最后实现打印。
3.获得类中构造器相关的方法 :
代码实例:
public static void reflectPrivateConstructor() {
try {
Class<?> c2 = Class.forName("Fmlambda.Student");
Constructor<?> constructor = c2.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
Student student = (Student) constructor.newInstance("ilovejava", 20);
System.out.println(student);
} catch (NoSuchMethodException e) {
throw new RuntimeException();
} catch (InstantiationException e) {
throw new RuntimeException();
} catch (InvocationTargetException e) {
throw new RuntimeException();
} catch (IllegalAccessException e) {
throw new RuntimeException();
} catch (ClassNotFoundException e) {
throw new RuntimeException();
}
}
注解:拿到反射的类的Class对象,并且获取这个类中与参数匹配的构造方法,由于为私有属性所以得“授权”,然后进行实例化,改变这个私有构造方法的内容,最后实现打印。
4.获得类中方法相关的方法:
getMethod(String name, Class...<?> parameterTypes)
|
获得该类某个公有的方法
|
getMethods()
|
获得该类所有公有的方法
|
getDeclaredMethod(String name, Class...<?> parameterTypes)
|
获得该类某个方法
|
getDeclaredMethods()
|
获得该类所有方法
|
代码实例:
public static void reflectPrivateMethod() {
Class<?> c4 = null;
try {
c4 = Class.forName("Fmlambda.Student");
Method method = c4.getDeclaredMethod("function", String.class);
method.setAccessible(true);
Student student = (Student) c4.newInstance();
method.invoke(student, "我是一个参数....");
System.out.println();
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
}
}
}
注解:拿到反射的类的Class对象,并且获取这个类中的某个私有方法,进行参数匹配,由于为私有属性所以得“授权”,然后进行实例化,改变这个私有方法的内容,最后实现打印。
1.6获取反射对象的三种方法
第一种 ,使用 Class.forName(" 类的全路径名 "); 静态方法。前提:已明确类的全路径名。第二种 ,使用 .class 方法。说明:仅适合在编译前就已经明确要操作的 Class第三种 ,使用类对象的 getClass() 方法
代码演示:
public static void main(String[] args) {
//1.通过调用getclass
Student student = new Student();
Class c = student.getClass();
//2.直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
//这说明任何一个类都有一个隐含的静态成员变量 class
Class c1 = Student.class;
//3、通过 Class 对象的 forName() 静态方法来获取,用的最多,
//但可能抛出 ClassNotFoundException 异常
Class c2 = null;
try {
c2 = Class.forName("Fmlambda.Student");
} catch (ClassNotFoundException e) {
throw new RuntimeException();
}
注意:使用forName时要抛出异常,要通过try-catch来进行捕获,并进行抛出异常。这里小编加了注解大家可以通过注解来进行查看。
1.7反射的总结
优点:
1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。缺点:
1. 使用反射会有效率问题。会导致程序效率降低
2. 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂
📚️2.枚举
2.1背景以及定义
枚举是在 JDK1.5 以后引入的。主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式
常量举例有不好的地方,例如:可能碰巧有个数字1,但是他有可能误会为是RED,现在我们可以直接用枚举来进行组织,这样一来,就拥有了类型,枚举类型。而不是普通的整形1.
代码如下:
public static final int RED = 1;
public static final int GREEN = 2;
public static final int BLACK = 3;
//改为枚举类型后
public enum TestEnum {
RED,BLACK,GREEN;
}
2.2枚举的常用方法
values()
|
以数组形式返回枚举类型的所有成员
|
ordinal()
|
获取枚举成员的索引位置
|
valueOf()
|
将普通字符串转换为枚举实例
|
compareTo()
|
比较两个枚举成员在定义时的顺序
|
代码实现:
public enum Textdemo {
RED(0,"红色"),WHITE(1,"WHITE"),
GREEN(2,"GREEN"),BLACK(3,"BLACK");
public int ordinal;
public String color;
Textdemo(int ordinal, String color) {
this.ordinal = ordinal;
this.color = color;
}
public static void main(String[] args) {
Textdemo[] textdemos=Textdemo.values(); //以数组的形式返回枚举实例
for (int i = 0; i <textdemos.length ; i++) {
System.out.println(textdemos[i]+"索引位置是"+textdemos[i].ordinal());//进行枚举索引的打印
}
Textdemo textdemo=Textdemo.valueOf("RED"); //将字符串转化为枚举实例
System.out.println(textdemo.color);
System.out.println(WHITE.compareTo(BLACK)); //比较两个枚举在定义时的位置
}
注意:这里的字符串转化为枚举时需要这个字符串时已经被定义了的枚举类型,否则就会报错。这里小编在每个方法之后都加了注解,大家可以按照注解来进行学习。
注意:枚举的构造方法为私有方法,在编写构造方法时,为私有权限符,但是这里可以进行省略
2.3枚举的总结
优点:
枚举常量更加简单和安全
枚举具有内置接口,代码更加简洁优美
缺点:
无法进行继承,不能进行扩展
📚️3.反射和枚举的关系
在上述讲解中,我们知道了关于反射机制,又由于枚举的构造方法是私有的,那么我们可以通过反射来拿到枚举的实例对象呢?
此时就有如下代码:
public static void reflectconstruct() {
try {
Class<?> c1 = Class.forName("Fmlambda.Textdemo");
Constructor<?> constructor = c1.getDeclaredConstructor( int.class, String.class);
constructor.setAccessible(true);
Textdemo textdemo = (Textdemo) constructor.newInstance(5, "紫色");
System.out.println(textdemo);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
此时就会发现代码报错了!!!
此时可以看到没有构造方法!!!
解释:
我们所有的枚举类,都是默认继承与 java.lang.Enum ,说到继承,继承了什么?继承了父类除构造函数外的所有东西,并且子类要帮助父类进行构造而我们写的类,并没有帮助父类构造!
枚举的内部原码构造方法:
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
此时我们发现父类还有两个参数没有进行子类帮助构造
所以改正后代码如下:
constructor = c1.getDeclaredConstructor(String.class, int.class, int.class, String.class);
只用该这一行代码即可,那么此时就可以发现又报错啦~~~~
所以这就是源码的问题了:
源码图示:
这里说明的清清楚楚,就是说不能通过反射获取枚举实例,所以一切真相大白!!!
所以总结:枚举已经被Java的反射机制给过滤了~~~,所以枚举可以避免反射和序列化的问题。
📚️4.总结
💬💬本期小编讲解了关于反射,枚举的相关使用方法,并且附加代码实现讲解,最后通过源码解析总结了反射和枚举之间的关系。
🌅🌅🌅~~~~最后希望与诸君共勉,共同进步!!!
💪💪💪以上就是本期内容了, 感兴趣的话,就关注小编吧。
😊😊 期待你的关注~~~