当前位置: 首页 > news >正文

数据结构—(java)反射,枚举,lambda表达式

文章目录

  • 反射
    • 反射的定义:
    • 反射相关的类:
    • 反射相关的方法:
    • 反射示例:
      • 获取Class类对象
      • 创建指定类的对象
      • 反射私有属性:
      • 反射私有方法:
      • 反射私有的构造方法
  • 枚举
    • 枚举的意义
    • 枚举类的实现
    • 枚举类的使用:
    • Enum类中常用的四个方法:
    • 枚举与反射:
  • lambda表达式
    • 函数式接口:
    • lambda表达式的语法:
    • lambda表达式的使用:
    • 关于lambda表达式语法精简的问题:
    • java集合类与lambda表达式的使用问题:
  • 变量捕获:
  • 困惑:


反射

反射的定义:

java的反射机制是指,在程序的运行状态中,对于任意一个类,可以获取这个类的全部信息(包括,类加载器(后面会学到),构造方法,成员属性,成员方法等。)对于任意一个对象,我们也能够调用其属性与方法进行修改信息,这种动态地获取信息与动态地调用对象的机制,我们称为反射机制。

反射相关的类:

在这里插入图片描述

反射相关的方法:

在Class类中即包含了获取类加载器,创建指定类对象,获取构造方法,属性,成员方法的方法,如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

反射示例:

获取Class类对象

此处的Class并不是指表示类名的关键字,而是指Class这个具体的类,
因为Class类的构造方法是私有方法,所以不能够直接实例化对象。
我们需要获取Class类对象有三种方式:
第一种:调用对象的getClass方法

        Student student = new Student();//getClass方法也是用c/c++代码实现的Class<Student> c1 = (Class<Student>) student.getClass();

第二种:直接调用类名的class属性

 但是我们并没有在Student中定义class属性//这说明每一个方法都有一个默认的class属性
   Class c2 = Student.class;

第三种:通过class对象的ForName方法来获取

   Class c3 = null ;c3 = Class.forName("reflectDemo.Student");

判断这三个class对象是不是同一个对象。

        System.out.println(c1 ==c2);System.out.println(c1==c3);System.out.println(c2==c3);

在这里插入图片描述
结果表明,我们通过三种方式创建的三个Class对象实际上是一个,

实际上是因为任何一个类在JVM中只会被加载一次,所以其所对应的Class对象也
只会被创建一次。如果通过两个不同的类来创建Class对象,则这两个Class对象不一样。
    Class c2 = Dog.class;

结果为:此时c2与c1,c3均不相同。
在这里插入图片描述

创建指定类的对象

使用的Student类

public class Student {//私有属性nameprivate String name = "bit"; //公有属性agepublic int age = 18;//不带参数的构造方法public Student(){System.out.println("Student()");}private Student(String name,int age) {this.name = name;this.age = age;System.out.println("Student(String,name)");}private void eat(){System.out.println("i am eat");}public void sleep(){System.out.println("i am pig");}private void function(String str) {System.out.println(str);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +
'}';}}

通过反射实例化对象的方法:

  public static void reflectNewInstance() throws   ClassNotFoundException, InstantiationException, IllegalAccessException {Class c3 = null ;c3 =     Class.forName("reflectDemo.Student");//要通过c3对象来调用实例化对象的方法Student student1 = (Student) c3.newInstance();System.out.println(student1);}

调用此方法。

 public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {//通过class对象创建一个学生对象reflectNewInstance();}

在这里插入图片描述

反射私有属性:

//简写了
public class Student {//私有属性nameprivate String name = "bit"; //公有属性agepublic int age = 18;

反射私有属性的方法:

public static void reflectPrivateField(){Class c3 = null ;try {c3 =   Class.forName("reflectDemo.Student");Field field =  c3.getDeclaredField("name");//我们可以修改这个私有属性的值field.setAccessible(true);//还需要有一个Student对象,Student student3 = (Student)c3.newInstance();field.set(student3,"张三");System.out.println(student3);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}
}
  public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {reflectPrivateField();}

在这里插入图片描述

反射私有方法:

public class Student {
private void eat(String s){System.out.println(s);}}
public static void reflectPrivateMethod(){Class  c4 = null;try {c4 = Class.forName("reflectDemo.Student");//在有参数时一定要加上参数类型的classMethod method = c4.getDeclaredMethod("eat",String.class);Student student4 = (Student) c4.newInstance();method.setAccessible(true);method.invoke(student4, "i am eat");} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}
}
 public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {reflectPrivateMethod();}

在这里插入图片描述

反射私有的构造方法

public class Student {private Student(String name,int age) {this.name = name;this.age = age;System.out.println("Student(String,name)");}
}
 public static void reflectPrivateConstructor(){Class c3 = null ;try {c3 =     Class.forName("reflectDemo.Student");//调用getConstructor方法,参数为Constructor<Student> constructor =  c3.getDeclaredConstructor(String.class,int.class);//在获取了构造方法之后呢?constructor.setAccessible(true);//直接调用此构造方法,为对象赋值Student student2 =    constructor.newInstance("张三",15);System.out.println(student2);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}
  public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {reflectPrivateConstructor();}

在这里插入图片描述

枚举

枚举的意义

枚举是将一组常量组织起来,即将这一组常量赋予特殊的意义,用特殊的类型表示它们。
所用的场景为:错误状态码,消息类型,颜色的划分,状态机等等…

枚举类的实现

枚举类有自己特定的关键字即enum,
在这里插入图片描述
所有我们自己定义的枚举类均继承于java提供的Enum类。

枚举类的使用:

在类中定义枚举成员:

public enum Myenum {//在自定义的枚举类中定义一些成员Red,Yellow,Blue,Green;
}

获取枚举成员:

public enum Myenum {//在自定义的枚举类中定义一些成员Red,Yellow,Blue,Green;public static void main(String[] args) {
//我们可以通过枚举类名,来直接获取枚举成员,而不需要创建枚举类的对象。System.out.println(Myenum.Blue);}
}

关于枚举类的构造方法:
在这里插入图片描述
:因为枚举类型的构造方法是私有的,所以不能够在其他类中进行
创建对象,但是在枚举类中也不能够创建枚举类对象,
在这里插入图片描述
枚举类的使用意义并不在于它的对象,而在于它的枚举成员,其枚举成员可以直接通过类名调用。

Enum类中常用的四个方法:

在这里插入图片描述
因为我们定义的枚举类继承于Enum类,所以Enum类中的所有方法均可使用

public static void main(String[] args) {//关于枚举类中方法的使用//1. values方法,用于获取枚举类中所有的枚举成员。//问题:在Enum类中并没有values方法,那么这个方法是从哪里来的?Myenum[] myenums = Myenum.values();for (Myenum myenum2: myenums) {//在获取了每个枚举成员后,开始进行每个枚举成员的索引位// 2. 调用ordinal方法System.out.println(  myenum2  +" "+myenum2.ordinal());}// 3.  valueof方法,将普通的字符串转换成枚举实例?//    System.out.println(Myenum.valueOf("GREEN"));//意思为:如果在枚举类中有此枚举成员,则会返回对应的枚举成员,如果没有则报异常System.out.println("Red");// 4. 第四个方法:compareTo方法//在Enum类中实现了comparable接口,实现了compareTo方法,用于比较两个//枚举成员的索引位置。System.out.println(Red.compareTo(Blue));}

在这里插入图片描述

枚举与反射:

我们不能够通过枚举的构造方法来实例化枚举类对象,那么能否通过反射机制来创建枚举类对象呢?
实际上是不行的。
Enum类中的构造方法:
在这里插入图片描述

public static void main(String[] args)  {//尝试通过反射进行实例化enum对象Class<?> c1 = null;try {//要注意当父类的构造方法未调用时,子类的构造方法是不能被调用的c1 = Class.forName("enumdemo.Myenum");//枚举类不能够通过反射类进行创建。//在指定的类的具有父类时,也应该加上父类形参类型的.class属性Constructor  constructor=   c1.getDeclaredConstructor(String.class,int.class,int.class,String.class);//获取了相应的构造方法后constructor.setAccessible(true);Myenum myenum = (Myenum) constructor.newInstance(2,"hong");} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}

运行结果:
在这里插入图片描述

lambda表达式

函数式接口:

如果一个接口中只有一个抽象方法,则此接口称为函数式接口。
lambda表达式可代替函数式接口的实现,直接将lambda表达式赋给接口类型的变量。

lambda表达式的语法:

如 : (parameters) -> expression 或 (parameters) ->{ statements; }
. paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明
也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
2. ->:可理解为“被用于”的意思
3. 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反
回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不返回。

lambda表达式的使用:

interface NoParameterNoReturn{//无参且无返回值void test();
}
interface OneParameterNoReturn{//有一个参数无返回值void test(int a);
}
interface MultipleParameterNoReturn{//有多个参数无返回值void test(int a,int b);
}
interface NoParameterReturn{//无参且有返回值int test();
}
interface OneParameterReturn{//有一个参数有返回值int  test(int a);
}
interface MultipleParameterReturn{//有多个参数有返回值int  test(int a,int b);
}public static void main(String[] args) {//Lambda表达式可用于实现只有一个抽象方法的接口。//先实现无返回值无参数的接口NoParameterNoReturn noParameterNoReturn1 = new NoParameterNoReturn() {@Overridepublic void test() {System.out.println("调用无返回值无参数方法");}};//直接调用方法noParameterNoReturn1.test();//我们采用lambda表达式,直接赋给noParameterNoReturns变量NoParameterNoReturn noParameterNoReturn2 = ()->{ System.out.println("调用无返回值无参数方法");};noParameterNoReturn2.test();}

在这里插入图片描述
此两种方式效果相同。

 public static void main(String[] args) {//调用一个无参有返回值的方法NoParameterReturn noParameterReturn = ()->10;  //可以不写return 关键字,直接写数值或语句System.out.println(noParameterReturn.test());}

在这里插入图片描述

关于lambda表达式语法精简的问题:

  1. 参数类型可以省略,如果需要省略,每个参数的类型都要省略。
  2. 参数的小括号里面只有一个参数,那么小括号可以省略
  3. 如果方法体当中只有一句代码,那么大括号可以省略
  4. 如果方法体中只有一条语句,且是return语句,那么大括号可以省略,且去掉return关键字。

java集合类与lambda表达式的使用问题:

在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {//举例:ArrayList中的forEach语句ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(10);arrayList.add(20);arrayList.add(15);//遍历数组可以用迭代器,foreach语句等,也可以采用arrayList本身的方法//accept是接口中的抽象方法,将其重写//方法1:直接创建匿名内部类调用。arrayList.forEach(new Consumer<Integer>() {@Overridepublic void accept(Integer integer) {System.out.println(integer);}});// 方法2:通过lambda表达式//当我们这样编写时,代码很简洁,但是可读性比较差。arrayList.forEach((a)->{System.out.println(a);});}
 public static void main(String[] args) {//举例: List中的sort方法ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(10);arrayList.add(20);arrayList.add(15);/* arrayList.sort(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1.compareTo(o2);}});*/// System.out.println(arrayList);arrayList.sort(((o1, o2) -> {return o1.compareTo(o2);}));System.out.println(arrayList);}

注:

      Lambda表达式的优点是代码简洁,编写方便,缺点,代码可读性变差,不容易调试

变量捕获:

    //变量捕获是指在匿名内部类,或lambda表达式中,所使用的变量在此之前与之后不能被修改,或者此变量被final修饰

在这里插入图片描述
在这里插入图片描述

困惑:

问题:

  1. Enum中并没有value方法,为什么在自定义的enum类中可以使用这个方法?
  2. 为什么匿名内部类与lambda表达式中用到的变量必须被final修饰或者在使用之前与之后不能被修改?
  3. 我们不能通过枚举的构造方法来创建其对象,也不能通过反射类来创建对象,那么此构造方法还有什么意义?
  4. 什么是类加载器,它是物理的,还是概念的?软件的?
  5. 枚举成员可以通过类名调用,它存放在哪里?答:存放在常量池(也被称为静态区或方法区)当中。

相关文章:

  • 开发受用户喜欢有声听书APP:快速满足用户需求的秘诀
  • [PICO VR眼镜]眼动追踪串流Unity开发与使用方法,眼动追踪打包报错问题解决(Eye Tracking/手势跟踪)
  • 使用 LlamaIndex 进行 CRAG 开发用来强化检索增强生成
  • python 将 aac 转为 mp3,保持原有目录结构
  • Spring 全家桶使用教程 —— 后端开发从入门到精通
  • 江协科技STM32学习- P19 TIM编码器接口
  • 深入理解函数【JavaScript】
  • WPF项目中使用Caliburn.Micro框架实现日志和主题切换
  • ubuntu20.04系统安装zookeeper简单教程
  • 【PostgreSQL】PostgreSQL数据库允许其他IP连接到数据库(Windows Linux)
  • MATLAB案例 | Copula的密度函数和分布函数图
  • vue echarts tooltip动态绑定模板,并且处理vue事件绑定
  • 将ai模型部署在服务器,会比本地离线更快吗
  • Proteus-7.8sp2安装
  • 论文阅读 | 一种基于潜在向量优化的可证明安全的图像隐写方法(TMM 2023)
  • 5、React组件事件详解
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • Electron入门介绍
  • JWT究竟是什么呢?
  • MD5加密原理解析及OC版原理实现
  • Python十分钟制作属于你自己的个性logo
  • Vue 2.3、2.4 知识点小结
  • Vue--数据传输
  • web标准化(下)
  • 从0实现一个tiny react(三)生命周期
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 两列自适应布局方案整理
  • 每天10道Java面试题,跟我走,offer有!
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 一文看透浏览器架构
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #define 用法
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (附源码)spring boot校园拼车微信小程序 毕业设计 091617
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (排序详解之 堆排序)
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (总结)(2)编译ORB_SLAM2遇到的错误
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)
  • .DFS.
  • .FileZilla的使用和主动模式被动模式介绍
  • .gitignore文件设置了忽略但不生效
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .NET Core中如何集成RabbitMQ
  • .net 验证控件和javaScript的冲突问题