Loading

17、反射

1、什么是类对象

类的对象:

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

类对象:

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

2、获取类对象

通过类的对象,获取类对象

  Student s = new Student();

  Class c = s.getClass();

通过类名获取类对象

  Class c = 类名.class;

通过静态方法获取类对象

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

3、常用方法

3.1、获取该类的名称

public String getName()

3.2、获取该类的存放路径

public Package getPackage()

3.3、获取父类名称

public Class<? super T> getSuperclass()

3.4、获取该类实现的所有接口

public Class<?>[] getlnterfaces()

3.5、获取所有权限为 public 的成员变量

public Field[] getFields()

3.6、获取所有权限为 public 的方法

public Method[] getMethods()

3.7、获取所有权限为 public 的构造方法

public Constructor<?>[] getConstructors()

3.8、用来创建新的对象

public T newlnstance()

/**
 * Person类
 */
public class Person implements Serializable,Cloneable{
    //姓名
    private String name;
    //年龄
    private int age;
    // 性别
    public int sex;
    
    public Person() {
        System.out.println("无参构造执行了...");
    }
    
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
        System.out.println("带参构造方法执行了...");
    }


    //
    public void eat() {
        System.out.println(name+"正在吃东西......");
    }


    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }

    //带参的方法
    public void eat(String food) {
        System.out.println(name+"开始吃...."+food);
    }
    
    //私有的方法
    private void privateMethod() {
        System.out.println("这是一个私有方法");
    }
    
    //静态方法
    public static void staticMethod() {
        System.out.println("这是一个静态方法");
    }
}
View Code

 

//-verbose:class 显示类的加载过程
public class TestPerson {
    public static void main(String[] args) throws Exception {
//        Person zhangsan=new Person();
//        zhangsan.name="张三";
//        zhangsan.eat();

        //getClazz();
        reflectOpe1();
        //reflectOpe2();
        //reflectOpe3();
        
//        Properties properties=new Properties();
//        properties.setProperty("name","zhangsan");
//        System.out.println(properties.toString());
//        invokeAny(properties, "setProperty", new Class[] {String.class, String.class}, "username","张三");
//        System.out.println(properties.toString());
        
//        reflectOpe4();
    }

    //获取类对象的三种方式
    public static void getClazz() throws Exception {
        //1使用对象获取类对象
        Person zhangsan=new Person();
        Class<?> class1=zhangsan.getClass();
        System.out.println(class1.hashCode());

        //2使用类名.class属性
        Class<?> class2=Person.class;
        System.out.println(class2.hashCode());

        //3使用Class的静态方法[推荐使用]
        Class<?> class3=Class.forName("com.qf.chap17_1.Person");
        System.out.println(class3.hashCode());
    }
    
    //1 使用反射获取类的名字、包名、父类、接口
    public static void reflectOpe1() throws Exception {
        //(1)获取类对象 Person
        Class<?> class1=Class.forName("com.qf.chap17_1.Person");

        //getName();
        // com.qf.chap17_1.Person
        System.out.println(class1.getName());

        //getPackage();
        // com.qf.chap17_1
        System.out.println(class1.getPackage().getName());

        //getSuperClass();
        // java.lang.Object
        System.out.println(class1.getSuperclass().getName());

        //getInterfaces();
        // [interface java.io.Serializable, interface java.lang.Cloneable]
        Class<?>[] classes=class1.getInterfaces();
        System.out.println(Arrays.toString(classes));

        // getFields
        Field[] fields = class1.getFields();
        System.out.println("getFields==="+Arrays.toString(fields));

        // getMethods
        Method[] methods = class1.getMethods();
        System.out.println("methods==="+Arrays.toString(methods));

        // Person
        System.out.println(class1.getSimpleName());
        // com.qf.chap17_1.Person
        System.out.println(class1.getTypeName());
    }
    
    //2使用反射获取类的构造方法,创建对象
    public static void reflectOpe2() throws Exception{
        //(1)获取类的类对象
        Class<?> class1=Class.forName("com.qf.chap17_1.Person");

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

        //(3)获取类中无参构造
        Constructor<?> con=class1.getConstructor();
        Person zhangsan=(Person)con.newInstance();
        Person lisi=(Person)con.newInstance();
        System.out.println(zhangsan.toString());
        System.out.println(lisi.toString());

        //简便方法:类对象.newInstance();
        Person wangwu=(Person)class1.newInstance();
        System.out.println(wangwu.toString());

        //(4)获取类中带参构造方法
        Constructor<?> con2=class1.getConstructor(String.class,int.class);
        Person xiaoli=(Person)con2.newInstance("晓丽",20);
        System.out.println(xiaoli.toString());
        
    }
    
    //3使用反射获取类中的方法,并调用方法
    public static void reflectOpe3() throws Exception{
        //(1)获取类对象
        Class<?> class1=Class.forName("com.qf.chap17_1.Person");

        //(2)获取方法  Method对象
        //2.1getMethods() 获取公开的方法,包括从父类继承的方法
        //Method[] methods=class1.getMethods();

        //2.2getDeclaredMethods() 获取类中的所有方法,包括私有、默认、保护的 、不包含继承的方法
//        Method[] methods=class1.getDeclaredMethods();
//        for (Method method : methods) {
//            System.out.println(method.toString());
//        }

        //(3)获取单个方法
        //3.1eat
        Method eatMethod=class1.getMethod("eat");
        //调用方法
        //正常调用方法  Person zhangsan=new Person();  zhangsan.eat();
        Person zhangsan=(Person)class1.newInstance();
        eatMethod.invoke(zhangsan);//zhangsan.eat();
        System.out.println("------------------");

        //3.2toString
        Method toStringMethod=class1.getMethod("toString");
        Object result=toStringMethod.invoke(zhangsan);
        System.out.println(result);
        System.out.println("-------------------");

        //3.3带参的eat 
        Method eatMethod2=class1.getMethod("eat", String.class);
        eatMethod2.invoke(zhangsan, "鸡腿");
        
        //3.4获取私有方法
        Method privateMethod=class1.getDeclaredMethod("privateMethod");

        //设置访问权限无效
        privateMethod.setAccessible(true);
        privateMethod.invoke(zhangsan);
        
        //3.4获取静态方法
        Method staticMethod=class1.getMethod("staticMethod");

        //正常调用 Person.staticMethod
        staticMethod.invoke(null);
    }
    
    //4使用反射实现一个可以调用任何对象方法的通用方法
    public static Object invokeAny(Object obj,String methodName,Class<?>[] types,Object...args) throws Exception {
        //1获取类对象
        Class<?> class1=obj.getClass();
        //2获取方法
        Method method=class1.getMethod(methodName, types);
        //3调用
        return method.invoke(obj, args);
    }
    
    //5使用反射获取类中的属性
    public static void reflectOpe4() throws Exception{
        //(1)获取类对象
        Class<?> class1=Class.forName("com.qf.chap17_1.Person");

        //(2)获取属性(字段) 公开的字段,父类继承的字段
        //Field[] fields=class1.getFields();

        //getDeclaredFields()获取所有的属性,包括私有,默认 ,包含,
        // Field[] fields=class1.getDeclaredFields();

//        System.out.println(fields.length);
//        for (Field field : fields) {
//            System.out.println(field.toString());
//        }

        //(3)获取name属性
        Field namefield=class1.getDeclaredField("name");
        namefield.setAccessible(true);

        //(4)赋值  获取值 正常调用  Person zhangsan=new Person(); zhangsan.name="张三";
        Person zhangsan=(Person)class1.newInstance();
        namefield.set(zhangsan, "张三"); //zhangsan.name="张三";
        //(5) 获取值
        System.out.println(namefield.get(zhangsan));// zhangsan.name
    }
}

3、设计模式

什么是设计模式:

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

好处:

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

4、工厂设计模式

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

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

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

1、父类产品

/**
 * 父类产品
 *
 */
public interface Usb {
    void service();
}

2、风扇

/**
 * 风扇
 */
public class Fan implements Usb{
    @Override
    public void service() {
        System.out.println("风扇开始工作了...");
    }
}

3、键盘

/**
 * 键盘
 */
public class KeyBoard implements Usb{
    @Override
    public void service() {
        System.out.println("键盘开始工作了...");
    }
}

4、鼠标

/**
 * 鼠标
 */
public class Mouse implements Usb{
    @Override
    public void service() {
        System.out.println("鼠标开始工作了.....");
    }
}

5、U盘

/**
 * U盘
 */
public class Upan implements Usb{
    @Override
    public void service() {
        System.out.println("U盘开始工作了...");
    }
}

6、工厂类

/**
 * 工厂类
 */
public class UsbFactory {
    public static Usb createUsb(String type) {//类型的全名称 com.qf.
        Usb usb=null;
        Class<?> class1=null;
        try {
            class1 = Class.forName(type);
            usb=(Usb)class1.newInstance();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return usb;
    }
}

7、客户程序

/**
 * 客户程序
 */
public class Demo {
    public static void main(String[] args) throws Exception{
        System.out.println("=========请选择 1 鼠标  2风扇 3 u盘===========");
        Scanner input=new Scanner(System.in);
        String choice=input.next();
        //1 = com.qf.chap17_2.Mouse
        //2 = com.qf.chap17_2.Fan
        //3 = com.qf.chap17_2.Upan
        //4 = com.qf.chap17_2.KeyBoard
        Properties properties=new Properties();
        FileInputStream fis=new FileInputStream("src\\usb.properties");
        properties.load(fis);
        fis.close();
        
        Usb usb=UsbFactory.createUsb(properties.getProperty(choice));
        if(usb!=null) {
            System.out.println("购买成功");
            usb.service();
        }else {
            System.out.println("购买失败,您要购买的产品不存在");
        }
    }
}

5、单例模式

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

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

/**
 * 饿汉式单例
 * (1)首先创建一个常量
 * (2)构造方法改成私有的,类外部不能创建对象
 * (3)通过一个公开的方法,返回这个对象
 * 
 * 优点:线程安全,缺点:声明周期太长,浪费空间
 *
 */
public class SingleTon {
    private static final SingleTon instance=new SingleTon();
    private SingleTon() {}
    public static SingleTon getInstance() {
        return instance;
    }
}

方式2: 懒汉式(使用时创建,线程不安全,加同步)

/**
 * 懒汉式单例 
 * (1)首先创建一个对象,赋值为null 
 * (2)构造方法改成私有的,类外部不能创建对象 
 * (3)通过一个公开的方法,返回这个对象
 * 
 * 优点:声明周期短,节省空间 缺点:有线程安全问题
 *
 */
public class SingleTon2 {
    // 创建对象
    private static SingleTon2 instance = null;

    // 私有化构造方法
    private SingleTon2() {
    }

    // 静态方法
    public static  SingleTon2 getInstance() {
        if(instance==null) {//提高执行效率
            synchronized (SingleTon2.class) {
                if (instance == null) {
                    instance = new SingleTon2();
                }
            }
        }
        return instance;
    }
}

方式3: 懒汉式(使用时创建,线程安全)

/**
 * 单例第三种写法:静态内部类写法
 *
 */
public class SingleTon3 {
    private SingleTon3() {}
    
    private static class Holder{
        static SingleTon3 instance=new SingleTon3();
    }
    
    public static SingleTon3 getInstance() {
        return Holder.instance;
    }
}

6、枚举

1、什么是枚举:

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

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

3、定义枚举使用enum关键字。

4、枚举的本质:

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

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

/**
 * 性别枚举
 * 注意
 * (1)枚举中必须要包含枚举常量,也可以包含属性、方法、私有构造方法
 * (2)枚举常量必须在前面,多个常量之间使用逗号隔开,最后分号可写可不写
 *
 */
public enum Gender {
    MALE,FEMALE;
}
/**
 * 季节枚举
 *
 */
public enum Season {
    SPRING,SUMMER,AUTUMN,WINTER;
}
public class TestGender {
    public static void main(String[] args) {
        Gender gender=Gender.MALE;
        System.out.println(gender.toString());

        Season season=Season.SPRING;
        System.out.println(season.toString());
    }
}

7、注解

什么是注解:

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

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

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

常见注解:@Override、@Deprecated

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

注解属性类型:

  1、String类型

  2、基本数据类型

  3、Class类型

  4、枚举类型

  5、注解类型

  6、以上类型的一维数组

/**
 * 创建注解类型  @interface
 *
 */
public @interface MyAnnotation {
    //属性(类似方法)
    String name() default "张三";
    int age() default 20;
}
public @interface MyAnnotation2 {
    //属性
    //字符串类型
    String value();
    //基本类型
    int num() default 20;
    //Class类型
    Class<?> class1();
    //枚举类型
    Gender gender();
    //注解类型
    MyAnnotation annotation();
    //ArrayList<String> list();
}
public class Person {

    @MyAnnotation()
    public void show() {
        
    }
    
    //@MyAnnotation2(value="大肉",num=25)
    public void eat() {
        
    }
    
    @PersonInfo(name="小岳岳",age=30,sex="男")
    public void show(String name,int age,String sex) {
        System.out.println(name+"==="+age+"===="+sex);
    }
}

元注解:

  用来描述注解的注解。

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

  RetentionPolicy.CLASS:

    注解记录在class文件中,运行Java程序时,JVM不会保留,此为默认值。

   RetentionPolicy.RUNTIME:

    注解记录在class文件中,运行Java程序时,JVM会保留,程序可以通过反射获取该注释。

  RetentionPolicy.SOURCE:

    编译时直接丢弃这种策略的注释。

@Target:

  指定注解用于修饰类的哪个成员。

@Retention(value=RetentionPolicy.RUNTIME)
@Target(value= {ElementType.METHOD})
public @interface PersonInfo {
    String name();
    int age();
    String sex();
}
public class Demo {
    public static void main(String[] args) throws Exception{
        //(1)获取类对象
        Class<?> class1=Class.forName("com.qf.chap17_5.Person");

        //(2)获取方法
        Method method=class1.getMethod("show", String.class,int.class,String.class);

        //(3)获取方法上面的注解信息 personInfo=null
        PersonInfo personInfo=method.getAnnotation(PersonInfo.class);
        
        //(4)打印注解信息
        System.out.println(personInfo.name());
        System.out.println(personInfo.age());
        System.out.println(personInfo.sex());
        
        //(5)调用方法
        Person yueyue=(Person)class1.newInstance();
        method.invoke(yueyue, personInfo.name(),personInfo.age(),personInfo.sex());
    }
}

8、总结

类对象:

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

获取类对象的三种方式:

  Class c=对象.getClass();

  Class c =类名.class;

  Class c=Class.forName(“包名.类名”);

工厂模式:

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

单例模式:

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

枚举类型、注解类型

posted @ 2021-09-12 21:53  菜鸟的道路  阅读(29)  评论(0)    收藏  举报