Java 反射

74 阅读3分钟

Java 反射

类对象

类的对象:基于某个类 new 出来的对象,也成为实例对象 类对象:类加载的产物,分装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)

每个类加载到内存中都会生成一个唯一的类对象‘

获取类对象

  • 通过类的对象,获取类对象
Student s = new Student();
Class<? extend Student> c = s.getClass();
  • 通过类名获取类对象

Class<Student> c = Student.class

  • 通过静态方法获取类对象

Class<?> c = Class.forName("包名.类名")

反射通用操作

⽅法名描述
public String getName()获取类的完全名称
public Package getPackage()获取包信息
public Class<? super T> getSuperclass()获取⽗类
public Class<?>[] getInterfaces()获取实现⽗接⼝
public Field[] getFields()获取字段信息
public Method[] getMethods()获取⽅法信息
public Constructor<?>[] getConstructors()获取构造⽅法
public T newInstance()反射创建对象

使用反射机制获取类对象,并使用Class对象的方法获取表示类成员的各种对象,实现反射各种应用。

设计模式

工厂方法模式

public abstract class Clothes {

    public abstract void prepare();

    public abstract void make();

    public abstract void box();

}
public class ClothesFactory {
    private static Properties properties;
    static {
        properties = new Properties();
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream("src\clothes.properties");
            properties.load(fileInputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    System.out.println("流关闭失败");
                }
            }
        }
    }

    public static Clothes create(int type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        String className = properties.getProperty(type + "");
        Clothes clothes = null;
        if (className != null) {
            Class<?> class1 = Class.forName(className);
            clothes = (Clothes) class1.newInstance();
            if (clothes != null) {
                clothes.prepare();
                clothes.make();
                clothes.box();
            }
        }
        return clothes;
    }
}

单例模式

饿汉式

优点:线程安全 缺点:生命周期长,浪费空间

public class SingleInstance {
    private static SingleInstance singleInstance = new SingleInstance();

    private SingleInstance() {

    }

    public static SingleInstance getInstance() {
        return singleInstance;
    }
}

懒汉式

优点:获取对象时才创建对象 缺点:线程不安全

public class SingleInstance2 {
    private static volatile SingleInstance2 singleInstance2;

    private SingleInstance2() {

    }

    public SingleInstance2 getSingleInstance2() {
        if (singleInstance2 == null) {
            synchronized (SingleInstance2.class) {
                if (singleInstance2 == null) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    singleInstance2 = new SingleInstance2();
                }
            }
        }
        return singleInstance2;
    }
}

静态内部类

兼具懒汉式和饿汉式的优点

public class SingleInstance3 {

    private SingleInstance3() {

    }

    private static class Inner {
        static SingleInstance3 singleInstance3 = new SingleInstance3();
    }

    public SingleInstance3 getInstance() {
        return Inner.singleInstance3;
    }
}

枚举

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

  • 枚举变量不能使用其他的数据,只能使用枚举中常量赋值,提高程序安全性。
  • 定义枚举使用enum关键字。
  • 枚举的本质
    • 枚举是一个终止类,并继承Enum抽象类。
    • 枚举中常量是当前类型的静态常量。
public enum Gender {
    MALE,FEMALE
}
  • 枚举中必须要包含枚举常量,也可以包含属性、方法、私有构造方法。
  • 枚举常量必须在前面,多个常量之间使用逗号隔开,最后分号可写可不写。

注解

注解(Annotation):是代码里的标记,程序可以读取注解,一般用于代替配置文件。 开发人员可以通过注解告诉类如何运⾏。 在Java技术⾥注解的典型应⽤是:可以通过反射技术去得到类⾥⾯的注解,以决定怎么去运⾏类。

定义注解

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

public @interface MyAnnotation {
    String name() default "张三";
    int age();
}

注解属性类型

  • String类型
  • 基本数据类型
  • Class类型
  • 枚举类型
  • 注解类型
  • 以上类型的一维数组

元注解

元注解:⽤来描述注解的注解。

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

  • RetentionPolicy.CLASS:
    • 注解记录在class⽂件中,运⾏Java程序时, JVM不会保留,此为默认值。
  • RetentionPolicy.RUNTIME:
    • 注解记录在 class⽂件中,运⾏Java程序时,JVM会保留,程序可以通过反射获取该注释
  • RetentionPolicy.SOURCE:
    • 编译时直接丢弃这种策略的注释。

@Target

  • 指定注解用于修饰类的哪个成员
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {Element.METHOD})
public @interface PersonInfo {
    String name();
    int age();
    String sex();
}