0
点赞
收藏
分享

微信扫一扫

反射、枚举、lambada

40dba2f2a596 2022-01-21 阅读 97

目录

1、反射的使用

(1)定义

(2)用途

(3)反射相关的类

(4)常用获得类相关的方法

(5)反射的一些使用实例:

2、枚举的使用

(1)背景和定义

(2)常用方法

(3)枚举的优缺点

优点:

缺点:

(4)反射的特点

3、lambda表达式

(1)背景

(2)lambda表达式的语法

(3)lambda表达式的语法

(4)变量捕获

(5)lambda表达式在集合当中的使用

a.foreach在list中的使用:

(5)lambda表达式的总结

优点:

缺点:


1、反射的使用

(1)定义

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

(2)用途

1、在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应 用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法 。

2、反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论 是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类 的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。

(3)反射相关的类

(4)常用获得类相关的方法

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

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

第二种,使用 .class 方法。

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

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

常用的是forName方法。

一个类对应一个class对象

(5)反射的一些使用实例:

自已定义一个student类,里面的私有变量和公共变量,私有构造方法和共有构造方法。

class Student {
    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 +
                '}';
    }
}

里面使用反射的方式就可以不new一个对象就创建一个新的对象

使用代码如下:

public static void reflectNewInstance() {
    try {
        Class<?> c1 = Class.forName("demo.Student");
        Student student = (Student) c1.newInstance();
        System.out.println(student);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

此时在主函数中调用reflectNewInstance函数就可以输出student,从代码中可以看出,这里并没有new一个student,却用了Student类中的无参数构造方法来创建出一个对象。

这里也可以在函数中调用public修饰的方法。

并且也可以反射私有的构造方法

 代码如下:

public static void reflectPrivateConstructor() {
    try {
        Class<?> c1 = Class.forName("demo.Student");
        Constructor<?> constructor = c1.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);
        Student student = (Student) constructor.newInstance("YT",19);
        System.out.println(student);
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

使用getDeclaredConstructor就可以获取到私有的构造方法。

获取和修改私有字段代码:

public static void reflectPrivateField() {
    try {
        Class<?> c1 = Class.forName("demo.Student");
        Field field = c1.getDeclaredField("name");
        field.setAccessible(true);
        Student student = (Student) c1.newInstance();
        field.set(student,"YT");
        System.out.println(student);
        String str = (String) field.get(student);
        System.out.println(str);
    } catch (ClassNotFoundException | NoSuchFieldException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

调用私有方法:

 

public static void reflectPrivateMethod() {
    try {
        Class<?> c1 = Class.forName("demo.Student");
        Method method = c1.getDeclaredMethod("eat");
        Student student = (Student) c1.newInstance();
        method.setAccessible(true);
        method.invoke(student);
        method = c1.getDeclaredMethod("function", String.class);
        method.setAccessible(true);
        method.invoke(student,"私有方法");
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}

如果私有方法是有返回值的,就要用和返回值类型相同的变量来接受,但这里记得要类型转换。 

所以反射是有利有弊的。

反射优点:

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

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

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

反射缺点:

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

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

反射总结:反射实际上就是一种机制,在运行期间,在运行期间,可以动态获取当前对象的属性,类型,方法等等(类的信息)

2、枚举的使用

(1)背景和定义

枚举是在JDK1.5以后引入的。主要用途是:将一组常量组织起来。

可以知道在java里面枚举是一个对象。

public enum TestEnum {
    RED,BLACK,GREEN
}

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

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

public static void main(String[] args) {
    TestEnum testEnum = TestEnum.BLACK;
    switch (testEnum) {
        case RED:
            System.out.println("RED");
            break;
        case BLACK:
            System.out.println("BLACK");
            break;
        case GREEN:
            System.out.println("GREEN");
            break;
        case WHITE:
            System.out.println("WHITE");
            break;
        default:
            System.out.println("无对应选择");
            break;
    }
}

(2)常用方法


public static void main(String[] args) {
    TestEnum[] testEnums = TestEnum.values();
    for (int i = 0; i < testEnums.length; i++) {
        System.out.println(testEnums[i]);
    }
}

 


public static void main(String[] args) {
    TestEnum testEnum = TestEnum.valueOf("RED");
    System.out.println(testEnum);
}


public static void main(String[] args) {
    System.out.println(RED.compareTo(BLACK));
}

 

用compareTo就可以对枚举定义的顺序进行比较

 枚举的构造方法:

public enum TestEnum {
    RED("红色",1),BLACK("黑色",2),GREEN("绿色",3),WHITE("白色",4);
    public String color;
    public int ordinal;
    TestEnum(String color,int ordinal) {
        this.color = color;
        this.ordinal = ordinal;
    }
}

 重要:枚举的构造方法默认是private的。

(3)枚举的优缺点

优点:

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

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

缺点:

a. 不可继承,无法扩展

(4)反射的特点

反射不可以获取枚举对象,所以枚举可以用来实现单例模式。(只有一个对象)

3、lambda表达式

(1)背景

Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达 式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。

lambda实则就是一个匿名函数

正常的函数是有:返回值 方法名(参数列表) { 方法体 }、

而匿名函数是没有方法名的,并可以不写返回值。

(2)lambda表达式的语法

基本语法:

(parameters) -> expression 或 (parameters) ->{ statements; }

(3)lambda表达式的语法

函数式接口:

@FunctionalInterface
interface NoParameterNoReturn {
    //只能有一个方法
    void test();
}

当创建一个继承了这个接口的类,并对这个函数进行重写:

用正常的方式:

@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}
public class TestDemo {
    public static void main(String[] args) {
        NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn() {
            @Override
            public void test() {
                System.out.println("haha");
            }
        };
    }
}

用lambda表达式:

无返回值无参数的lambda表达式:

public class TestDemo {
    public static void main(String[] args) {
        NoParameterNoReturn noParameterNoReturn = () ->{
            System.out.println("haha");
        };
        noParameterNoReturn.test();
    }
}

有返回值有一个参数:

@FunctionalInterface
interface OneParameterHaveReturn {
    int test(int a);
}
public class TestDemo {
    public static void main(String[] args) {
        OneParameterHaveReturn oneParameterHaveReturn = (int a) -> {return a;};
        System.out.println(oneParameterHaveReturn.test(10));
    }
}

无返回值多个参数:

@FunctionalInterface
interface MoreParameterNoReturn {
    void test(int a,int b);
}
public class TestDemo {
    public static void main(String[] args) {
        MoreParameterNoReturn moreParameterNoReturn = (int a,int b) -> {
            System.out.println(a + " " + b);
        };
        moreParameterNoReturn.test(10,11);
    }
}

lambda表达式可以简化代码,但是简化代码就会带来代码的可读性降低的问题,并且lambda还可以有更简单的减法。

例如,有返回值有一个参数可以更简化为:

@FunctionalInterface
interface OneParameterHaveReturn {
    int test(int a);
}
public class TestDemo {
    public static void main(String[] args) {
        OneParameterHaveReturn oneParameterHaveReturn = (a) -> a;
        System.out.println(oneParameterHaveReturn.test(10));
    }
}

所以一般来讲lambda的使用场景是比较少的。

lambda的使用:

例如在构造大根堆和小根堆的时候:

PriorityQueue<Integer> priorityQueue = new PriorityQueue<>((o1,o2) -> o1 - o2);
priorityQueue.add(1);
priorityQueue.add(2);
priorityQueue.add(4);
System.out.println(priorityQueue);

(4)变量捕获

class Test {
    public void func() {
        System.out.println("func()");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        int a = 10;
        new Test() {
            @Override
            public void func() {
                System.out.println("这是重写内部类方法");
                System.out.println(a);
            }
        }.func();
    }
}

这里的a就是所捕获的变量,这里的a就不能在重写的func里面被修改了。

所以a一定是常量或者是一个没有改变的量。

lambda变量捕获:

同理,在lambda表达式里面,也不能补修改捕获变量:

(5)lambda表达式在集合当中的使用

为了能够让Lambda和Java的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与Lambda表达式对接。

a.foreach在list中的使用:

public class TestDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(123);
        list.add(234);
        list.add(345);
        list.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
            }
        });
        System.out.println("==============");
        list.forEach((a) -> System.out.println(a));
    }
}

b.foreach在hashmap中的使用

public class TestDemo {
    public static void main(String[] args) {
        HashMap<Integer,String> hashMap = new HashMap<>();
        hashMap.put(1,"123");
        hashMap.put(2,"234");
        hashMap.put(3,"345");
        hashMap.forEach(new BiConsumer<Integer, String>() {
            @Override
            public void accept(Integer integer, String s) {
                System.out.println("key:"+integer + " value:"+s);
            }
        });
        System.out.println("=================");
        hashMap.forEach((Integer integer,String s) -> System.out.println("key:"+integer + " value"+s));

    }
}

 ​​结果:

 使用lambda表达式就可以用一行代码解决多行代码才能解决的问题,但是这也明显地降低了代码的可读性,所以一般较少使用。

(5)lambda表达式的总结

Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。

优点:

1. 代码简洁,开发迅速

2. 方便函数式编程

3. 非常容易进行并行计算

4. Java 引入 Lambda,改善了集合操作

缺点:

1. 代码可读性变差

2. 在非并行计算中,很多计算未必有传统的 for 性能要高

3. 不容易进行调试

举报

相关推荐

0 条评论