反射的详解

反射

  • 类加载
    概念:
    类是编译器编译后的产物,是硬盘中的一个.class文件,如果在一个java程序中需要使用一个类,JVM必然会从硬盘中加载(读取)该类的信息(.class)文件。
    
    类加载的时机与过程:
    1. 当JVM第一次使用某个类时,需要通过class_path找到该类的.class文件
    2. 将.class文件中描述的信息(属性、方法、构造方法、父类、接口、代码),读取到虚拟机内存中。
    3. 加载时会初始化静态资源(静态属性,静态方法)并执行静态初始化代码块。
    
    注意:类加载只会执行一次。
  • 反射的概念:
    当JVM从硬盘中加载了一个.class文件的信息会在内存中生成一个对应的Class对象
    Class对象就包含了.class文件的所有信息。
    面向对象编程:创建对象--->调用方法--->使用属性---->完成功能。
    反射编程(上帝模式):通过Class对象---->获取方法--->获取属性---->选择对象执行或赋值。
    

1 Class对象

  • 概念:JVM类加载时的产物,包含了一个类的所有信息。
1.1 获取Class对象的三种方式
  1. 通过Object中的getClass方法
    获取ArrayList类的Class对象。
    List list = new ArrayList();
    Class cls1 = list.getClass();
    
  2. 通过类名.class获取Class对象
    获取ArrayList类的Class对象。
    Class<ArrayList> cls2 = ArrayList.class;
    
  3. 通过字符串获取Class对象
    获取ArrayList类的Class对象。
    Class cls3 = Class.forName("java.util.ArrayList");
    
    注意:处理异常
1.2 常用方法
  • 演示的代码如下:
    // 通过字符串获取Class对象
     Class cl = Class.forName("java.util.ArrayList");
    // 获取全类名
    String className = cl.getName();
    System.out.println(className);
    // 获取类名
    String name = cl.getSimpleName();
    System.out.println(name);
    // 获取直接父类
    Class supClass = cl.getSuperclass();
    System.out.println(supClass);
    // 获取实现的接口
    Class[] is = cl.getInterfaces();
    System.out.println(Arrays.toString(is));
    // 获取所有属性(公开的属性或父类继承的公开的属性)
    Field[] fs = cl.getFields();
    System.out.println(Arrays.toString(fs));
    // 获取所有属性(本类的所有的)
    Field[] fs2 = cl.getDeclaredFields();
    System.out.println(Arrays.toString(fs2));
    // 获取所有的方法(公开的或父类继承的)
    Method[] ms = cl.getMethods();
    System.out.println(Arrays.toString(ms));
    // 获取所有的方法(本类的所有的)
    Method[] ms2 = cl.getDeclaredMethods();
    // 获取类中的公开的内部类
    Class[] css = Super.class.getClasses();
    System.out.println(Arrays.toString(css));
    // 获取包
    Package p = cl.getPackage();
    System.out.println( p );
    // 获取构造方法
    Constructor[] cts = cl.getConstructors();
    System.out.println(Arrays.toString(cts));
    
    演示的代码如下:
package com.txw.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class TestClass {
    public static void main(String[] args) throws Exception{
    /*    // 1.Object中的getClass方法获取
        List list = new ArrayList();
        Class cls1 = list.getClass();
        // 2.通过类名.class获取Class对象
        Class<ArrayList> cls2 = ArrayList.class;*/
        // 3.通过字符串获取Class对象
        Class cl = Class.forName("java.util.ArrayList");
        // 获取全类名
        String className = cl.getName();
        System.out.println(className);
        // 获取类名
        String name = cl.getSimpleName();
        System.out.println(name);
        // 获取直接父类
        Class supClass = cl.getSuperclass();
        System.out.println(supClass);
        //获取实现的接口
        Class[] is = cl.getInterfaces();
        System.out.println(Arrays.toString(is));
        // 获取所有属性(公开的属性或父类继承的公开的属性)
        Field[] fs = cl.getFields();
        System.out.println(Arrays.toString(fs));
        // 获取所有属性(本类的所有的)
        Field[] fs2 = cl.getDeclaredFields();
        System.out.println(Arrays.toString(fs2));
        // 获取所有的方法(公开的或父类继承的)
        Method[] ms = cl.getMethods();
        System.out.println(Arrays.toString(ms));
        // 获取所有的方法(本类的所有的)
        Method[] ms2 = cl.getDeclaredMethods();
        // 获取类中的公开的内部类
        Class[] css = Super.class.getClasses();
        System.out.println(Arrays.toString(css));
        // 获取包
        Package p = cl.getPackage();
        System.out.println( p );
        // 获取构造方法
        Constructor[] cts = cl.getConstructors();
        System.out.println(Arrays.toString(cts));
    }
}
class Super{
    public class InnerClass{
    }
}

2 反射编程步骤

2.1 获取Class对象
  • 获取Class对象,根据Class对象创建对应的实例。
    Class对象引用.newInstance();
    
    比如:
    Class cls = Class.forName("com.txw.Student");		// 获取Class对象
    Object obj = cls.newInstance();			// 创建Student对象
    
2.2 获取属性或方法,选择对象执行
  • 获取方法,选择对象执行。

    // 获取公开的方法
    Method m = cls.getMethod("方法名",参数类型.class,参数类型.class...);			
    // 选择对象执行方法
    m.invoke( obj,实参1,实参2...);
    
  • 获取私有方法。

    Method m = cls.getDeclaredMethod("方法名",参数类型.class,参数类型.class....);
    m.setAccessible(true);		// 授权访问私有成员
    m.invoke(...);
    
  • 获取属性,为某个对象的属性赋值。

    // 获取公开属性
    Field f = cls.getField("属性名");
    // 赋值基本数据类型
    f.setInt/setDouble等等(obj,"值");
    // 对象类型
    f.set(obj,);
    
  • 获取私有属性,为某个对象的属性赋值。

    Field f = cls.getDeclaredField("属性名");
    f.setAccessible(true);		// 授权访问私有成员
    f.set(...);
    

    演示的代码如下:

package com.txw.test;

import java.lang.reflect.Field;
import java.util.Map;
public class TestReflect {
    public static void main(String[] args) throws Exception{
        // Class cls = Class.forName("com.txw.test.MyClass");
        // Object obj = cls.newInstance();
        // 面向对象编程
        // MyClass mc = new MyClass();
        // mc.m1();
        // Hello h = new Hello()
        // h.m1();
        // 反射编程
           /* Method m1Method = cls.getMethod("m1");        // 获取无参m1
            Method m1Method2 = cls.getMethod("m1",int.class);       // 获取有参m1 参数类型为int
            m1Method.invoke(obj);
            Object result = m1Method2.invoke(obj,10);
            System.out.println(result);*/
        //  Method m = cls.getDeclaredMethod("m2");
        //  m.setAccessible(true);      // 授权访问私有成员
        //  m.invoke(obj);
        //  Field fa =cls.getField("a");
        //  fa.set(obj,100);
        // System.out.println(obj);
           /* Field fb = cls.getDeclaredField("b");
            fb.setAccessible(true);     // 授权访问私有成员
            fb.set(obj,"Hello");
            System.out.println(obj);*/

        Class cls = Class.forName("java.util.HashMap");
        Object obj = cls.newInstance();
        Map map = (Map)obj;
        map.put("A","AA");
        map.put("B","BB");
        System.out.println(map.size());
        Field f = cls.getDeclaredField("size");
        f.setAccessible(true);      // 设置访问私有属性权限
        f.setInt(obj,100);
        System.out.println(map.size());
        map.put("C","CC");
        System.out.println(map.size());
        System.out.println( map );
    }
}
class Hello{
    public void m1(){
        System.out.println("Hello m1()");
    }
}
class MyClass{
    public Integer a;
    private String b;

    public String toString(){
        return "MyClass["+b+"]";
    }
    public void m1(){
        System.out.println("MyClass m1()");
    }
    public String m1(int n){
        System.out.println("MyClass m1(int)" + n);
        return "invoke success";
    }
    private void m2(){
        System.out.println("private m2()");
    }
}

3 单例模式

  • 概念:保证应用中的某一类只有一个实例(对象),通常用于资源管理类,例如:线程池、连接池、常量池。
    设计规范:
    1. 构造方法私有化避免手动创建对象。
    2. 提供用于获取对象的静态方法或提供一种途径。
    
  1. 饿汉式单例模式。
    class Singleton1{
        // 存储一个实例
        private static final Singleton1 instance = new Singleton1();
        // 构造方法私有化
        private Singleton1(){}
        // 提供获取对象的方法
        public static Singleton1 getInstance(){
            return instance;
        }
    }
    
  2. 懒汉式单例模式。
    class Singleton2{
        // 存储一个实例
        private static Singleton2 instance;
        // 构造方法私有化
        private Singleton2(){}
        // 提供获取对象的方法
        public synchronized  static Singleton2 getInstance(){
            if(instance==null){
                instance = new Singleton2();					// 创建单例对象
            }
            return instance;
        }
    }
    
    两种实现方式的特点:
    1. 饿汉式以空间换时间,可能会浪费空间但节省了创建对象的时间。
    2. 懒汉式以时间换空间,会因为创建对象而浪费时间但是节省了空间。
    
  3. 懒汉式变种:支持并发,效率高。
    class Singleton3{
        //  静态内部类,加载外部类时不会加载内部类
        private static class SingletonInstance{
            private static final Singleton3 instance  = new Singleton3();
        }
        private Singleton3(){}		// 构造方法私有化
        // 提供获取对象的方法
        public static Singleton3 getInstance(){
            return SingletonInstance.instance;		// 返回内部类的属性
        }
    
    }
    
    演示的代码如下:
package com.txw.test;

public class TestSingleton1 {
    public static void main(String[] args) {
        // Singleton1 sl1 = Singleton1.getInstance();
        // Singleton1 sl2 = Singleton1.getInstance();
        Singleton2 sl1 = Singleton2.getInstance();
        Singleton2 sl2 = Singleton2.getInstance();
        System.out.println(sl1);
        System.out.println(sl2);

    }
}
class Singleton1{
    // 存储一个实例
    private static final Singleton1 instance = new Singleton1();
    // 构造方法私有化
    private Singleton1(){}
    // 提供获取对象的方法
    public static Singleton1 getInstance(){
        return instance;
    }
}
class Singleton2{
    // 存储一个实例
    private static Singleton2 instance;
    // 构造方法私有化
    private Singleton2(){}
    // 提供获取对象的方法
    public synchronized  static Singleton2 getInstance(){
        if(instance==null){
            instance = new Singleton2();    // 创建单例对象
        }
        return instance;
    }
}
class Singleton3{
    private static class SingletonInstance{
        private static final Singleton3 instance  = new Singleton3();
    }
    private Singleton3(){}      // 构造方法私有化
    // 提供获取对象的方法
    public static Singleton3 getInstance(){
        return SingletonInstance.instance;      // 返回内部类的属性
    }
}

4 工厂模式

  • 概念:将创建对象的代码封装到一个类中,统一分配对象管理对象,便于扩展与维护。
    实现代码:
package com.txw.test;

import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class TestFactory {
    public static void main(String[] args) {
        List list1 =Factory.getBean(List.class);		// Class<List>
        Set set =  Factory.getBean(Set.class);          // Class<Set>
        Map map =Factory.getBean(Map.class);
        MyInterface mi = Factory.getBean(MyInterface.class);
        System.out.println(list1.getClass());
        System.out.println(set.getClass());
        System.out.println(map.getClass());
        System.out.println(mi);
    }
}
interface MyInterface{ }
class MyInterfaceImpl implements MyInterface{}
// 工厂模式2.5
class Factory{
    private static Properties p = new Properties();										// 存储配置文件信息
    static{
        InputStream is = Factory.class.getResourceAsStream("./factory.properties");
        // 加载配置文件中的内容
        try{p.load(is);}catch(Exception e){e.printStackTrace();}
    }
    public static<T> T getBean(Class<T> cls){//Class<Set> cls
        // 读取配置文件
        // InputStream is = Factory.class.getResourceAsStream("./factory.properties");
        // InputStream is = null;
        T result = null;
        try {
            // is = new FileInputStream("./test/src/com/txw/test/factory.properties");
            // 根据key获取value(全类名)
            // 获取类名
            String clasName = cls.getSimpleName();
            String value = p.getProperty(clasName);        // java.util.List
            Class c = Class.forName(value);
            result = (T)c.newInstance();	// 创建对象
        }catch(Exception e){
            e.printStackTrace();
        }
        return result;
    }
}

创建factory.properties的代码如下:

List=java.util.LinkedList
Set=java.util.LinkedHashSet
Map=java.util.LinkedHashMap
MyInterface=com.txw.test.MyInterfaceImpl

如图所示:在这里插入图片描述

总结在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学无止路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值