* [反射的优缺点](#_107)
+ [枚举](#_114)
+ - * [枚举的定义](#_119)
* [枚举的常用方法](#_146)
+ [枚举是否可以反射](#_176)
+ [单例模式(了解)](#_180)
+ [Lambda表达式](#Lambda_220)
+ - * [函数式接口](#_226)
* [用法](#_231)
* [举例](#_264)
反射
在java中,通过编译会生成一个.class的字节码文件,在使用java命令来运行java文件的时候,第一步java.exe启动JVM,第二步JVM启动类加载器,第三步类加载器加载对应类,类加载器有三种,分别是:
Boot Strap Class Loader 启动类加载器
Extension Class Loader
Application Class Loader 自定义类
这里会采用双亲委派模型来加载类,加载成功后就变成了一个Class对象,而这个对象中存储的就是当前类的信息。
而下一步就会进入一个链接的环节:链接指的是将Java类的二进制代码合并到JVM的运行状态之中的过程,这个过程包含验证、准备、解析等几个步骤,验证用来确保java类的二进制表示在结构上是正确的,如果出现错误,则会抛出异常。准备过程是建造java类的静态域,并将这些域的值设置为默认值,而解析的过程是确保java类引用 的其他类,包括接口,父类,方法的形参,返回值等能够被正确的寻找到,解析的过程可能会导致其他的java类被加载。
当一个java类第一次被真正使用时,JVM会进行该类的初始化操作。初始化过程的主要操作时执行静态代码块和初始化静态域。且其父类也会被初始化(接口的父类不需要初始化)
java的反射是指在运行状态中,对于任意一个类,都能知道这个类的所有方法与属性;对于任意一个对象,都能够调用这个类的方法与属性。
Java程序中许多对象在运行时会出现两种类型:运行时类型(RTTI)和编译时类型
反射中重要的几个类型:
Class 代表类的实体,表示类或接口
Filed 表示类的成员变量
Method 表示类的方法
Constructor 表示类的构造方法
获得Class对象的方法
如果要进行反射,那么就需要拿到一个当前需要反射的类的一个对象,通过这个对象的核心方法,达到反射的目的。
而获取Class的方法有三种:
首先写一个要操作的类:(自定义类,没有要求)
package reflect;
class Picture{
private String name = "lit";
public String color = "black";
Picture() {
System.out.println(name+color);;
}
private Picture (String name ,String color){
this.color = color;
this.name = name;
System.out.println(name+color);
}
private void func (){
System.out.println("这是一个func方法");
}
@Override
public String toString() {
return "Picture{" + "name='" + name + '\'' + ", color=" + color + '}';
}
}
使用类对象的getClass()方法
Picture p1 = new Picture();
Class c1 = p1.getClass();
使用.class方法
适合在编译前就已经明确要操作的class
Class c2 = Picture.class;
使用Class.forName(“类的全路径名”);静态方法
适合确定了要操作的类的全路径
try {
Class c3 = Class.forName("reflect.Picture");//这里的Picture是需要操作的类的全路径,如果有包,则需要加上包的路径
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
反射的使用
class的对象获取到了,接下来就该反射了,这里要注意的是,所有与反射相关的包都在import java.lang.reflect这个路径下。
反射调用私有的构造方法:
try {
Class<?> cl = Class.forName("reflect.Picture");
//加了Declared就是不仅可以调用公开的,也可以调用私有的
Constructor<?> constructor = cl.getDeclaredConstructor(String.class,String.class);//后面的参数是需要操作的构造方法的参数
//cl.getConstructor();
constructor.setAccessible(true);//修改访问权限
Object obj = constructor.newInstance("abcd","white");//传值
Picture pic = (Picture) obj;
System.out.println(pic);
}catch (Exception e){
e.printStackTrace();
}
反射修改私有的属性:
try {
Class<?> cl = Class.forName("reflect.Picture");
//加了Declared就是不仅可以调用公开的,也可以调用私有的
Field field = cl.getDeclaredField("name");//此处填要操作的属性的变量名
field.setAccessible(true);//修改访问权限
Object obj = cl.newInstance();//传值
Picture pic = (Picture) obj;
field.set(pic,"what");
System.out.println(pic);
}catch (Exception e){
e.printStackTrace();
}
反射调用私有方法:
try {
Class<?> cl = Class.forName("reflect.Picture");
Method method = cl.getDeclaredMethod("func");//无参,则只需要传入一个String类型的方法名,有参数则在后面加参数类型.class
method.setAccessible(true);
Object obj = cl.newInstance();
Picture pic = (Picture) obj;
method.invoke(pic);
}catch (Exception e){
e.printStackTrace();
}
反射的优缺点
反射的优点:
对于任意一个类,通过反射都能获取这个这个类的任意方法或属性,对于任何一个对象,通过反射可以调用这个对象堆所有方法,也可修改这个对象的所有属性
增加程序的灵活性、扩展性,降低耦合性
反射的缺点:
有效率问题,会导致程序效率降低
因为绕过了源代码,所以会带来相应的维护问题
枚举
将一组常量组织起来进行统一管理
在java中,枚举实际上就是一个类,但是,枚举的构造方法默认是私有的
优点:更简单,安全,有内置方法,代码更优雅,可避免反射和序列化问题
缺点:不可继承,无法扩展
枚举的定义
枚举是可以使用switch语句的:
public enum MyEnum {
dog,cat,pig,sheep;
public static void main(String[] args) {
MyEnum myEnum = MyEnum.cat;
switch (myEnum){
case cat:
System.out.println("cat");
break;
case dog:
System.out.println("dog");
break;
case pig:
System.out.println("pig");
break;
case sheep:
System.out.println("sheep");
break;
default:
System.out.println("null");
break;
}
}
}
枚举的常用方法
values()以数组形式返回枚举类型的所有成员
public static void main(String[] args) {
MyEnum[] myEnums = MyEnum.values();//以数组形式返回枚举类型的所有成员
}
ordinal()获取枚举成员的索引位置
public static void main(String[] args) {
for (int i = 0; i <myEnums.length ; i++) {
System.out.println(myEnums[i] + " " + myEnums[i].ordinal());//获取枚举成员的索引位置
}
}
valueOf()将普通字符串转换为枚举实例
public static void main(String[] args) {
System.out.println(MyEnum.valueOf("cat"));//大小写敏感
}
compareTo()比较两个枚举成员在定义时的顺序
public static void main(String[] args) {
MyEnum myEnums1 = MyEnum.sheep;
MyEnum myEnums2 = MyEnum.pig;
# 最后
金三银四马上就到了,希望大家能好好学习一下这些技术点
学习视频:
![](https://img-blog.csdnimg.cn/img_convert/65ec5df3b0bcf1b7311dfe32b7e8b866.webp?x-oss-process=image/format,png)
大厂面试真题:
![](https://img-blog.csdnimg.cn/img_convert/a922aebf768e3dedaf1a8031eb605ef6.webp?x-oss-process=image/format,png)
public static void main(String[] args) {
MyEnum myEnums1 = MyEnum.sheep;
MyEnum myEnums2 = MyEnum.pig;
# 最后
金三银四马上就到了,希望大家能好好学习一下这些技术点
学习视频:
[外链图片转存中...(img-1dHDZFXV-1714722910382)]
大厂面试真题:
[外链图片转存中...(img-WUEWAQxp-1714722910383)]
> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/topics/618154847)收录**