反射,枚举,lambda表达式

目录

 

一、反射

1、反射

2、用途

3、反射相关的类

(1)Class类

(2)Filed类

(3)Method类

(4)ConStructor类

4、反射示例

(1)获取class类的三种方法

 (2)反射的使用

5、反射的优缺点

二、枚举

1、定义

2、使用

 3、枚举的优缺点

4、枚举和反射

三、Lambda表达式

1、Lambda的语法

2、函数式接口

3、Lambda表达式的使用

4、变量捕获

5、Lambda表达式在集合中的使用

(1)Collection接口的forEach()方法

(2)List接口的sort()方法

(3)HashMap的forEach()方法

6、Lambda表达式的优缺点


一、反射

1、反射

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

反射需要引入java.lang.reflect

2、用途

  • 某个类的私有的成员变量和方法只对系统应用开放,我们可以通过反射来获取到所需要的私有的成员变量或者方法;
  • 反射最重要的用途是开发各种通用的框架。比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取数据,而配置中给的就是类的信息,spring根据这些信息,需要创建哪些Bean,spring就动态的创建这些类。

3、反射相关的类

类名 用途
Class类 代表类的实体,在运行的java应用程序中表示类和接口
Filed类 代表类的成员变量/类的属性
Method类 代表类的方法
Constructor类 代表类的构造方法

(1)Class类

常用方法:

方法 用途
getClassLoader() 获取类的加载器
getDeclaredClasses() 返回一个数组,这个数组中包含该类中所有类和接口类的对象(包含私有的)
forName(String classname) 根据类名返回类的对象
newInstance()

创建类的实例

getName() 获取类的完整路径名字

(2)Filed类

常用方法:

方法 用途
getFiled(String name) 获得某个公有的属性对象
getFileds() 获取所有的公有的属性对象
getDeclaredFiled(String name) 获取某个属性对象
getDeclaredFileds() 获取所有的属性对象

(3)Method类

常用方法:

方法 用途
getMethod(String name, Class...<?> parameterTypes) 获得该类某个公有的方法
getMethods() 获得该类所有公有的方法
getDeclaredMethod(String name, Class...<?> parameterTypes) 获得该类某个方法
getDeclaredMethods() 获得该类所有方法

(4)ConStructor类

常用方法:

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

4、反射示例

(1)获取class类的三种方法

在反射之前,第一步是先要拿到需要反射的类的class对象,然后通过class类的核心方法,达到反射的目的。

  • 第一种:Class.forName("类的全路径名")
  • 第二种:类名.class(使用.class方法)
  • 第三种:使用类对象的getClass()方法

0ea06f9239a74f34a7bdcf628668451e.png

 (2)反射的使用

  • 使用反射创建对象

    33036de777ca4fafb699d50d4ab57f20.png

  • 反射构造方法

    5bcac914d3d74f8c9daa0d156e39e299.png

    06bfe21ed6a64c8a87a8852df85b7727.png

  • 反射属性

    a38a00f56ab248f1a0f570960f561c48.png

  • 反射方法

    df045c8208b64c72a44e6d89887ef7d7.png

创建对象的几种方式:

  • 使用new关键字创建
  • clone()方法创建
  • newInstance()→Class类

5、反射的优缺点

优点:

  • 对于任意一个类,都能够知道这个类的所有的属性和方法;对于任意一个对象,都能够调用它的任意一个方法;
  • 增加了程序的灵活性和扩展性,降低了耦合性,提高了自适应能力;
  • 反射应用到了很多的框架中:Struts、Spring等等。

缺点:

  • 使用反射程序的效率很低;
  • 反射技术绕过了源代码的技术,因而会带来维护问题。反射的代码更加复杂。

二、枚举

1、定义

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

public static int final RED = 1;
public static int final GREEN = 2;
public static int final BLACK = 3;

使用常量举例存在不好的地方:如果有一个数字1,可能会误认为是RED。如果使用枚举来组织,就拥有了类型,而不是整型1。

public enum TestEnum {
    RED,BLACK,GREEN;
}

本质:是Enum的子类,自己写的枚举类,即便没有显示的继承Enum,也会默认继承这个类。

2、使用

枚举通常搭配switch来使用。

常用方法:

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

枚举类的API中没有values()方法,所以,它到底在哪里?

重要:枚举类的默认方法是私有的!!!

f67a0acfb25f4522835404a2ffef8701.png

 3、枚举的优缺点

优点:

  • 枚举常量更简单安全
  • 枚举具有内置方法,代码更优雅

缺点:

  • 不可继承,无法扩展

4、枚举和反射

66a4695ba5504699afa44dc14c2722cd.png

c97f0bd270c2454e91d9ec594e70af5a.png

面试题:如何实现一个线程安全的单例模式?

 可以通过枚举来实现一个线程安全的单例模式。(不能通过反射来获取枚举的实例)

三、Lambda表达式

Lambda表达式允许通过表达式来代替接口的功能。Lambda表达式和方法一样,提供了一个正常的参数列表和一个使用这些参数的主体(一个表达式或者一个代码块)。可以看作是一个匿名函数。

1、Lambda的语法

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

Lambda表达式由三部分组成:

  • parameters:类似方法的形参列表,这里的参数是函数式接口里的参数。参数类型可以声明也可以不声明由JVM隐含的推断。只有一个参数时可以省略小括号。
  • →:“被用于”的意思;
  • 方法体:可以是表达式也可以是代码块,是函数式接口里方法的实现。代码块等同于方法中的方法体。

2、函数式接口

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

【注】

  • 一个接口只有一个抽象方法,该接口就是一个函数式接口;
  • 可以在接口上使用@FunctionalInterface注解,此时编译器会按照函数式接口的定义来要求该接口,如果接口中定义了两个抽象方法,程序编译就会报错。

定义函数式接口,可以只有一个抽象方法,也可以有其它的default方法:

//方式一:
@FunctionalInterface
interface NoParameterNoReturn {
    //注意:只能有一个方法
    void test();
}
//方式二:
@FunctionalInterface
interface NoParameterNoReturn {
    void test();
    default void test2() {
        System.out.println("JDK1.8新特性,default默认方法可以有具体的实现");
    }
}

3、Lambda表达式的使用

以无参无返回值的函数式接口为例:

//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}

//使用匿名内部类实现接口
NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){
    @Override
    public void test() {
        System.out.println("hello");
    }
};

//使用Lambda表达式实现接口
NoParameterNoReturn noParameterNoReturn = ()->System.out.println("hello");

【注】

  • 参数类型可以省略,如果省略,所有参数都要省略;
  • 只有一个参数,参数的小括号可以省略;
  • 方法体只有一条语句,大括号可以省略;
  • 方法体只有一条语句,且其是return语句,大括号可以省略,且去掉return关键字。

4、变量捕获

Lambda表达式本质就是使用匿名内部类来实现接口。

对于以下代码,a就是捕获变量:

@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}
public static void main(String[] args) {
    int a = 10;
    NoParameterNoReturn noParameterNoReturn = ()->{
        // a = 99; error
        //变量a就是捕获变量
        System.out.println("捕获变量:"+a);
    };
    noParameterNoReturn.test();
}

进行变量捕获时,捕获的变量要么被final修饰,如果不被final修饰,要保证变量不能被修改。

5、Lambda表达式在集合中的使用

为了让Lambda表达式在Java集合中更好的使用,集合当中,新增了部分接口,以便于Lambda表达式进行对接。

接口 方法
Collection removeIf()、stream()、forEach()、spliterator()
List replaceAll()、sort()
Map

forEach()、replaceAll()、remove()、replace()、compute()、

merge()

(1)Collection接口的forEach()方法

//原型如下
default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}
//Lambda表达式
list.forEach(s -> {
    System.out.println(s);
});

(2)List接口的sort()方法

//按照字符串的长度进行排序
list.sort(new Comparator<String>() {
    @Override
    public int compare(String str1, String str2){
        //注意这里比较长度
        return str1.length()-str2.length();
    }
});
//Lambda表达式
list.sort((str1,str2)-> str1.length()-str2.length());

(3)HashMap的forEach()方法

default void forEach(BiConsumer<? super K, ? super V> action) {
    Objects.requireNonNull(action);
    for (Map.Entry<K, V> entry : entrySet()) {
        K k;
        V v;
        try {
            k = entry.getKey();
            v = entry.getValue();
        } catch(IllegalStateException ise) {
        // this usually means the entry is no longer in the map.
            throw new ConcurrentModificationException(ise);
        }
     action.accept(k, v);
}

map.forEach(new BiConsumer<Integer, String>(){
    @Override
    public void accept(Integer k, String v){
        System.out.println(k + "=" + v);
    }
});
//Lambda表达式
map.forEach((k,v)-> System.out.println(k + "=" + v));

6、Lambda表达式的优缺点

优点:

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

缺点:

  • 代码可读性变差
  • 不容易进行调试
  • 在非并行计算中,很多计算没有for的性能高

猜你喜欢

转载自blog.csdn.net/weixin_54342360/article/details/124629731