java反射详解 (二)

Wesley13
• 阅读 506

【案例】通过反射操作属性

class hello { 
    public static void main(String[] args) throws Exception { 
        Class<?> demo = null; 
        Object obj = null; 
  
        demo = Class.forName("Reflect.Person"); 
        obj = demo.newInstance(); 
  
        Field field = demo.getDeclaredField("sex"); 
        field.setAccessible(true); 
        field.set(obj, "男"); 
        System.out.println(field.get(obj)); 
    } 
}// end class

【案例】通过反射取得并修改数组的信息:

import java.lang.reflect.*; 
class hello{ 
    public static void main(String[] args) { 
        int[] temp={1,2,3,4,5}; 
        Class<?>demo=temp.getClass().getComponentType(); 
        System.out.println("数组类型: "+demo.getName()); 
        System.out.println("数组长度  "+Array.getLength(temp)); 
        System.out.println("数组的第一个元素: "+Array.get(temp, 0)); 
        Array.set(temp, 0, 100); 
        System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0)); 
    } 
}

【运行结果】:

数组类型: int

数组长度 5

数组的第一个元素: 1

修改之后数组第一个元素为: 100

【案例】通过反射修改数组大小

class hello{ 
    public static void main(String[] args) { 
        int[] temp={1,2,3,4,5,6,7,8,9}; 
        int[] newTemp=(int[])arrayInc(temp,15); 
        print(newTemp); 
        System.out.println("====================="); 
        String[] atr={"a","b","c"}; 
        String[] str1=(String[])arrayInc(atr,8); 
        print(str1); 
    } 
      
    /** 
     * 修改数组大小 
     * */ 
    public static Object arrayInc(Object obj,int len){ 
        Class<?>arr=obj.getClass().getComponentType(); 
        Object newArr=Array.newInstance(arr, len); 
        int co=Array.getLength(obj); 
        System.arraycopy(obj, 0, newArr, 0, co); 
        return newArr; 
    } 
    /** 
     * 打印 
     * */ 
    public static void print(Object obj){ 
        Class<?>c=obj.getClass(); 
        if(!c.isArray()){ 
            return; 
        } 
        System.out.println("数组长度为: "+Array.getLength(obj)); 
        for (int i = 0; i < Array.getLength(obj); i++) { 
            System.out.print(Array.get(obj, i)+" "); 
        } 
    } 
}

 【运行结果】:

数组长度为: 15

1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================

数组长度为: 8

a b c null null null null null

动态代理

【案例】首先来看看如何获得类加载器:

class test{ 
      
} 
class hello{ 
    public static void main(String[] args) { 
        test t=new test(); 
        System.out.println("类加载器  "+t.getClass().getClassLoader().getClass().getName()); 
    } 
}

【程序输出】:

类加载器 sun.misc.Launcher$AppClassLoader

其实在java中有三种类类加载器。

1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。

2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类

3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。

如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。

package Reflect; 
import java.lang.reflect.*; 
  
//定义项目接口 
interface Subject { 
    public String say(String name, int age); 
} 
  
// 定义真实项目 
class RealSubject implements Subject { 
    @Override 
    public String say(String name, int age) { 
        return name + "  " + age; 
    } 
} 
  
class MyInvocationHandler implements InvocationHandler { 
    private Object obj = null; 
  
    public Object bind(Object obj) { 
        this.obj = obj; 
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj 
                .getClass().getInterfaces(), this); 
    } 
  
    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) 
            throws Throwable { 
        Object temp = method.invoke(this.obj, args); 
        return temp; 
    } 
} 
  
class hello { 
    public static void main(String[] args) { 
        MyInvocationHandler demo = new MyInvocationHandler(); 
        Subject sub = (Subject) demo.bind(new RealSubject()); 
        String info = sub.say("Rollen", 20); 
        System.out.println(info); 
    } 
}

【运行结果】:

Rollen  20

类的生命周期

在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。

类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class****对象。用来封装数据。 但是同一个类只会被类装载器装载以前

链接就是把二进制数据组装为可以运行的状态。

链接分为校验,准备,解析这3个阶段

校验一般用来确认此二进制文件是否适合当前的JVM(版本),

准备就是为静态成员分配内存空间,。并设置默认值

解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)

完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。

当没有任何引用指向Class对象时就会被卸载,结束类的生命周期

将反射用于工厂模式

先来看看,如果不用反射的时候,的工厂模式吧:

http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144851.html

interface fruit{ 
    public abstract void eat(); 
} 
  
class Apple implements fruit{ 
    public void eat(){ 
        System.out.println("Apple"); 
    } 
} 
  
class Orange implements fruit{ 
    public void eat(){ 
        System.out.println("Orange"); 
    } 
} 
  
// 构造工厂类 
// 也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了 
class Factory{ 
    public static fruit getInstance(String fruitName){ 
        fruit f=null; 
        if("Apple".equals(fruitName)){ 
            f=new Apple(); 
        } 
        if("Orange".equals(fruitName)){ 
            f=new Orange(); 
        } 
        return f; 
    } 
} 
class hello{ 
    public static void main(String[] a){ 
        fruit f=Factory.getInstance("Orange"); 
        f.eat(); 
    } 
  
}

这样,当我们在添加一个子类的时候,就需要修改工厂类了。如果我们添加太多的子类的时候,改的就会很多。

现在我们看看利用反射机制:

package Reflect; 
  
interface fruit{ 
    public abstract void eat(); 
} 
  
class Apple implements fruit{ 
    public void eat(){ 
        System.out.println("Apple"); 
    } 
} 
  
class Orange implements fruit{ 
    public void eat(){ 
        System.out.println("Orange"); 
    } 
} 
  
class Factory{ 
    public static fruit getInstance(String ClassName){ 
        fruit f=null; 
        try{ 
            f=(fruit)Class.forName(ClassName).newInstance(); 
        }catch (Exception e) { 
            e.printStackTrace(); 
        } 
        return f; 
    } 
} 
class hello{ 
    public static void main(String[] a){ 
        fruit f=Factory.getInstance("Reflect.Apple"); 
        if(f!=null){ 
            f.eat(); 
        } 
    } 
}

现在就算我们添加任意多个子类的时候,工厂类就不需要修改。

上面的爱吗虽然可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。

下面我们来看看: 结合属性文件的工厂模式

首先创建一个fruit.properties的资源文件,

内容为:

apple=Reflect.Apple 
orange=Reflect.Orange

然后编写主类代码:

package Reflect; 
  
import java.io.*; 
import java.util.*; 
  
interface fruit{ 
    public abstract void eat(); 
} 
  
class Apple implements fruit{ 
    public void eat(){ 
        System.out.println("Apple"); 
    } 
} 
  
class Orange implements fruit{ 
    public void eat(){ 
        System.out.println("Orange"); 
    } 
} 
  
//操作属性文件类 
class init{ 
    public static Properties getPro() throws FileNotFoundException, IOException{ 
        Properties pro=new Properties(); 
        File f=new File("fruit.properties"); 
        if(f.exists()){ 
            pro.load(new FileInputStream(f)); 
        }else{ 
            pro.setProperty("apple", "Reflect.Apple"); 
            pro.setProperty("orange", "Reflect.Orange"); 
            pro.store(new FileOutputStream(f), "FRUIT CLASS"); 
        } 
        return pro; 
    } 
} 
  
class Factory{ 
    public static fruit getInstance(String ClassName){ 
        fruit f=null; 
        try{ 
            f=(fruit)Class.forName(ClassName).newInstance(); 
        }catch (Exception e) { 
            e.printStackTrace(); 
        } 
        return f; 
    } 
} 
class hello{ 
    public static void main(String[] a) throws FileNotFoundException, IOException{ 
        Properties pro=init.getPro(); 
        fruit f=Factory.getInstance(pro.getProperty("apple")); 
        if(f!=null){ 
            f.eat(); 
        } 
    } 
}

下面这个是一个比较完整的反射工具类,用来获得一个类里面属性的具体信息

package util; 
import java.lang.reflect.*; 
/** 
 * 获取Class的信息 
 * 
 */ 
public class ClassInfo { 
  //需要反射的JAVA类型 
  private static Class reflectionClass; 
  private static String[][] relation; 
  private static String[] constructors; 
  private static String[] methods; 
  private static String[] fields; 
   
  //加载需要反射的类 
  public static void load(String reflectionClassName) { 
    try { 
      reflectionClass = null; 
      reflectionClass = Class.forName(reflectionClassName); 
    } catch (ClassNotFoundException e) { 
      System.err.println(e.getMessage()); 
    } 
  } 
  //获取类关系 
  public static String[][] getRelation() { 
    String superClassName = reflectionClass.getSuperclass().getSimpleName(); 
    Class[] interfaceClass = reflectionClass.getInterfaces(); 
    if(superClassName == null) 
      superClassName = "Have not super class!"; 
    if (reflectionClass.getInterfaces().length == 0) { 
      relation = new String[2][1]; 
      relation[1][0] = "Have not interface!"; 
    }else { 
      relation = new String[2][reflectionClass.getInterfaces().length]; 
      for (int i = 0; i < interfaceClass.length; i++) { 
        relation[1][i] = interfaceClass[i].getName(); 
        System.out.println( "interfaceClass:"+relation[1][i] ); 
      } 
    } 
    relation[0][0] = superClassName; 
    System.out.println( "superClassName:"+superClassName ); 
    return relation; 
  } 
  
  //获取构造方法 
  public static String[] getConstructors() { 
    Constructor[] constructor = reflectionClass.getDeclaredConstructors(); 
    constructors = new String[constructor.length]; 
    for (int i = 0; i < constructor.length; i++) { 
      Class[] paramType = constructor[i].getParameterTypes(); 
      String param = ""; 
      for (int j = 0; j < paramType.length; j++) { 
        param += paramType[j].getSimpleName().toString() + " "; 
      } 
      constructors[i] = constructor[i].getName().toString()  
                + "(" + param + ")"; 
      System.out.println("constructor:"+ constructors[i] ); 
    } 
    return constructors; 
  } 
  //获取类方法 
  public static String[] getMethods() { 
    Method[] method = reflectionClass.getDeclaredMethods(); 
    methods = new String[method.length]; 
    for (int i = 0; i < method.length; i++) { 
      Class[] paramType = method[i].getParameterTypes(); 
      String param = ""; 
      for (int j = 0; j < paramType.length; j++) { 
        param += paramType[j].getSimpleName().toString() + " "; 
      } 
      methods[i] = method[i].getName().toString()  
            + "(" + param + ")"; 
      System.out.println("method:"+ methods[i]); 
    } 
    return methods; 
  } 
  //获取类属性 
  public static String[] getFields() { 
    Field[] field = reflectionClass.getDeclaredFields(); 
    fields = new String[field.length]; 
    for (int i = 0; i < field.length; i++) { 
    field[i].setAccessible( true ); //允许访问私有属性 
      fields[i] = field[i].toGenericString(); 
      String type=field[i].getGenericType().toString(); 
      System.out.println("fields:"+fields[i]+"   type:"+type); 
    } 
    return fields; 
  } 
   
  //私有方法,被外部调用 
  private void testInvoke() { 
    System.out.println("invoke!"); 
  } 
  private void testInvoke(String str) { 
    System.out.println("invoke!:" + str); 
  } 
}
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
2星期前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
2年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
6个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这