【十六】Java反射(了解单例、用工厂模式去创建对象,它不香吗?)


目录


一、什么是类对象
二、获取类对象的方法
三、常见方法
四、工厂设计模式
五、单例设计模式


思维导图参考:【十六】Java反射思维导图


一、什么是类对象

  • 类的对象: 基于某个类new出来的对象,也称为实例对象
  • 类对象: 类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)
    在这里插入图片描述

二、获取类对象的方法

  • 通过类的对象,获取类对象
    • Person p = new Person();
    • Class c = p.getClass();
  • 通过类名获取类对象
    • Class c = 类名.class;
  • 通过静态方法获取类对象
    • Class c = Claa.forName(“包名.类名”);
package com.sweetown.reflect.reflect1.reflects;

public class TestGetClassObject {
    public static void main(String[] args) throws ClassNotFoundException {
        /*1.通过类的对象,获取Class对象*/
        Person person = new Person();//类的对象
        Class c = person.getClass();//类对象(Class对象,保存了Person.class这个文件中的所有信息)
        System.out.println(c.getName());//com.sweetown.reflect.reflect1.reflects.Person

        /*2.通过类名获取Class对象*/
        Class c1 = Person.class;
        System.out.println(c1.getName());//com.sweetown.reflect.reflect1.reflects.Person

        /*3.通过Class的静态方法获取Class对象*/
        Class c2 = Class.forName("com.sweetown.reflect.reflect1.reflects.Person");
        System.out.println(c2.getName());//com.sweetown.reflect.reflect1.reflects.Person
    }

    //该方法返回一个类对象(Class对象)
    public static Class getClassObject(String className) {
        Class c = null;
        try {
            c = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return c;
    }
}

class Person {

}

三、常见方法

  • public String getName()
  • public Package getPackage()
  • public Class<? super T> getSupercalass()
  • public Class<?>[] getInterfaces()
  • public Field[] getFields()
  • public Method[] getMethods()
  • public Constructor<?>[] getConstructors()
  • public T newInstance()
package com.sweetown.reflect.reflect2.methods;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class TestClassMethod {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //获取类对象
        Class c = Class.forName("com.sweetown.reflect.reflect2.methods.Student");
//        Class c = Class.forName("com.sweetown.reflect.reflect2.methods.Person");
        System.out.println(c.getName());

        //获取指定类对象的包
        Package pack = c.getPackage();
        System.out.println(pack.getName());//com.sweetown.reflect.reflect2.methods

        //获取父类的Class对象
        Class superClass = c.getSuperclass();
        System.out.println(superClass.getName());//java.lang.Object
        
        //获取接口的Class对象
        Class[] interfaces = c.getInterfaces();
        for (Class inter : interfaces) {
            System.out.println(inter.getName() + " ");//java.io.Serializable
        }

        //获取属性(自身+父类的公开属性)
        Field[] fields = c.getFields();
        for (Field f : fields) {
            System.out.print(f.getName() + " ");//sex money
        }

        //获取Class对象的自身所有属性
        Field[] fields1 = c.getDeclaredFields();
        for (Field f : fields1) {
            System.out.println(f.getName() + " ");//money
        }

        //获取方法(自身+父类的所有公开方法)
        Method[] methods = c.getMethods();
        for (Method m : methods) {
            System.out.println(m.getName());//sleep eat wait wait wait equals toString hashCode getClass notify notifyAll
        }

        //获取普通方法和返回值类型
        Method[] methods1 = c.getDeclaredMethods();
        for (Method m : methods1) {
            System.out.println(m.getName() + ":" + m.getReturnType());//sleep:void eat:void
        }

        //获取构造方法
        Constructor[] constructors = c.getConstructors();
        for (Constructor cs : constructors) {
            System.out.print(cs.getName() + ":");
            Class[] param = cs.getParameterTypes();//获取构造方法的形参
            for (Class p : param) {
                System.out.println(p.getName());//com.sweetown.reflect.reflect2.methods.Student:java.lang.String double
            }
        }

        //获取对象
        Object o = c.newInstance();
        Student student = (Student)o;
        System.out.println(student);//com.sweetown.reflect.reflect2.methods.Student:com.sweetown.reflect.reflect2.methods.Student@7daf6ecc
    }
}

class Person implements Serializable {
    public String sex;
    public double money;
    public void eat() {}
    public void sleep() {}
}

class Student extends Person implements Serializable, Runnable, Comparable {
    public String sex;
    public double money;
    public void eat() {}
    public void sleep() {}

    public Student() {
    }

    public Student(String sex, double money) {
        this.sex = sex;
        this.money = money;
    }

    private int aaa() {
        return 0;
    }

    public int compareTo(Object o) {
        return 0;
    }

    public void run() {

    }
}

四、工厂设计模式

  • 开发中有一个非常重要的原则“开闭原则”,对拓展开放、对修改关闭
  • 工厂模式主要负责对象创建的问题
  • 可通过反射进行工厂模式的设计,完成动态的对象创建

创建对象的工厂模式

package com.sweetown.reflect.reflect3.factory;

/**
 * 创建对象的工厂模式
 */
public class TestFactory {
    public static void main(String[] args) {
        Object o = createObject("com.sweetown.reflect.reflect3.factory.A");
        System.out.println(o.toString());
    }

    /*工厂--->创建对象的工厂*/
    public static Object createObject(String className) {
        try {
            Class c = Class.forName(className);
            return c.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

class A {

}

利用创建对象工厂加工的对象来实现Method的调用方法

package com.sweetown.reflect.reflect3.factory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 *利用创建对象工厂加工的对象来实现Method的调用方法
 * 注意:Method底层结构是数组来实现存储调用的方法的!
 */
public class TestInvokeMethod {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        /*反射--->类的对象*/
        Object o = createObject("com.sweetown.reflect.reflect3.factory.Student");
        /*类对象*/
        Class c = o.getClass();

        /*---------------------------------分割线-------------------------------*/

        /**
         * name->方法名
         * parameterTypes->参数列表类型
         * 调用无参study方法
         */
        Method method = c.getMethod("study", null);//正在学习...

        /*---------------------------------分割线-------------------------------*/

        /**
         * 通过invoke方法,执行某个实例方法
         * 参数:Object->所需对象
         * args->调用的方法所需的实参
         */
        method.invoke(o, null);
        Method method1 = c.getMethod("study", int.class);
        /*接收方法返回值,如果是基本类型,则转换为包装*/
        Object result = method1.invoke(o, 100);
        System.out.println(result);//学习了100个小时 0
        /*简写*/
        System.out.println(c.getMethod("study", int.class).invoke(o, 99));//学习了99个小时 0

        /*---------------------------------分割线-------------------------------*/

        /*调用的exam三参方法*/
        Method method2 = c.getMethod("exam", int.class, double.class, String.class);
        method2.invoke(o, 10, 100, "Ziph");//Ziph做了10小时的测验,考了100.0分

        /*---------------------------------分割线-------------------------------*/

//        Method method3 = c.getMethod("cala", null);//java.lang.NoSuchMethodException(Error!无法获得私有属性!)
        Method method3 = c.getDeclaredMethod("calc", null);
        /*注意:反射是一种Java的底层技术,可以取消语言修饰符的价差,突破封装,但不影响封装思想(切勿混为一坛)*/
        /**
         * 将此对象的 accessible 标志设置为指示的布尔值。
         * 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
         * 值为 false 则指示反射的对象应该实施 Java 语言访问检查。
         */
        method3.setAccessible(true);
        method3.invoke(o, null);
    }

    /*工厂--->创建对象的工厂*/
    public static Object createObject(String className) {
        try {
            Class c = Class.forName(className);
            return c.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

class Student {
    String name;
    Integer age;
    String sex;
    Double score;

    public Student() {
    }

    public Student(String name, Integer age, String sex, Double score) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.score = score;
    }

    public void study() {
        System.out.println("正在学习...");
    }

    public int study(int hours) {
        System.out.println("学习了" + hours + "个小时");
        return 0;
    }

    public void exam(int hours, double score, String name) {
        System.out.println(name + "做了" + hours + "小时的测验,考了" + score + "分");
    }

    public void calc() {
        System.out.println("Ziph正在计算...");
    }
}

创建对象并调用方法工厂模式

package com.sweetown.reflect.reflect3.factory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestInvokeAnything {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Object o = createObject("com.sweetown.reflect.reflect3.factory.Students");
        
        /*创建Students对象并调用exam三参方法*/
        invokeAnything(o, "exam", new Class[] {int.class, double.class, String.class}, 10, 100, "Ziph");

        /*创建Students对象并调用study无参方法*/
        invokeAnything(o, "study", null, null);
        
        /*创建Students对象并调用study一参方法*/
        invokeAnything(o, "study", new Class[] {int.class}, 100);
    }

    /**
     * 利用反射底层技术执行任何方法的通用编程(可以调用每一个方法)
     * @param obj 对象
     * @param methodName 方法名称
     * @param types 方法的形参列表(注意:数组接收)
     * @param args 需要传入的实参(注意:可变长参数)
     */
    public static void invokeAnything(Object obj, String methodName, Class[] types, Object... args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        /*类对象*/
        Class c = obj.getClass();
        /*获取方法的对象Method*/
        Method method = c.getDeclaredMethod(methodName, types);
        /*执行方法*/
        method.invoke(obj, args);
    }

    /**
     * 创建对象的工厂模式
     * @param className 需要传入的类对象名
     * @return
     */
    public static Object createObject(String className) {
        try {
            Class c = Class.forName(className);
            return c.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

class Students {
    String name;
    Integer age;
    String sex;
    Double score;

    public Students() {
    }

    public Students(String name, Integer age, String sex, Double score) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.score = score;
    }

    public void study() {
        System.out.println("正在学习...");
    }

    public int study(int hours) {
        System.out.println("学习了" + hours + "个小时");
        return 0;
    }

    public void exam(int hours, double score, String name) {
        System.out.println(name + "做了" + hours + "小时的测验,考了" + score + "分");
    }

    public void calc() {
        System.out.println("Ziph正在计算...");
    }
}

五、单例设计模式

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

  • 方式1: 饿汉式(类加载时创建,天生线程安全)
/**
 * 饿汉式:
 * 天生线程安全(无锁)
 * 类加载时创建(不用的时候,也被迫创建了,占用资源)
 */
class Singleton {
    private static final Singleton instance = new Singleton();

    private Singleton() {

    }

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

  • 方式2: 懒汉式(使用时创建,线程不安全,加同步)
/**
 * 懒汉式:
 * 使用时创建
 * 天生线程不安全(加同步锁)
 * 效率低
 */
class Singleton {
    private static Singleton instance = null;

    public Singleton() {

    }

    public synchronized static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

  • 方式3: 懒汉式(使用时创建,线程安全)
/**
 * 懒汉式:
 * 使用时创建
 * 天生线程安全
 */
class Singleton {
    private Singleton() {
        
    }
    
    private static class Holder {
        static final Singleton instance = new Singleton();
    }

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

发布了121 篇原创文章 · 获赞 184 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_44170221/article/details/104982540