2021/07/24笔记

我们于2021/07/24 的学习目标是:反射,注解和函数式接口,核心任务为:

1、学习技术:

1)、反射的概念

2)、反射操作构造器和反射创建对象

3)、反射操作属性和方法

4)、反射操作数组

5)、注解的概念

6)、元注解

7)、自定义注解

8)、注解解析器

9)、函数式接口

2、文档总结

1)、反射的概念

反射是发生在程序运行期间的动态机制或行为,Java中唯一的动态机制就是反射机制。

对于:

class Person{

    void test(){

    }

}



class Student extends Person{

    void test(){

    }

}

class Teacher extends Person{

    void test(){

    }

}

有:

//通过反射创建对象

        Person obj = (Person) Class.forName(pro.getProperty("Student")).newInstance();

        obj.test();

Java反射机制,可以实现以下功能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法
  • 生成动态代理

反射的源头:

Class<T> Class类型的实例可以用来表示Java运行期间的一个类型

Class对象:

   Class对象在类第一次加载到内存后就已经存在的,唯一的,不变的,每一个类型只有一个Class对象可以操作这个类的所有内容(属性方法构造器…)

如何获取反射的源头:Class对象

  • 类名.class
  • Class.forName(权限定名)

权限定名推荐命名成 包名.类名 的格式

  •  对象.getClass()
//1.类名.class

        Class<String> cls1 = String.class;

        System.out.println(cls1.toString());



        //2.Class.forName(权限定名)

        Class cls2 = Class.forName("java.lang.String");

        System.out.println(cls2);

        System.out.println(cls2==cls1);



        //3.对象.getClass()

        Class cls3 = "abc".getClass();

        System.out.println(cls3);

        System.out.println(cls3==cls1);



        //获取当前Class对象所表示类型的父类的Class对象

        Class cls4 = cls1.getSuperclass();

        System.out.println(cls4);

        System.out.println(cls4==Object.class);



        //获取基本数据类型的Class对象

        System.out.println(Integer.class);

        System.out.println(int.class);

        System.out.println(int.class==Integer.class);

        System.out.println(Integer.TYPE);

        System.out.println(Integer.TYPE==int.class);

2)、反射操作构造器和反射创建对象

反射操作构造器:

构造器<T> getConstructor(类<?>... parameterTypes) 

返回一个 构造器对象,该对象反映此 类对象所表示的类的指定公共构造函数。

构造器<?>[] getConstructors() 

返回一个包含构造器对象的数组, 构造器对象反映了此 类对象所表示的类的所有公共构造函数。

以上都是获取公共的,被public修饰的构造器

构造器<T> getDeclaredConstructor(类<?>... parameterTypes) 

返回一个构造器对象,该对象反映此类对象所表示的类或接口的指定构造函数。

构造器<?>[] getDeclaredConstructors() 

返回构造器对象的数组, 构造器对象反映由此类对象表示的类声明的所有构造函数。

反射创建对象:

Class-->T newInstance()  

默认调用类型的空构造为对象初始化信息

   不推荐使用,因为不能确定一个类型是否存在空构造,极有可能遇到运行时异常

Constructor---> T newInstance(Object... initargs)

   创建对象的同时调用当前构造器为对象初始化信息


 

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

public class Class003_Reflect {

    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {





        //获取构造器

        Class<User> cls = User.class;



        Constructor[] cons =  cls.getConstructors();

        for(Constructor con:cons){

            System.out.println(con);

        }



        Constructor<User> con = cls.getDeclaredConstructor(String.class,int.class);

        System.out.println(con);



        //创建对象

        //1)

        User user =  User.class.newInstance();

        System.out.println(user);



        //2) 私有内容需要忽略权限使用

        con.setAccessible(true);  //忽略权限

        User user2 = con.newInstance("sample",345);

        System.out.println(user2);

    }





}



class User{

    private String name;

    private int pwd;



    //公共的

    public User() {

    }



    public User(String name) {

        this.name = name;

    }

    //私有的

    private User(String name, int pwd) {

        this.name = name;

        this.pwd = pwd;

    }



    public String getName() {

        return name;

    }



    public void setName(String name) {

        this.name = name;

    }



    public int getPwd() {

        return pwd;

    }



    public void setPwd(int pwd) {

        this.pwd = pwd;

    }



    @Override

    public String toString() {

        return "User{" +

                "name='" + name + '\'' +

                ", pwd=" + pwd +

                '}';

    }

}



3)、反射操作属性和方法

反射操作属性:

getField(String name) 

返回 字段对象,该对象反映此类对象表示的类或接口的指定公共成员字段。

 [] getFields()

返回一个包含 字段对象的数组,字段对象反映此 类对象所表示的类或接口的所有可访问公共字段。

getDeclaredField(String name)

返回字段对象,该对象反映此 类对象表示的类或接口的指定声明字段。

 [] getDeclaredFields()

返回 字段对象的数组,字段对象反映由此类对象表示的类或接口声明的所有字段。

void set(Object obj, Object value) 

将指定对象参数上此 字段对象表示的字段设置为指定的新值。

Object get(Object obj)

返回指定对象上此 字段表示的字段的值。

反射操作方法:

getMethod(String name, 类<?>... parameterTypes) 

返回方法对象,该对象反映此类对象表示的类或接口的指定公共成员方法。

getMethods()

返回一个包含 方法对象的数组,方法对象反映此类对象所表示的类或接口的所有公共方法,包括由类或接口声明的那些以及从超类和超接口继承的那些。

getDeclaredMethod(String name,类<?>... parameterTypes)

返回方法对象,该对象反映此类对象表示的类或接口的指定声明方法。

getDeclaredMethods() 

返回一个包含方法对象的数组,方法对象反映此类对象表示的类或接口的所有已声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承的方法。

Object invoke(Object obj, Object... args)

在具有指定参数的指定对象上调用此 方法对象表示的基础方法。

import java.lang.reflect.Field;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

public class Class004_Reflect {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        User user = new User("zhangsan");



        //User类的Class对象

        Class<User> cls = User.class;



        testMethod(cls,user);



    }



    //测试方法

    public static void testMethod(Class<User> cls,User user) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        Method[] methods = cls.getMethods();

        for(Method m:methods){

            System.out.println(m);

        }



        //私有方法

        Method method = cls.getDeclaredMethod("haha",int.class);



        //调用方法

        method.setAccessible(true);

        System.out.println(method.invoke(user,100));;

        System.out.println(method.invoke(null,100));;



        Method m = cls.getMethod("getName");

        System.out.println(m.invoke(user));

    }



    //测试属性

    public static void testField(Class<User> cls,User user) throws NoSuchFieldException, IllegalAccessException {

        Field field = cls.getDeclaredField("name");



        System.out.println(field.getName());

        System.out.println(field.getType());



        //忽略权限

        field.setAccessible(true);



        field.set(user,"zhangsanfeng");



        System.out.println(field.get(user));

    }



}






 

4)、反射操作数组

static Object newInstance(类<?> componentType, int length) 

创建具有指定组件类型和长度的新数组。

static Object get(Object array, int index) 

返回指定数组对象中索引组件的值。

static void set(Object array, int index, Object value) 

将指定数组对象的索引组件的值设置为指定的新值。

import java.lang.reflect.Array;

import java.lang.reflect.Modifier;

import java.util.Arrays;

public class Class005_Reflect {

    public static void main(String[] args) throws Exception {

        testArray();



        test(String.class);



    }

    public static void test(Class<String> cls){

        //int getModifiers() 返回此类或接口的Java语言修饰符,以整数编码。

        System.out.println(cls.getModifiers());

        System.out.println(Modifier.toString(cls.getModifiers()));



        //类<?>[] getInterfaces() 返回由此对象表示的类或接口直接实现的接口。

        System.out.println(Arrays.toString(cls.getInterfaces()));



        //String getName() 返回此 类对象表示的实体名称(类,接口,数组类,基本类型或void),作为 String 。

        System.out.println(cls.getName());



        //String getSimpleName() 返回源代码中给出的基础类的简单名称。

        System.out.println(cls.getSimpleName());

    }



    //简单操作数组

    public static void testArray(){

        int[] arr = (int[]) Array.newInstance(int.class,5);



        Array.set(arr,2,200);



        System.out.println(Arrays.toString(arr));



        System.out.println(Array.get(arr,2));

    }

}

5)、注解的概念

注解:Annotation 标注,Java8引入

作用:

  • 注释
  • 标志|标识
  • 使用注解时可以传递参数,可以在程序中通过反射操作注解,获取配置的信息在程序中使用
  • 可以存在于Class文件中
  • 大量的代替|简化配置文件的使用

使用:

@注解名(参数)

注解的分类:

   JDK内置注解(常见):

      @Override 检查重写方法

      @SuppressWarnings("all")抑制警告

      @Deprecated 表示已过时,不推荐使用

      @FunctionalInterface 标识函数式接口

   参数的个数分类:

      标志|标识注解

      单值注解

      完整注解

      元注解:给注解进行注解

      自定义注解

6)、元注解

  • @Target 用于描述注解的使用范围
  • @Retention 规定注解类型的声明周期
  • @Documented 保留在API文档中
  • @Inherited 标识注解类型可以被继承

7)、自定义注解

  • @interface定义注解类型
  • 默认实现java.lang.annotation.Annotation接口
  • 自定义的注解类型不能显示的继承其他父类,实现其他接口
  • 如果注解类中的属性只有一个,建议名字为value,为value属性赋值可以直接赋值
  • 为注解类型定义属性|字段:数据类型 数据名();
  • 属性的数据类型要求:基本数据类型、String、枚举、注解类型以及以上类型的数组
  • 属性可以通过default提供默认值
import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

public class Class003_MyAnnotation {

    @MyAnnotation(value=111,haha=123,hehe=321)

    int apple;

}





@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

@interface MyAnnotation{

    int value() default 1;

    int haha();

    int hehe();

}

8)、注解解析器

定义:通过反射操作注解

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.reflect.Field;

import java.util.Arrays;



/*

    案例: 自定义水果清单 FruitList

        int apple;

        int pair;



        为每种水果提供一个默认的进货数量,通过注解进行配置



        注解类型: FruitNum  属性: int value();



    注意:

        如果通过反射操作注解,注解类型的生命周期应该定义为运行期



 */

public class Class004_FruitList {

    public static void main(String[] args) throws Exception {

        FruitList list = new FruitList();

        list.apple=200;

        System.out.println(list);



        testFruitList(list,FruitList.class);



        System.out.println(list);

    }



    //注解解析器

    public static FruitList testFruitList(FruitList list,Class<FruitList> cls) throws  Exception {

        //1.获取所有属性

        Field[] arr = cls.getDeclaredFields();



        //2.判断当前对象的每一个属性值

        for(Field field:arr){

            Object value =  field.get(list);



            //是否==null,如果不等于 略过  如果==null 1)获取当前成员变量上的注解对象,  2)获取到实现   3)赋值

            if(value==null){

                //判断当前属性上是否存在FruitNum注解修饰

                if(field.isAnnotationPresent(FruitNum.class)){

                    //获取当前属性上的FruitNum注解实例

                    FruitNum fruitNum = field.getAnnotation(FruitNum.class);

                    System.out.println(fruitNum.value());



                    //为当前属性赋值,值为成员上的注解上配置的实参

                    field.set(list,fruitNum.value());

                }

            }

        }



        return list;

    }

}



class FruitList{

    @FruitNum(50)

    Integer apple;

    @FruitNum

    Integer pair;



    @Override

    public String toString() {

        return "FruitList{" +

                "apple=" + apple +

                ", pair=" + pair +

                '}';

    }

}



//水果数量

@Retention(RetentionPolicy.RUNTIME)

@interface FruitNum{

    int value() default 20;

}

9)、函数式接口

定义:接口中只与一个必须被重写的抽象方法

@FunctionalInterface

四大内置函数式接口:

  • 消费性接口: Consumer<T>

void accept(T t)   --> 有来无回,有参数没有返回值

  • 供给型接口: Supplier<T>

T get()

  • 函数型接口: Function<T,R>

R apply(T t)

  • 段言型接口: Predicate<T>

boolean test(T t)

import java.util.ArrayList;

import java.util.List;

import java.util.function.Consumer;

import java.util.function.Function;

import java.util.function.Predicate;

import java.util.function.Supplier;

public class Class001_FunctionalInterface {

    public static void main(String[] args) {

        testConsumer(5000, m-> System.out.println(m));

        testConsumer(10000, m-> System.out.println(m));



        System.out.println(getNum(5,()->(int)(Math.random()*(5-1+1)+1)));;

        System.out.println(getNum(3,()->(int)(Math.random()*(15-10+1)+10)));;



        System.out.println(strHandler("   haha  ",s->s.trim()));;

        System.out.println(strHandler("   haha  ",s->s.toUpperCase()));;



        List<Employee> list = new ArrayList<Employee>();



        list.add(new Employee(1003,"zhangsan",19));

        list.add(new Employee(1002,"lisi",17));

        list.add(new Employee(1001,"wangwu",18));



        System.out.println(checkEmp(list,e->e.getAge()>=18));

    }



    //对员工集合中的员工数据按照某种规则进行过滤,返回结果

    public static List<Employee> checkEmp(List<Employee> list, Predicate<Employee> predicate){

        List<Employee> newList = new ArrayList<>();

        for(Employee e:list){

            if(predicate.test(e)){

                newList.add(e);

            }

        }

        return newList;

    }



    //对字符串进行处理,返回结果

    public static String strHandler(String str, Function<String,String> my){

        return my.apply(str);

    }



    //产生指定个数的指定规则的随机数

    public static List<Integer> getNum(int num, Supplier<Integer> supplier){

        List<Integer> list = new ArrayList<>();

        for(int i=1;i<=num;i++){

            list.add(supplier.get());

        }

        return list;

    }



    //消费的功能

    public static void testConsumer(int money, Consumer<Integer> con){

        con.accept(money);

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值