java 枚举反射,java lambda表达式用法

  java 枚举反射,java lambda表达式用法

  00-1010一、反射1.1定义1.2用法1.3反射的基本信息1.4与反射相关的类1.5类(反射机制的起源)1.6类中的相关方法1.7获取类对象的三种方式1.8反射的使用1.9反射的优缺点2 .枚举的常用方法2.1枚举类2.2枚举的优缺点3。Lambda表达式3.1语法和lambda表达式3的基本用法

  

目录

  

一、反射

Java的反射机制是在运行状态,对于任意一个类,都能够知道这个类的所有属性和方法;为任意一个对象都能够调用它的任意方法和属性,我们既然可以得到它,我们就可以修改某些类型的信息;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射(reflection)机制.

  00-1010 1.在第三方应用开发的日常过程中,你会经常遇到某种某个成员变量、方法或是属性是私有的只对系统应用开放,然后你可以利用Java的反射机制通过反射来获取所需的私有成员或是方法.

  2.反射式最重要的用途开发各种通用框架.比如在spring中,我们把所有的类bean交给spring容器进行管理,不管是XML配置bean还是注解配置。当我们从容器中获得依赖注入的beans时,容器将读取配置,配置给出关于类的信息。根据这些信息,spring将动态创建这些类。

  

1.1 定义

Java程序中的Java对象在运行时会出现两种类型:比如运行时类型(RTTI)和编译时类型,Person p=new student();在这段代码中,P的类型在编译时是Person,在运行时是Student。程序需要在运行时发现对象和类的真实信息。还有通过使用反射程序就能判断出该对象和类属于哪些类.

  00-1010类名使用Class Class Class表示类的实体,表示运行Java应用程序中的类和接口。字段class表示类的成员变量/属性。方法类表示类的方法。构造函数类表示类的构造方法。

  

1.2 用途

Class表示类的实体,表示正在运行的Java应用程序中的类和接口。

  编译完Java文件后,会生成一个. Class文件,JVM将解释。类文件。编译后的Java文件。类也被JVM解释为对象,也就是java.lang.Class这样,程序运行时,每个类文件最终都会成为类对象的一个实例。通过将Java的反射机制应用到这个实例中,我们可以获得甚至增加和改变这个类的属性和动作,使之成为一个动态类。

  

1.3 反射基本信息

常用获得类相关的方法:

  方法getClassLoader()获取该类的loader getDeclaredClasses()并返回一个数组,该数组包含该类的所有对象(包括私有对象)。forName(String className)根据类名返回该类的对象newInstance(),创建该类的一个实例。getName()获取类的完整路径名常用获得类中属性相关的方法(以下方法的返回值与字段相关)

  方法用途getField(String name)获得某个公有的属性对象getFields()获得某个公有的属性对象getDeclaredField(String name)获得某个属性对象getDeclaredFields()获得某个属性对象获得类中注解相关的方法

  方法属性getAnnotation(Class annotationClass)返回该类中与参数类型匹配的公有注解对象getAnnotations()返回该类所有的公有注解对象getDeclaredAnnotation(Class annotationClass)–getDeclaredAnnotations()返回该类所有的注解对象获得类中构造器相关的方法(以下方法返回值为Constructor相关)

  方法属性getConstructor(Class…<?> parameterTypes)获得该类中与参数类型匹配的公有构造方法getConstructors()获得该类的所有公有构造方法getDeclaredConstructor(Class…<?> parameterTypes)获得该类中与参数类型匹配的构造方法getDeclaredConstructors()获得该类中所以构造方法

  

1.7 获得Class对象的三种方式

在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的Class对象,然后通过Class对象的核心方法,达到反射的目的,即:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到,那么我们就可以修改部分类型信息。

  第一种,使用Class.forName("类的全路径名"); 静态方法。

  前提:已明确类的全路径名。

  第二种,使用.class方法。

  说明:仅适合在编译前就已经明确要操作的Class

  第三种,使用类对象的getClass()方法。

  代码示例:

  本节代码均在一个包下面。

  

package reflectTest;class Student{ //私有属性name private String name = "bit"; //公有属性age public 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); } @ Override public String toString() { return "Student{" + "name=" + name +  + ", age=" + age + }; }}public class test01 { public static void main(String[] args) { try { //通过 Class 对象的 forName() 静态方法来获取,用的最多, //但可能抛出 ClassNotFoundException 异常 Class<?> c1 = Class.forName("reflectTest.Student"); //直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高 //这说明任何一个类都有一个隐含的静态成员变量 class Class<?> c2 = Student.class; //通过getClass获取Class对象 Student student = new Student(); Class<?> c3 = student.getClass(); System.out.println(c1.equals(c2)); System.out.println(c1.equals(c3)); System.out.println(c2.equals(c3)); } catch (ClassNotFoundException e) { e.printStackTrace(); } }}
输出结果:

  

  

  

1.8 反射的使用

package reflectTest;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * 通过class类的newInstance方法获取类的实例 */public class ReflectClassDemo { public static void reflectNewInstance(){ try { //获得Class对象 Class<?> c1 = Class.forName("reflectTest.Student"); //创建类的实例 Student student = (Student) c1.newInstance(); System.out.println(student); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } /** * 反射私有的构造方法 */ public static void reflectPrivateConstructor() { try { Class<?> c1 = Class.forName("reflectTest.Student"); //构造方法 Constructor<?> constructor = c1.getDeclaredConstructor(String.class,int.class); //设置为true后可修改访问权限 constructor.setAccessible(true); Student student = (Student) constructor.newInstance("world",18); System.out.println(student); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } /** * 反射私有属性 */ public static void reflectPrivateField() { try { Class<?> c1 = Class.forName("reflectTest.Student"); Student student = (Student) c1.newInstance(); Field field = c1.getDeclaredField("name"); field.setAccessible(true); field.set(student,"zhang"); System.out.println(student); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } // 反射私有方法 public static void reflectPrivateMethod() { try { Class<?> c1 = Class.forName("reflectTest.Student"); Student student = (Student) c1.newInstance(); Method method = c1.getDeclaredMethod("function",String.class); method.setAccessible(true); method.invoke(student,"我是私有的方法的参数"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } public static void main(String[] args) {// reflectNewInstance();// reflectPrivateConstructor();// reflectPrivateField(); reflectPrivateMethod(); }}

  

1.9 反射优点和缺点

优点

  1.对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法

  2.增加程序的灵活性和扩展性,降低耦合性,提高自适应能力

  3.反射已经运用在了很多流行框架如:Struts、Hibernate、Spring等等。

  缺点

  1.使用反射会有效率问题。会导致程序效率降低。

  2.反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。

  

  

二、枚举

枚举的主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式:

  

public static int final RED = 1;public static int final GREEN = 2;public static int final BLACK = 3;
但是常量举例有不好的地方,例如:可能碰巧有个数字1,但是他有可能误会为是RED,现在我们可以直接用枚举来进行组织,这样一来,就拥有了类型,枚举类型。而不是普通的整形1。

  代码示例:

  

package enumTest;public enum test01 { RED,BLACK,GREEN,WHITE; public static void main(String[] args) {// System.out.println(test01.BLACK);// System.out.println(BLACK); test01 te = test01.BLACK; switch (te) { case RED: System.out.println("red"); break; case BLACK: System.out.println("black"); break; case WHITE: System.out.println("white"); break; case GREEN: System.out.println("green"); break; default: break; } }}
输出结果:

  

  优点:将常量组织起来统一进行管理;

  场景:错误状态码,消息类型,颜色的划分,状态机等等…

  本质:是java.lang.Enum的子类,也就是说,自己写的枚举类,就算没有显示的继承Enum,但是其默认继承了这个类。

  

  

2.1 Enum 类的常用方法

方法名称描述values()以数组形式返回枚举类型的所有成员ordinal()获取枚举成员的索引位置valueOf()将普通字符串转换为枚举实例compareTo()比较两个枚举成员在定义时的顺序values()代码示例

  

public enum test01 { RED,BLACK,GREEN,WHITE; public static void main(String[] args) { test01[] te = test01.values(); for (int i = 0; i < te.length; i++) { System.out.println(te[i]); } } }
输出结果:

  

  ordinal() 代码示例:

  

public enum test01 { RED,BLACK,GREEN,WHITE; public static void main(String[] args) { test01[] te = test01.values(); for (int i = 0; i < te.length; i++) { System.out.println(te[i] + " --> " + te[i].ordinal()); } } }
输出结果:

  

  valueOf() 、compareTo() 代码示例

  

public enum test01 { RED,BLACK,GREEN,WHITE; public static void main(String[] args) { //把字符串变成对应的枚举对象 test01 te = test01.valueOf("RED"); System.out.println(te); System.out.println(RED.compareTo(GREEN));//-2 System.out.println(BLACK.compareTo(RED));//1 } }
输出结果:

  

  枚举的构造方法默认是私有的

  

public enum test01 { //枚举对象 RED("red",1),BLACK(),GREEN(),WHITE(); public String color; public int ordinal;//private 加或者不加其都是私有的 test01(String color, int ordinal) { this.color = color; this.ordinal = ordinal; } //无参构造 test01(){ }}

  

2.2 枚举的优点和缺点

优点

  1.枚举常量更简单安全 。

  2.枚举具有内置方法 ,代码更优雅。

  缺点

  1.不可继承,无法扩展。

  枚举非常安全,不能通过反射,拿到实例对象。枚举本身就是一个类,其构造方法默认为私有的,且都是默认继承于java.lang.Enum枚举可以避免反射和序列化问题

  

三、Lambda 表达式

Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。Lambda表达式(Lambda expression)可以看作是一个匿名函数,基于数学中的λ演算得名,也可称为闭包Closure)。

  

  

3.1 Lambda表达式的语法及基本使用

基本语法:(parameters) -> expression 或 (parameters) ->{ statements; }

  Lambda表达式由三部分组成:

  1.paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型可以省略掉圆括号

  2.->:可理解为被用于的意思

  3.方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不返回。

  

// 1. 不需要参数,返回值为 2() -> 2// 2. 接收一个参数(数字类型),返回其2倍的值x -> 2 * x// 3. 接受2个参数(数字),并返回他们的和(x, y) -> x + y// 4. 接收2个int型整数,返回他们的乘积(int x, int y) -> x * y// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)(String s) -> System.out.print(s)
代码示例:

  

package lambdaTest;@FunctionalInterface//函数式接口interface NoParameterNoReturn { //注意:只能有一个方法 void test();}//无返回值一个参数@FunctionalInterfaceinterface OneParameterNoReturn { void test(int a);}//无返回值多个参数@FunctionalInterfaceinterface MoreParameterNoReturn { void test(int a,int b);}//有返回值无参数@FunctionalInterfaceinterface NoParameterReturn { int test();}//有返回值一个参数@FunctionalInterfaceinterface OneParameterReturn { int test(int a);}//有返回值多参数@FunctionalInterfaceinterface MoreParameterReturn { int test(int a,int b);}public class test01 { public static void main(String[] args) { // {} return 可以省略 NoParameterReturn noParameterReturn = ()->{return 10;}; int ret = noParameterReturn.test(); System.out.println(ret);//10 //()可以省略 OneParameterReturn oneParameterReturn = (a) -> a; System.out.println(oneParameterReturn.test(10));//10 MoreParameterReturn moreParameterReturn = (a,b) -> a+b; System.out.println(moreParameterReturn.test(1,2));//3 } public static void main3(String[] args) { //() {} 可省略 OneParameterNoReturn oneParameterNoReturn = (a)-> System.out.println(a); oneParameterNoReturn.test(10);//10 //int类型可以省略 MoreParameterNoReturn moreParameterNoReturn = (a,b)-> System.out.println(a+b); moreParameterNoReturn.test(10,20);//30 } public static void main2(String[] args) { NoParameterNoReturn noParameterNoReturn = () -> System.out.println("重写方法"); noParameterNoReturn.test(); } public static void main1(String[] args) { NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){ public void test(){ System.out.println("重写方法"); } }; noParameterNoReturn.test(); }}

  

3.2 函数式接口

函数式接口定义:一个接口有且只有一个抽象方法

  注意:

  1.如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口。

  2.如果我们在某个接口上声明了@FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的。

  代码示例:

  

@FunctionalInterface//函数式接口interface NoParameterNoReturn { //注意:只能有一个方法 void test();}public static void main1(String[] args) { NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){ public void test(){ System.out.println("重写方法"); } }; noParameterNoReturn.test(); }}

  

3.3 变量捕获

Lambda 表达式中存在变量捕获 ,了解了变量捕获之后,我们才能更好的理解Lambda 表达式的作用域 。Java当中的匿名类中,会存在变量捕获。

  

package lambdaTest;class Test { public void func(){ System.out.println("func()"); }} public class test02 { public static void main(String[] args) { int a = 100; new Test(){ @Override public void func() { System.out.println("我是内部类,且重写了func这个方法!"); System.out.println("捕获遍历" + a);//能捕获到的变量,要么是常量,要么未发生改变过。 } }; }}
Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。

  优点

  代码简洁,开发迅速;方便函数式编程;非常容易进行并行计算;Java 引入 Lambda,改善了集合操作;

  缺点

  代码可读性变差;在非并行计算中,很多计算未必有传统的 for 性能要高;不容易进行调试;

  

  

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注盛行IT的更多内容!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: