黑马程序员_高薪技术一(java反射)

本文深入讲解Java反射机制,包括Class类、Constructor类、Field类、Method类的基本使用,以及数组的反射应用。同时探讨了反射技术在框架开发中的作用,并介绍了类加载器管理资源和配置文件的方法。

----------- android培训java培训、java博客、java学习型技术博客、期待与您交流! --------------

 

 本章主要的知识点总结:1、了解Class类、得到字节码的三种方式以及反射的概念

                                2、Constructor类Field类、Method类的反射应用

                                 3、数组的反射和Object的关系及数组反射的应用,hashcode的分析。

                                 4、用反射技术开发框架的原理、用类加载器的方式管理资源和配置文件
                             
            

一.Class类——反射的基石


    (1)java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class.

   (2)举例

       人-->Person
       Java类-->Class
 (3)对比提问:Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,Class
      类代表Java类,它的各个实例对象又分别对应什么呢?
 ----对应各个类在内存中的字节码,例如:Person类的字节码,ArrayList类的字节码,等等。
 -----一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,
  -----不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个空间可分别用一个个
   -----的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?
(4)如何得到各个字节码对应的实例对象(Class类型)
     类名.class,         例如:Math.class
     对象.getClass(),      例如:new String().getClass()
      Class.forName("类名"),   例如:Class.forName("java.String")//查询或加载


java里面有9个预定义的Class实例对象(8个基本数据类型和void)。

     int.class == Integer.TYPE;

int.class.isPrimitive();-----true    //判断class类是否为基本数据类型。
      int[].class.isArray();-----true   //判断Class类是否为数组类。

总之在源程序出现的类型,都有各自的Class实例对象 如:int[ ] ,void


 2.class与Class的区别:
      class是指java类,java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,

  至于这个属性的值是什么,则由这个类的实例对象来确定,不同的实例对象有不同的属性值。
        java程序中的各个类,也属于同一类事物,Class类是用来描述java程序中的各个java类这一事物的,

  Class类描 述了类的名字,类的访问属性,类所属的包名,字段名称的列表,方法名称的列表等等。
 3.Class.forName("java.lang.String");中forName()的作用:
   返回字节码。有两种方式:第一,字节码已加载过。第二,字节码未被加载过,在java虚拟机中还不存在,
   则用类加载器去加载,然后缓存到虚拟机中,以后就不用再加载了。


、反射概念  

       Java中的反射:就是把Java类中各种成分映射成相应的Java类。

          例如,一个java类可用一个Class类的对象来表示,一个类中的组成部分有:成员变量,方法,构造方法,包等等 信息也可用一个个的java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个类。表示java类 的  Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field,Method,Contructor,Package等等。
            一 个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法
   可以得到这些实例对象。然后再使用这些对象。


三、Constructor类

代表某个类中的一个构造方法。
(1)得到某个类所有的构造方法:
    例子:Constructor[] contructors = Class.forName("java.lang.String").getConstructors();
 (2)得到某一个构造方法:
  例子:Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
  //获取方法时要用到类型
(3) 创建实例对象:
  1、通常方式:String str = new String(new StringBuffer("abc"));
  2、反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));

//调用获得的方法时要用到上面的相同类型的实例对象
(4)Class.newInstance()方法:
  1、例子:String obj = (String)Class.forName("java.lang.String").newInstance();
  2、该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。


四、Field 


Field类代表某个类中的一个成员变量。
  注意:得到的Field对象是对应到类上面的成员变量,不是对应到对象上的成员变量,
     字段fieldX代表的是x的定义,而不是具体的x变量。


代码实例:

  1. public class ReflectPoint   
  2. {  
  3.  private int x;  
  4.  public int y;  
  5.  public ReflectPoint(int x, int y) {  
  6.   super();  
  7.   this.x = x;  
  8.   this.y = y;  
  9.  }  
  10.   
  11. }  
  12.   
  13. import java.lang.reflect.Constructor;  
  14. import java.lang.reflect.Field;  
  15.   
  16. public class ReflectTest   
  17. {  
  18.  public static void main(String[] args)throws Exception  
  19.  {  
  20.    
  21.     ReflectPoint pt1 = new ReflectPoint(3,5);  
  22.   Field fieldY = pt1.getClass().getField("y");  
  23.   //fieldY的值是多少?不是5,fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值。  
  24.   System.out.println(fieldY.get(pt1));  
  25.   Field fieldX = pt1.getClass().getDeclaredField("x");//x 是私有变量,是看不见的,此方法则可看见,但不能用  
  26.   fieldX.setAccessible(true);//暴力反射:可强制使用已看到但不能用的私有变量。  
  27.   System.out.println(fieldX.get(pt1));  
  28.  }  
  29. }  

 五、Method类


                Method类代表某个类中的一个成员方法
     ( 1)得到类中的某一个方法:
                 如:Method charAt = String.class.getMethod("charAt",int.class);
     (2)调用方法:
             1、通常方式:System.out.println(str.charAt(1));
              2、反射方式:System.out.println(charAt.invoke(str,1));
               如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法。


      对接收数组参数的成员方法进行反射

       问题:

         启动java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),

       通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,

        整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,因为jdk1.5

       要兼容jdk1.4的语法,所以当把一个字符数组作为参数传递给invoke方法时,javac会按jdk1.4

          的语法进行处理。不能使用代码:mainMethod.invoke(null,new String[]{"xxx"});

      解决办法:

      (1)mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});//即封装成一个参数

       (2)mainMethod.invoke(null,(Object)new String[]{"xxx"});//这样做等于告诉编译器说这是一个参数

                  //编译器就不分把参数当数组看待,也不会把数组打散成若干个参数了.


     代码实例:

      1. import java.lang.reflect.Constructor;  
      2. import java.lang.reflect.Field;  
      3. import java.lang.reflect.Method;  
      4.   
      5. public class ReflectTest {  
      6.  public static void main(String[] args)throws Exception  
      7.  {  
      8.   //TestArguments.main(new String[]{"111","222","333"});  
      9.   String startingClassName = args[0];  
      10.   Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);  
      11.   //mainMethod.invoke(null,new Object[]{new String[]{"111","222","333"}});  
      12.   mainMethod.invoke(null, (Object)new String[]{"111","222","333"});  
      13.  }  
      14. }  
      15.   
      16. class TestArguments  
      17. {  
      18.  public static void main(String[] args)  
      19.  {  
      20.   for(String arg : args)  
      21.   {  
      22.    System.out.println(arg);  
      23.   }  
      24.     
      25.  }  
      26. }  

六、数组的反射与Object关系及其反射类型


1.数组反射
(1)具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
  (2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class.
  (3)基本类型的一维数组可以被告当作Object类型使用,不能当作Object[]类型使用,
  非基本类型的一维数组,即可以当作Object类型使用,也能当作Object[]类型使用。


代码例子:
  
  int[ ] a1 = new int[ ]{1,2,3};
  int[ ] a2 = new int[4];
  int[ ][ ] a3 = new int[2][3];
  String[ ] a4 = new String[ ]{"a","b","c"};
  System.out.println(a1.getClass() == a2.getClass());
  System.out.println(a1.getClass == a4.getClass());
  System.out.println(a1.getClass() == a3.getClass());
  System.out.println(a1.getClass().getName());
  System.out.println(a1.getClass().getSuperclass().getName());

//获取Class实例对象的父类对应的Class实例对象名称为Object
  System.out.println(a4.getClass().getSuperclass().getName());
  
  Object aobj1 = a1;
  Object aobj2 = a4;
  //Object[] aobj3 = a1;
  Object[] aobj4 = a3;
  Object[] aobj5 = a4;
  
  System.out.println(a1);
  System.out.println(a4);
  System.out.println(Arrays.asList(a1));//--->a1整体相当于一个Object类型,使用JDK1.5的,故打印结果为一个对象的哈希值。
  System.out.println(Arrays.asList(a4));//--->a4中相当于有三个Object类型,使用JDK1.4的,故打印结果为[a,b,c]。


Java.Lang.Reflect.Array类
     public final class Array extends Object
       Array 类提供了动态创建和访问 Java 数组的方法。 Array 允许在执行 get 或 set 操作期间进行扩展转换,
  但如果发生收缩转换,则抛出 IllegalArgumentException。 
  代码例子:

Object obj=null;

Class clazz=obj.getClass();

if(clazz.isArray()){

  int len=Array.getLength(obj);

for(int i=0;i<len;i++)

{

  System.out.println(Array.get(obj,i));

}

}


   hash集合中hashcode()方法及内存泄漏
         当一个对象被存储到HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值
  的字段了,否则,对象修改后哈希值就变了,这种情况下,使用contains方法传入该对象当前
  引用作为参数无法检索到对象,这也导致无法从HashSet集合中单独删除当前对象,从而造成
  内存泄露。


七、用反射技术开发框架的原理

 1.反射的作用-->实现框架功能
 ( 1)框架与框架要解决的核心问题
  我做房子给用户住,用户自己安装门窗,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中,框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
   你做的门调用锁,锁是工具,你做的门被房子调用,房子是框架,房子和锁都是别人提供的。
  (2)框架要解决的核心问题:
       若干年前写的框架可以调用若干年后写的程序。
      写程序时无法知被调用的类名,所以在程序中无法直接new某个类的实例对象, 而要用反射来做。


八、用类加载器的方式管理资源和配置文件


1.类 ClassLoader
  public abstract class ClassLoader  extends Object类加载器是负责加载类的对象。
  ClassLoader 类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。
  一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”。 
  每个 Class 对象都包含一个对定义它的 ClassLoader 的引用。
   InputStream getResourceAsStream(String name) 
          返回读取指定资源的输入流。 
将文件放到源文件下,会自动将它的字节码文件搬到classPath目录下。


代码实例
  (1)InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");
  //此例运行是将配置文件放在了源文件(src)目录下,意为:从根目录下开始查找,若不加cn/itcast/day1的话就找不到文件。

 (2)InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
  //此例运行是将配置文件放在了源文件的新建包cn.itcast.day1.resources下,意为:从默认的程序路径下开始查找,即从包cn.itcast.day下找。

     (3InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");

            //使用绝对路径


源码链接: https://pan.quark.cn/s/a4b39357ea24 斐讯K2是款广受用户青睐的无线路由器,其运行表现稳定且具备较高的可操作性,在DIY爱好者群体中拥有极高的声誉。本资料将系统性地阐述斐讯K2的固件刷机方法及其关联的技术要点。固件升级是路由器爱好者改善设备性能、扩展功能的种普遍手段,经由替换出厂固件,能够达成更加个性化的网络配置、增强安全防护等目标。斐讯K2固件资源库涵盖了多种知名的非官方固件,诸如Tomato Pheonix 不死鸟、高恪、PandoraBox 潘多拉等,这些固件均具备独特的优势,能够适配不同用户的需求。 1. Tomato Pheonix 不死鸟:Tomato是款立足于Linux的开源固件,以其精巧、高效而备受推崇。不死鸟版本是专门为华硕及斐讯路由器优化的分支,提供了卓越的QoS(服务质量)配置、详尽的图表监控以及便捷的固件升级途径。对于那些需要精准调控带宽和监测网络状态的用户而言,这是个理想的选项。 2. 高恪:高恪固件是OpenWrt的定制化版本,着重于操作的便捷性和运行的可靠性,特别适合对路由器操作不甚熟悉的用户群体。它提供了些实用的功能,例如内置的广告屏蔽、快速测速工具等,同时保留了OpenWrt的适应性。 3. PandoraBox 潘多拉:潘多拉盒是另款基于OpenWrt的固件,它以丰富的插件库和强大的自定义潜力而闻名。用户能够依据个人需求安装各类插件,实现更多功能,如远程接入、DDNS(动态域名解析服务)等。 4. 官方固件的纯净版本与定制版本:官方固件通常更侧重于稳定性,纯净版意味着未预置额外的应用或服务,适合注重稳定性的用户。定制版则可能包含了制造商的特色功能或优...
源码下载地址: https://pan.quark.cn/s/926926948560 AS3.0与XML结合的通用图片滚动功能,是种基于ActionScript 3.0和XML技术的动态图像展示方案,非常适合初学者进行学习和实践应用。此项目的关键在于借助XML文件作为数据媒介,用来保存图像的相关参数,例如图像的链接地址、展示的次序等,接着在AS3.0环境中对XML进行解析,并动态地载入和展示这些图像,达成图像的滚动或是循环播放的目的。 我们需要明确ActionScript 3.0(AS3.0)是Adobe Flash Professional以及Flex Builder等开发工具中采用的编程语言,用于构建交互式内容以及丰富的互联网应用。相较于先前的版本,AS3.0在性能上有了大幅度的提升,并且引入了更为规范的面向对象编程模式,涵盖了类、接口以及包等概念。 XML(可扩展标记语言)是种简明且高效的数据传输格式,既便于人类阅读和编写,也易于机器进行解析和生成。在该项目中,XML文件用于存储图像数据,例如图像的URL、延时的时长、动画的样式等,通过这种方式可以将数据与程序代码分离,从而增强代码的可维护性与可扩展程度。 实施这图片滚动功能,主要涉及到以下AS3.0的核心知识点: 1. **XML解析**:运用`XML`类来载入并解析XML文件,从而获取图像的清单。AS3.0提供了简便的API来操作XML节点,例如`children()`、`attributes()`等,用以获取子节点和属性值。 2. **事件监听**:借助`EventDispatcher`类来监控载入和解析过程中的事件,比如`Event.OPEN`、`Event.PROGRESS`、`Event...
内容概要:本文介绍了软件许可管理的技术实现方式及相关工具资源,重点阐述了加密外壳(EMS)和API加密两种保护机制。加密外壳通过将程序(如.exe、.dll、.apk)封装在加密壳中,实现运行时内存解密,防止静态反编译和代码篡改,同时支持对数据文件、系统参数及部分代码的加密,并依赖硬件锁(HL)或软件锁(SL)进行授权控制。API加密则通过在代码中嵌入安全验证调用,确保授权合法后才执行核心逻辑。文章还说明了锁的类型(HL/SL)、模式(有驱/AdminMode与无驱/UserMode)、升级路径以及虚拟时钟功能,并描述了产品授权流程从功能定义到产品创建、授权生成的全过程,支持通过C2V文件或锁ID复制已有授权状态。文中附带多个开源平台链接和技术博客参考资源。; 适合人群:从事软件版权保护、授权系统开发或安全技术研究的研发人员,尤其是具备定逆向工程、软件安全基础的1-3年经验开发者。; 使用场景及目标:①构建安全的软件授权体系,防止盗版和非法使用;②实现灵活的功能授权管理(如时效、并发、硬件绑定);③选择合适的加密方案(硬件锁/软锁、有驱/无驱)并集成到现有产品中;④学习加密外壳与API验证的实际应用方法; 阅读建议:此资源侧重于软件许可的技术架构与实施细节,建议结合提供的GitHub、Gitee项目链接及CSDN技术文章深入理解实现原理,并通过实际调试加密壳和模拟授权流程加强实践能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值