JavaSE基础入门_018_反射

反射

什么是类对象

  • 类的对象:基于某个类 new 出来的对象,也称为实例对象。

  • 类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)

 

获取类对象

  • 1、通过类的对象,获取类对象

    • Student s = new Student();
      Class c = s.getClass();
  • 2、通过类名获取类对象

    • Class c = 类名.class;
  • 3、通过静态方法获取类对象【推荐使用】

    • Class c = Class.forName("包名.类名");

 

常用方法

  • public String getName();//获取类对象所代表的类名

    public Package getPackage();//当前类对象所在的包

    public Class<? super T> getSuperclass();//获取当前类的父类

    public Class<?>[] getInterfaces();//获取当前类所实现的所有接口

    public Constructor<?>[] getConstructors();//获取当前类的所有公共构造类对象

    public T newInstance();//使用当前类对象来创建一个实例

    public Method[] getMethods();//获取类的方法

    public Field[] getFields();//获取 自身+父类 的公开属性

 

  • // 1,使用反射获取类的名字、包名、父类、接口
    public static void reflectOpe1() throws Exception{
    Class<?> class1 = Class.forName("getClassName.Person");
    System.out.println(class1.getName());
    System.out.println(class1.getPackageName());
    System.out.println(class1.getSuperclass().toString());
    System.out.println(class1.getInterfaces().toString());
    }

    // 2,使用反射获取类的构造方法,创建对象
    public static void reflectOpe2() throws Exception{

    // 2.1:获取类对象
    Class<?> class2 = Class.forName("getClassName.Person");

    // 2.2:获取类的构造方法
    // Constructor<?>[] cons = class2.getConstructors();
    // for (Constructor<?> con : cons) {
    // System.err.println(con.toString());
    // }

    // 2.3: 获取类中无参构造
    Constructor<?> con = class2.getConstructor();// 不给参数就是获取无参构造
    Person zhangsan = (Person)con.newInstance();// 利用构造方法新建一个实例对象,这里就是一个 Person 类型
    System.out.println(zhangsan.toString());
    //简便无参构造方法,创建实例对象;类对象.newInstance()
    Person wang5 = (Person)class2.newInstance();
    System.out.println(wang5.toString());

    // 2.4: 获取类中的带参构造方法
    Constructor<?> con2 = class2.getConstructor(String.class,int.class);
    Person xiaoli = (Person)con2.newInstance("小李",20);
    System.out.println(xiaoli.toString());
    }

    // 3,使用反射获取类中的方法,并调用方法
    public static void reflectOpe3() throws Exception {
    // 3.1,获得类对象
    Class<?> class1 = Class.forName("getClassName.Person");

    // 3.2,获取类方法
    // 3.2.1, 类对象.getMethods() 只能获取公开的方法,包括从父类继承的方法
    // Method[] methods = class1.getMethods();
    // 3.2.2, 类对象.getDeclaredMethods() 获取类自身中所有方法,包括私有,默认,保护;不包含继承的
    // Method[] methods = class1.getDeclaredMethods();
    // for (Method method : methods) {
    // System.out.println(method);
    // }

    // 3.3, 获取单个方法

    // 3.3.1 获取 eat()
    Method eatmethod = class1.getMethod("eat");
    // 调用方法
    // 正常一般的调用:对象.方法()
    //eatmethod.invoke(obj, args)
    Person zhang3=(Person)class1.newInstance();
    // eatmethod.invoke(zhang3);// 相当于:zhang3.eat()
    // System.out.println("----------------------------");

    // 3.3.2 获取toString()
    // Method toStringMethod = class1.getMethod("toString");
    // System.out.println(toStringMethod.invoke(zhang3));
    // System.out.println("----------------------------");

    // 3.3.3 获取eat(String food), 带参数的方法
    // Method eat2 = class1.getMethod("eat", String.class);
    // eat2.invoke(zhang3, "鸡腿");

    // 3.3.4 获取私有方法
    Method privatemethod = class1.getDeclaredMethod("privateMehod");

    // private方法被反射调用时,需要设置其访问权限无效
    privatemethod.setAccessible(true);//压制访问检查
    privatemethod.invoke(zhang3);

    // 3.3.5获取静态方法
    Method staticMethod = class1.getMethod("staticMethod");
    staticMethod.invoke(null);
    }

    // 4,使用反射实现一个可以调用任何对象方法的通用方法
    // 参数:对象,方法名,方法参数类型数组,参数
    public static Object invokeAny(Object obj,String methodName,Class<?>[] types,Object...args) throws Exception{
    // 4.1.获取类对象
    Class<?> class1 = obj.getClass();

    // 4.2.获取方法
    Method method = class1.getMethod(methodName, types);

    // 4.3.调用
    return method.invoke(obj, args);
    }

    // 5,使用反射获取类中的属性
    public static void reflectOpe4() throws Exception {
    // 5.1.获取类对象
    Class<?> class1 = Class.forName("getClassName.Person");

    // 5.2.获取属性
    // Field[] fields = class1.getFields();//只能拿 public 字段
    // Field[] fields = class1.getDeclaredFields();// 除了继承的,他自己声明的所有都可以获取
    // System.out.println(fields.length);
    // for (Field field : fields) {
    // System.out.println(field);
    // }

    // 5.3.获取name属性

    Field field = class1.getDeclaredField("name");
    // 私有属性,需要设置绕过java检查,修改访问权限
    field.setAccessible(true);
    System.out.println(field);

    // 5.4.给获取到的属性 赋值
    Person zhangsan = (Person) class1.newInstance();

    field.set(zhangsan , "z3");// zhangsan.name = "z3";
    // 5.5. 获取属性值
    Object result = field.get(zhangsan);//zhangsan.name
    System.out.println(result);

    }
  • 注意:反射是一种 Java 的底层技术,可以突破封装。使用起来比较危险。

  • 使用反射:解决通用编程的问题,需要使用反射。

 

设计模式介绍

  • 什么是设计模式

    • 一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。简单理解:特定问题的固定解决方法。

  • 好处:

    • 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、重用性。

  • 在GOF的《设计模式》书中描述了23种设计模式

 

 

工厂设计模式

  • 工厂模式主要负责对象创建的问题。

  • 开发中有一个非常重要的原则 “开闭原则”,对拓展开放、对修改关闭。

  • 可通过反射进行工厂模式的设计,完成动态的对象创建。

 

单例设计模式

  • 单例(Singleton):只允许创建一个该类的对象。

  • 方式1:饿汉式(类加载时创建,天生线程安全)

    • class Singleton{
         // 1. 用 Singleton 类,创建一个静态常量
         private static final Singleton instance = new Singleton();
         // 2. 修饰构造方法为私有
         private Singleton(){}
         // 3. 返回创建的常量
         public static Singleton getInstance(){
             return instance;
        }
      }
  • 方式2:懒汉式(使用时创建,线程不安全,加同步)

    • 迫切创建唯一对象

    • class Singleton{
         // 1. 用 Singleton 类,创建一个静态常量
         private static Singleton instance = null;
         // 2. 修饰构造方法为私有
         private Singleton(){}
         // 3. 返回创建的常量
         public static Synchronized Singleton getInstance(){
             if(instance == null){
                 instance = new Singleton();
            }
             return instance;
        }
      }
  • 方式3:线程安全的懒汉式(使用时创建,线程安全)

    • class Singleton{
         
         private Singleton(){}
         
         private static class Holder{
             static Singleton s = new Singleton();
        }

         public static Synchronized Singleton getInstance(){
             return Holder.s;
        }
      }

 

枚举

  • 什么是枚举

    • 枚举是一个引用类型,枚举是一个规定了取值范围的数据类型。

  • 枚举变量不能使用其他的数据,只能使用枚举中常量赋值,提高程序安全性。

  • 定义枚举使用: enum 关键字

  • 枚举的本质:

    • 枚举是一个终止类,并继承Enum抽象类。

    • 枚举中常量是当前类型的静态常量。

 

注解

  • 什么是注解

    • 注解(Annotation)是代码里的特殊标记,程序可以读取注解,一般用于替代配置文件。

 

  • 开发人员可以通过注解告诉类如何运行。

    • 在 Java 技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。

 

  • 常见注解:@Override

 

  • 定义注解使用 @interface 关键字,注解中只能包含属性

 

  • 注解属性类型

    • String 类型

    • 基本数据类型

    • Class 类型

    • 枚举类型

    • 注解类型

    • 以上类型的一维数组

 

  • 注解的本质:接口;它的属性实质是:抽象方法。

 

  • 元注解:用来描述注解的注解。

    • @Retention:用于指定注解可以保留的域

      • RetentionPolicy.CLASS:注解记录在 class 文件中,运行 Java 程序时,JVM不会保留。这是默认值
      • RetentionPolicy.RUNTIME:注解记录在 class 文件中,运行 JAVA 程序时,JVM会保留注解,程序可以通过反射获取该注释
      • RetentionPolicy.SOURCE:编译时直接丢弃这种策略的注释
      • // 代码使用演示:
        @Retention(value = RetentionPolicy.RUNTIME)
        public @interface PersonInfo {
        String name();
        int age();
        String sex();
        }
    • @Target:指定注解用于修饰类的哪个成员。

      • @Target(value = { ElementType.METHOD })//注解的使用范围
        //这个注解:指定此注解只能 打在 方法上面

 

总结

  • 类对象:

    • Class对象,封装了一个类的所有信息;程序运行中,可通过Class对象获取类的信息。

  • 获取类对象的三种方式:【推荐第三种,依赖方式最低】

    • Class s = 对象.getClass();
      Class s = 类名.class;
      Class s = Class.forName("包名.类名");
  • 工厂模式:

    • 主要用于创建对象,通过反射进行工厂模式的设计,完成动态对象创建。

  • 单例模式:

    • Singleton,只允许创建一个该类的对象。

  • 枚举类型

  • 注解类型

原文地址:https://www.cnblogs.com/77-is-here/p/13163756.html