反射与注解

反射 : 动态机制

定义:唯一的一个动态机制
Java反射机制,可以实现以下功能:

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

发生在程序运行期间

反射的源头  : Class类型的对象

代码:

public class Class001_Reflect {
public static void main(String[] args) throws Exception {
    Properties pro = new Properties();
    pro.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("classname.properties"));
    Person p = (Person) Class.forName(pro.getProperty("classname")).newInstance();
    p.sleep();
}
}
class Person{
    public void sleep(){
        System.out.println("闭着眼睛休息");
    }
}
class Student extends Person{
    public void sleep(){
        System.out.println("一边上课一边睡觉");
    }
}
class Teacher extends Person{
    public void sleep(){
        System.out.println("一边敲代码一边睡觉");
    }
}

反射的源头 : Class : 类类实例表示正在运行的Java应用程序中的类和接口。

Class对象 : 当类加载到内存中,就会存在这个表示这个类型的Class对象,唯一的,不变的,独一份的

获取反射源头的方式:

    1.类名.class
    2.Class.forName("权限定名") -->推荐
    3.对象.getClass()

代码:

   public class Class002_Reflect {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<String> cls1 = String.class;
        System.out.println(cls1.toString());

    Class cls2 = Class.forName("java.lang.String");
    System.out.println(cls1==cls2);

    Class cls3 = "".getClass();
    System.out.println(cls1==cls3);

    //基本数据类型的Class对象
    Class cls = int.class;
    System.out.println(cls);

    System.out.println(cls==Integer.TYPE);  //T
    System.out.println(Integer.class);

    //类<?>[] getInterfaces() 返回由此对象表示的类或接口直接实现的接口。
    Class[] arr=  cls1.getInterfaces();
    System.out.println(Arrays.toString(arr));

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

    //int getModifiers() 返回此类或接口的Java语言修饰符,以整数编码。
    System.out.println(cls1.getModifiers());
    System.out.println(Modifier.toString(cls1.getModifiers()));

    System.out.println(cls1.getName());
    System.out.println(cls1.getSimpleName());
}
}

通过反射创建对象

1.Class ->newInstance() 默认调用空构造为对象初始化信息–>不推荐使用
2.Constructor->newInstance() 创建对象

1.获取某一个类中构造器
    构造器<T> getConstructor(类<?>... parameterTypes) 返回一个 构造器对象,该对象反映此 类对象所表示的类的指定公共构造函数。
    构造器<?>[] getConstructors() 返回一个包含 构造器对象的数组, 构造器对象反映了此 类对象所表示的类的所有公共构造函数。
    构造器<T> getDeclaredConstructor(类<?>... parameterTypes) 返回一个 构造器对象,该对象反映此 类对象所表示的类或接口的指定构造函数。
    构造器<?>[] getDeclaredConstructors() 返回 构造器对象的数组, 构造器对象反映由此 类对象表示的类声明的所有构造函数。

2.调用Constructor类提供的newInstance方法,创建对象的时候调用当前构造器初始化信息

代码:

  public class Class003_Constructor {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    //1.创建对象
    System.out.println(Employee.class.newInstance());
    //获取构造器
    Constructor[] cons=Employee.class.getConstructors();
    System.out.println(Arrays.toString(cons));
    System.out.println("----------------------");
    Constructor<Employee>con=  Employee.class.getDeclaredConstructor(int.class,String.class);
    System.out.println(con);

    //2.创建 对象
    //私有的构造器先忽略权限再次使用
    con.setAccessible(true);
    Employee emp=  con.newInstance(1001,"刘亦菲");
    System.out.println(emp);
}
}

通过反射操作成员

操作方法
1.获取方法
       方法 getMethod(String name, 类<?>... parameterTypes) 返回 方法对象,该对象反映此 类对象表示的类或接口的指定公共成员方法。
       方法[] getMethods() 返回一个包含 方法对象的数组, 方法对象反映此 类对象所表示的类或接口的所有公共方法,包括由类或接口声明的那些以及从超类和超接口继承的那些。
       方法 getDeclaredMethod(String name, 类<?>... parameterTypes) 返回 方法对象,该对象反映此 类对象表示的类或接口的指定声明方法。
       方法[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映此 类对象表示的类或接口的所有已声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承的方法。

2.调用方法
       Object invoke(Object obj, Object... args) 在具有指定参数的指定对象上调用此 方法对象表示的基础方法。
操作属性
1.获取属性
       字段 getField(String name) 返回 字段对象,该对象反映此 类对象表示的类或接口的指定公共成员字段。
       字段[] getFields() 返回一个包含 字段对象的数组, 字段对象反映此 类对象所表示的类或接口的所有可访问公共字段。
       字段 getDeclaredField(String name) 返回 字段对象,该对象反映此 类对象表示的类或接口的指定声明字段。
       字段[] getDeclaredFields() 返回 字段对象的数组, 字段对象反映由此 类对象表示的类或接口声明的所有字段。

2.获取属性值
       Object get(Object obj) 返回指定对象上此 字段表示的字段的值。
3.设置属性值
       void set(Object obj, Object value) 将指定对象参数上此 字段对象表示的字段设置为指定的新值。

代码:

//通过反射操作成员
public class Class004_Member {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Employee emp=new Employee();
        testMethod(Employee.class,emp);
        testField(Employee.class,emp);
    }
    // 操作方法
    public  static void testMethod(Class<Employee> cls, Employee emp) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //获取所有公共的方法
       Method[] arr= cls.getMethods();
       Arrays.stream(arr).forEach(System.out::println);
       //获取指定的方法
       Method method= cls.getDeclaredMethod("testPrivate");
        System.out.println(method);

        method.setAccessible(true);
        //调用方法
        System.out.println(method.invoke(emp));
        //静态方法 存在返回值  可以跟随对象调用|可以跟随类名调用
        for (Method m:arr){
            if ("testStatic".equals(m.getName())){
                System.out.println(m.invoke(null,1000));
            }
        }

}
//操作属性
public  static void testField(Class<Employee> cls,Employee emp) throws NoSuchFieldException, IllegalAccessException {
    //获取所有公共的
  Field[] fields= cls.getFields();
    System.out.println(Arrays.toString(fields));
    //根据属性名获取指定的属性
   Field field= cls.getDeclaredField("name");
    System.out.println(field);
    //忽略权限
    field.setAccessible(true);
    field.set(emp,"刘亦菲");
    System.out.println(field.get(emp));

}
}

Properties

定义:Properties类表示一组持久的属性。 Properties可以保存到流中或从流中加载。 属性列表中的每个键及其对应的值都是一个字符串。
Properties常用做配置文件使用

定义使用步骤:

1.src下新建文件 xx.properties
2.创建Properties类型的对象
3.调用load(InputStream|Reader)
4.根据key获取value  getProperty(key)

代码:

public class Class001_Properties {
public static void main(String[] args) throws IOException {
    Properties pro = new Properties();
    //从流中加载数据
    pro.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));

    System.out.println(pro.getProperty("username"));
    System.out.println(pro.getProperty("password"));
}
}

注解:标注

dk1.5新增
作用:

1.具有解释说明的作用
2.强制检查,检测的作用
3.注解可以存在Class文件中
4.定义注解的时候同时传递数据,程序运行期间可以通过反射获取数据使用
5.大量代替了配置文件

使用:

@注解名(参数)

位置:

任意位置

分类

参数个数分

1.标记注解:0个
2.单值注解:1个
3.完整注解:多个

jdk内置注解

简单的内置注解:
    @Override:强制检测是否为重写方法
    @FunctionalInterface : 强制检测是否为函数式接口
    @Deprecated:标记已过时
    @SuppressWarnings:抑制警告
元注解 : 注解的注解
    @Target用于描述注解的使用范围
    @Retention表示需要在什么级别保存该注释信息,用于描述注解的生命周期
    @Documented表示使用该注解的元素应被javadoc或类似工具文档化
    @Inherited 表示一个注解类型会被自动继承

自定义注解

   1.通过@interface定义注解类型
   2.自定义的注解默认隐式的实现java.lang.annotation.Annotation接口
   3.并不能显示实现 其他接口,继承其他父类
   4.注解类中可以自定义定义属性|字段
   5.注解类属性的定义 : 数据类型 属性名();
   6.字段|属性类型只能为 : 基本数据类型 String enum annotation 或者以上类型的数组
   7.注解类型 中字段|属性只有一个,名字建议定义value,赋值的时候可以省略value=
   8.字段可以定义默认值 通过default关键字
注意: 如果通过反射操作注解,需要声明周期为@Retention(RetentionPolicy.RUNTIME)

注意 : 面向对象设计原则之一: 开闭原则
代码:

  public class Class003_FruitList {
public static void main(String[] args) throws IllegalAccessException {
    FruitList list=new FruitList();
    list.pair=0;
    System.out.println(list);
    System.out.println(testFruitList(list,FruitList.class));
}
//注解解析器
static  FruitList testFruitList(FruitList fruitList,Class<FruitList> cls) throws IllegalAccessException {
    //获取FruitList类所有属性
    Field[] arr= cls.getDeclaredFields();
    //遍历,拿到每一个属性判断,是否已经为属性赋值,已赋值略过,
    for (Field field:arr){
        //没有赋值,判断会是否属性存在默认值,如果不存在略过,存在获取默认值为当属性赋值
      if (field.get(fruitList)==null){
          System.out.println("------------");
          if (field.isAnnotationPresent(Num.class)){
              Num num=  field.getAnnotation(Num.class);
              field.set(fruitList,num.value());
          }
      }
  }
    return fruitList;
}
}

class FruitList{
    @Num(20)
    Integer apple;
    @Num(15)
    Integer pair;
    @Num(4)
    Integer banana;
    Integer strawberry;

public FruitList() {
}

public FruitList(Integer apple, Integer pair, Integer banana, Integer strawberry) {
    this.apple = apple;
    this.pair = pair;
    this.banana = banana;
    this.strawberry = strawberry;
}

@Override
public String toString() {
    return "FruitList{" +
            "apple=" + apple +
            ", pair=" + pair +
            ", banana=" + banana +
            ", strawberry=" + strawberry +
            '}';
}
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface  Num{
    int value() default 1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值