Java学习之走进反射

本文详细介绍了Java反射机制的基本概念及获取类对象的方法,并通过示例展示了反射的应用。此外,还深入探讨了几种常见的设计模式,包括工厂模式、单例模式、枚举和注解的应用。

什么是类对象

  • 类的对象:基于某个类new出来的对象,也称为实例对象
  • 类对象:类加载的产物,封装了一个类的所有信息(类名,父类,接口,属性,方法,构造方法)
  • 注意:使用-verbose:class 可以显示累的加载过程

获取类对象的方法

  • 通过类的对象,获取类对象
    Student s= new Student();
    Class c=s.getClass();
  • 通过类名获取类对象
    Class c=类名.class
  • 通过静态方法获取类对象
    Class c=Class.forName(“包名.类名”);
public class Demo01 {
    public static void main(String[] args) throws Exception{
        //1.通过类的对象,获取类对象
        Student student = new Student();
        Class<?> class1 = student.getClass();
        System.out.println(class1.hashCode());
        //2.通过类名获取类对象
        Class<?> class2 = Student.class;
        System.out.println(class2.hashCode());
        //3.通过静态方法获取类对象【推荐使用】
        Class<?> class3 = Class.forName("com.ozl.day14.Student");
        System.out.println(class3.hashCode());
    }
}

在这里插入图片描述

常见方法

在这里插入图片描述

/**
 * 反射的常用方法
 */
public class Demo02 {
    public static void main(String[] args) throws Exception{
        //获取类对象
        Class<?> studentClass = Class.forName("com.ozl.day14.Student");
        //获取类名字
        System.out.println(studentClass.getName());
        System.out.println("============");
        //获取类的包名
        System.out.println(studentClass.getPackage());
        System.out.println("============");
        //获取类的父类
        System.out.println(studentClass.getSuperclass());
        System.out.println("============");
        //获取类实现的接口
        System.out.println(studentClass.getInterfaces());
        System.out.println("============");
        //获取类的构造器
        System.out.println(studentClass.getConstructor());
        System.out.println("============");
        //无参构造创建实例
        Constructor<?> con = studentClass.getConstructor();
        Student s1 =(Student)con.newInstance();
        System.out.println(s1);
        System.out.println("============");
        //有参构造创建实例
        Constructor<?> con1 = studentClass.getConstructor(Integer.class, String.class);
        Student s3 = (Student) con1.newInstance(12,"小李");
        System.out.println(s3);
        System.out.println("================");
        //类对象创建实例
        Student s2 = (Student) studentClass.newInstance();
        System.out.println(s2);
        System.out.println("=============");
        //获取类的方法
        //1.包含父类继承的方法以及公开的方法
        Method[] methods = studentClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("===============");
        //2.获取类中声明的全部方法,包括私有的方法等,不包含继承方法
        Method[] dm = studentClass.getDeclaredMethods();
        for (Method method : dm) {
            System.out.println(method);
        }
        //3.获取单个方法
        Method run = studentClass.getMethod("run", String.class);
        //调用方法
        Student student = (Student) studentClass.newInstance();
        run.invoke(student, "小明");
        //4.获取私有方法
        Method jump = studentClass.getDeclaredMethod("jump");
        //设置访问权限无效
        jump.setAccessible(true);
        jump.invoke(student);
        //5.获取静态方法
        Method eat = studentClass.getMethod("eat");
        eat.invoke(null);
        System.out.println("==============");
        //获取类的属性
        //1.获取公开的属性和父类继承的的公开属性
        Field[] fields = studentClass.getFields();
        System.out.println(fields.length);
        //2.获取类对象的声明的方法
        Field[] declaredFields = studentClass.getDeclaredFields();
        System.out.println(declaredFields.length);
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        //3.获取单个属性
        Field name = studentClass.getDeclaredField("name");
        //设置访问权限无效
        name.setAccessible(true);
        //4.属性赋值
        Student s = (Student) studentClass.newInstance();
        name.set(s,"欧少");//s.name="欧少";
        //5.获取值
        System.out.println(name.get(s));//s.name
    }
}

在这里插入图片描述
在这里插入图片描述

  • 使用反射实现一个调用任何对象方法的通用方法
/**
 * 使用反射实现一个调用任何对象方法的通用方法
 */
public class Demo03 {
    public static void main(String[] args) throws Exception{
        Properties properties = new Properties();
//        properties.setProperty("name","lisi");
//        System.out.println(properties);
        inbvokeAny(properties,"setProperty",new Class[]{String.class,String.class},"name","lisi");
        System.out.println(properties);
    }
    public static Object inbvokeAny(Object obj,String methodName,Class<?>[] types,Object...args)throws Exception{
        //创建类对象
        Class<?> objClass = obj.getClass();
        //获取方法
        Method method = objClass.getMethod(methodName,types);
        //方法调用
        return method.invoke(obj,args);
    }
}

在这里插入图片描述

设计模式介绍

  • 什么设计模式
    • 一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结,简单理解:特定问题的特定解决方案
    • 好处,实现可重用代码,让代码更容易被他人理解,保证代码可靠性,重用性
    • 23种设计模式

工厂设计模式

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

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

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

  • 简单实现工厂模式

测试

public class Demo04 {
    public static void main(String[] args) {
        System.out.println("=========请选择物品==========");
        System.out.println("1.风扇 2.鼠标 3.U盘");
        Scanner scanner = new Scanner(System.in);
        int choice = scanner.nextInt();
        Usb usb = UsbFactory.creatUsb(choice);
        if (usb!=null){
            System.out.println("购买成功");
            usb.service();
        }else {
            System.out.println("购买失败,无此产品");
        }
    }
}

UsbFactory

public class UsbFactory {
    public static Usb creatUsb(int choice){
        Usb usb=null;
        if (choice==1){
            usb=new Fan();
        }else if (choice==2){
            usb=new Mouse();
        }else if (choice==3)
            usb=new Upan();
        return usb;
    }

}

Usb接口

public interface Usb {
    public void service();
}

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

实现类

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

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

在这里插入图片描述
在这里插入图片描述

  • 反射优化工厂模式

UsbFactory

public class UsbFactory {
    public static Usb creatUsb(String type) {
        Usb usb = null;
        try {
            Class<?> c = Class.forName(type);
            usb = (Usb) c.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return usb;
    }
}

测试

public class Demo04 {
    public static void main(String[] args) throws Exception{
        System.out.println("=========请选择物品==========");
        System.out.println("1.风扇 2.鼠标 3.U盘");
        Scanner scanner = new Scanner(System.in);
        String choice = scanner.next();
        Properties properties = new Properties();
        FileInputStream fis = new FileInputStream("src/com/ozl/day14/usb.properties");
        properties.load(fis);
        fis.close();
        Usb usb = UsbFactory.creatUsb(properties.getProperty(choice));
        if (usb!=null){
            System.out.println("购买成功");
            usb.service();
        }else {
            System.out.println("购买失败,无此产品");
        }
    }
}

usb.properties

1=com.ozl.day14.Fan
2=com.ozl.day14.Mouse
3=com.ozl.day14.Upan

在这里插入图片描述

单例设计模式

  • 单例:只允许创建一个该类的对象
  • 方式1:饿汉式(类加载时创建,天生线程安全,声明周期长,浪费资源)

测试类

public class Demo05 {
    public static void main(String[] args) {
        for (int i = 0; i <5 ; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Singleton.getInstance().hashCode());
                }
            }).start();
        }
    }
}

Singleton

/**
 * 饿汉式单例
 * 1.创建一个静态常量
 * 2。构造方法私有化,类外部不可创建
 * 3.通过一个公开方法,返回这个对象
 */
public class Singleton {
    private static final Singleton instance=new Singleton();
    private Singleton(){}

    public static Singleton getInstance() {
        return instance;
    }
}

在这里插入图片描述

  • 方式2:懒汉式(使用时创建,线程不安全,需加同步,声明周期短,节省空间)
    同步方法实现
/**
 * 懒汉式单例
 *  * 1.创建一个静态对象
 *  * 2。构造方法私有化,类外部不可创建
 *  * 3.通过一个公开方法,返回这个对象
 */
public class Singleton2 {
    private static  Singleton2 instance=null;
    private Singleton2(){}
    public static synchronized Singleton2 getInstance() {
        if (instance==null){
            instance=new Singleton2();
        }
        return instance;
    }
}

同步代码块实现

/**
 * 懒汉式单例
 *  * 1.创建一个静态对象
 *  * 2。构造方法私有化,类外部不可创建
 *  * 3.通过一个公开方法,返回这个对象
 */
public class Singleton2 {
    private static  Singleton2 instance=null;
    private Singleton2(){}
    public static  Singleton2 getInstance() {
        synchronized (Singleton2.class){
            if (instance==null){
                instance=new Singleton2();
            }
        }
        return instance;
    }
}

同步代码块优化

/**
 * 懒汉式单例
 *  * 1.创建一个静态对象
 *  * 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;
    }
}

在这里插入图片描述

  • 由于jvm有指令重排序的优化,所以instance=new Singleton2();会分成三部执行
    • 给 instance 分配内存
    • 调用 Singleton 的构造函数来初始化成员变量
    • 将instance对象指向分配的内存空间
  • 第二步和第三步有序优化执行顺序可能会不一样,就会出现问题,所以instance 变量声明成 volatile 就可以完美解决
public class Singleton2 {
    private volatile 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;
    }

}

枚举

  • 什么是枚举
    • 枚举是一个引用类型,枚举是一个规定了取值范围的数据类型
  • 枚举变量不能使用其他的数据,只能使用枚举中的常量赋值,提高程序安全性
  • 定义枚举使用enum关键字
  • 枚举的本质
    • 枚举是一个终止类(final 修饰的类),并继承Enum抽象类
    • 枚举中的常量就是当前类型的静态常量
/**
 * 性别枚举
 * 1.枚举必须有枚举常量,也可以包含属性,方法,私有构造方法,构造方法一定是私有方法
 * 2.枚举常量必须放在最前面,多个常量之间用逗号隔开,最后的分号可写可不写
 */
public enum  Gender {
    MALE,FEMALE;
}

public class TestGender {
    public static void main(String[] args) {

        Gender male = Gender.MALE;
        System.out.println(male);
    }
}

在这里插入图片描述

注解

  • 什么是注解
    • 注解(Annotation)是代码里的特殊标记,程序可以读取注解,一般用于替代配置文件
  • 开发人员可以通过注解告诉类如何运行
    • 在java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么运行类
  • 常见注解:@Override,@Deprecated
  • 定义注解使用@interface关键字,注解中只能包含属性
  • 注解的本质就是接口,继承了Annotation
/**
 * 注解使用
 */
public @interface MyAnnotation {
    //设置属性(类似方法)
    //设置默认值
    String name() default "张三";
    //不设置默认值
    int age();
}

public class Person {
    @MyAnnotation(age = 20)
    public void show(){

    }
}

  • 注解属性类型
    • String类型
    • 基本数据类型
    • Class类型
    • 枚举类型
    • 注解类型
    • 以上类型的一维数组
public @interface MyAnnotation2 {
    //属性
    //字符串类型
    String value();
    //基本数据类型
    int num();
    //Class类型
    Class<?> class1();
    //枚举类型
    Gender gender();
    //注解类型
    MyAnnotation annotation();
    //一维数组
    char[] char1();
}

  • 元注解:用来描述注解的注解
  • @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 Person {
    @MyAnnotation(age = 20)
    public void show(){
        System.out.println();
    }
    @PersonInfo(name="小明",age=30,sex="男")
    public void show(String name,int age,String sex){
        System.out.println(name+"===="+age+"===="+sex);
    }
}

public class Demo08 {
    public static void main(String[] args) throws Exception{
        //获取该类
        Class<?> aClass = Class.forName("com.ozl.day14.Person");
        //获取方法
        Method show = aClass.getMethod("show", String.class, int.class, String.class);
        //获取方法上的注解
        PersonInfo personInfo = show.getAnnotation(PersonInfo.class);
        //打印注解信息
        System.out.println(personInfo.name());
        System.out.println(personInfo.sex());
        System.out.println(personInfo.age());
        //调用方法
        Person xiaoming = (Person)aClass.newInstance();
        show.invoke(xiaoming,personInfo.name(),personInfo.age(),personInfo.sex());
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值