Java反射机制详解上篇

简介:

1反射机制是什么

反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。


在面向对象的世界里,万事万物皆对象.在java语言里,静态的成员,普通数据类型是不是对象呢?

类又是谁的对象呢?

首先类是对象,类是java.lang.Class类的实例对象.

新创建一个Foo类

Foo这个类也是一个实例对象,是Class类的实例对象,这个对象在官网被称为(class type).

反射是java程序开发语言的特性之一,它允许运行中的java程序获取自身的信息,并且可以操作类或者对象内部的属性.

反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

了解反射其实需要了解JVM,不过一般的资料不会在这一部分讲到JVM,毕竟学习也是要从浅入深的.


2反射机制能做什么


反射机制主要提供了以下功能: 

  • 在运行时判断任意一个对象所属的类;

  • 在运行时构造任意一个类的对象;

  • 在运行时判断任意一个类所具有的成员变量和方法;

  • 在运行时调用任意一个对象的方法;

  • 生成动态代理。

注意;是运行时获取而不是编译时获取.其实很多时候我们直接用eclipse写代码忽略了编译的过程

在Eclipse,当我们输入一个点的时候(比如 a.)   编译器就会自动列出它的属性和方法,这里就会用到反射


3反射机制的相关API (在这里只说反射机制五种功能的前两种)

java的反射机制的实现要借助于4个类: class,Constructor,Field,Method;

通过一个对象获得完整的包名和类名

1
2
3
4
5
6
7
8
9
10
11
12
package  cn.xins08.boke;
 
public  class  TestReflect {
 
     public  static  void  main(String[] args) {
         TestReflect testReflect =  new  TestReflect();
         System.out.println(testReflect.getClass().getName());
         // 结果:cn.xins08.boke.TestReflect
 
     }
 
}


实例化Class对象:

实现反射机制获取类有三种方法:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package  cn.xins08.boke;
 
public  class  TestReflect {
     public  static  void  main(String[] args)  throws  Exception {
 
         Class<?> class1 =  null ;
         Class<?> class2 =  null ;
         Class<?> class3 =  null ;
         //第一种方式(在JDBC开发中常用此方法加载数据驱动)
         class1 = Class.forName( "cn.xins08.boke.TestReflect" );
       //第三种方式:java中任何一个对象都有getClass方法
         class2 =  new  TestReflect().getClass();
         
         //第三种方式java中任何一个对象都有class属性
         class3 = TestReflect. class ;
         System.out.println( "类名称: "  + class1.getName());
         System.out.println( "类名称: "  + class2.getName());
         System.out.println( "类名称: "  + class3.getName());
         // 打印结果:
         /*
          * 类名称: cn.xins08.boke.TestReflect 类名称: cn.xins08.boke.TestReflect 类名称:
          * cn.xins08.boke.TestReflect
          */
     }
}


获取一个对象的父类与实现的接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package  cn.xins08.boke;
 
import  java.io.Serializable;
 
public  class  TestReflect  implements  Serializable {
      private  static  final  long  serialVersionUID = -2862585049955236662L;
     public  static  void  main(String[] args)  throws  Exception {
          
             
                 Class<?> clazz = Class.forName( "cn.xins08.boke.TestReflect" );
                 // 取得父类
                 Class<?> parentClass = clazz.getSuperclass();
                 System.out.println( "clazz的父类为:"  + parentClass.getName());
                 // clazz的父类为: java.lang.Object
                 // 获取所有的接口
                 Class<?> intes[] = clazz.getInterfaces();
                 System.out.println( "clazz实现的接口有:" );
                 for  ( int  i =  0 ; i < intes.length; i++) {
                     System.out.println((i +  1 ) +  ":"  + intes[i].getName());
                 }
                 // clazz实现的接口有:
                 // 1:java.io.Serializable
         
     }
}


创建实例:

通过反射来生成对象主要有两种方式:

(1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。

1
2
Class<?> c = String. class ;
Object str = c.newInstance();

    初始化一个类,生成一个实例的时候,new与newInstance() 有什么区别?

     区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有两种创建对象方式?这个就要从可伸缩、可扩展,可重用等软件思想上解释了。

newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。
newInstance()是实现IOC、反射、面对接口编程 和 依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口编程。


(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。

1
2
3
4
5
6
7
// 获取String所对应的Class对象
         Class<?> c = String. class ;
         // 获取String类带一个String参数的构造器
         Constructor constructor = c.getConstructor(String. class );
         // 根据构造器创建实例
         Object obj = constructor.newInstance( "23333" );
         System.out.println(obj);



注意事项:反射会额外的消耗一定的系统资源,如果不需要动态的创建一个对象,那么就不需要用反射


在文章的最后我们讨论下工厂模式:

1
2
3
4
5
6
package  cn.xins08.boke;
 
public  interface  Fruit {
public  void  eat();
 
}
1
2
3
4
5
6
7
8
9
10
package  cn.xins08.boke;
 
public  class  Apple  implements  Fruit{
     public  void  eat(){
         System.out.println( "吃苹果" );
     }
 
     
 
}
1
2
3
4
5
6
7
8
9
10
package  cn.xins08.boke;
 
public  class  Factory {
public  static  Fruit getInstance(String className){
     if ( "apple" .equals(className)){
         return  new  Apple();
     }
     return  null ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
package  cn.xins08.boke;
 
public  class  FactoryDemo {
 
     public  static  void  main(String[] args) {
         Fruit f = Factory.getInstance( "apple" );
         f.eat();
 
     }
 
}
//返回的结果是"吃苹果"

这种是一个最简单的工厂设计模式,但是有一个很大的问题是,如果现在接口的子类增加了,那么工厂类肯定需要改.而造成这个问题的病因就是new,如果变成反射机制就不一样了.反射的实例化对象只需要包.类就可以了.

1
2
3
4
5
6
package  cn.xins08.boke;
 
public  interface  Fruit {
public  void  eat();
 
}
1
2
3
4
5
6
7
8
9
10
package  cn.xins08.boke;
 
public  class  Orange  implements  Fruit{
     public  void  eat(){
         System.out.println( "吃橘子" );
     }
 
     
 
}
1
2
3
4
5
6
7
8
package  cn.xins08.boke;
 
public  class  Apple  implements  Fruit{
     public  void  eat(){
         System.out.println( "吃苹果" );
     }
 
     }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package  cn.xins08.boke;
 
public  class  Factory {
public  static  Fruit getInstance(String className){
    Fruit fruit =  null ;
try {
    //这里是Fruit的类类型,做强制类型转换 
     fruit = (Fruit) Class.forName(className).newInstance() ;
     catch (Exception e) {
        e.printStackTrace();
    }
        return   f ;
        }
   }
 
 
 
}
1
2
3
4
5
6
7
8
9
10
11
package  cn.xins08.boke;
 
public  class  FactoryDemo {
 
     public  static  void  main(String[] args) {
         Fruit f = Factory.getInstance( "cn.xins08.boke.Apple" );
         f.eat();
 
     }
 
}



这时候我们发现即使增加几个接口的子类,工厂类照样可以完成对象的实例化操作,可以对应所有的变化.


    到目前为止你已经会了最基本的反射使用了,在学习Spring之前先讲这些,等学习了Spring的依赖注入,反转控制之后,相信会对反射有更好的理解.


关于反射以下功能,等写完后会在本文加链接

  • 在运行时判断任意一个类所具有的成员变量和方法;

  • 在运行时调用任意一个对象的方法;

  • 生成动态代理。


--java一万小时成神之路--本文首发与51CTO博客---


近期读书计划:

《思考,快与慢》

《浪潮之巅》



本文转自 维度2018 51CTO博客,原文链接:http://blog.51cto.com/xinsz08/1946912,如需转载请自行联系原作者

相关文章
|
23天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
60 2
|
27天前
|
Java 编译器
探索Java中的异常处理机制
【10月更文挑战第35天】在Java的世界中,异常是程序运行过程中不可避免的一部分。本文将通过通俗易懂的语言和生动的比喻,带你了解Java中的异常处理机制,包括异常的类型、如何捕获和处理异常,以及如何在代码中有效地利用异常处理来提升程序的健壮性。让我们一起走进Java的异常世界,学习如何优雅地面对和解决问题吧!
|
1月前
|
XML 安全 Java
Java反射机制:解锁代码的无限可能
Java 反射(Reflection)是Java 的特征之一,它允许程序在运行时动态地访问和操作类的信息,包括类的属性、方法和构造函数。 反射机制能够使程序具备更大的灵活性和扩展性
42 5
Java反射机制:解锁代码的无限可能
|
26天前
|
Java 数据库连接 开发者
Java中的异常处理机制及其最佳实践####
在本文中,我们将探讨Java编程语言中的异常处理机制。通过深入分析try-catch语句、throws关键字以及自定义异常的创建与使用,我们旨在揭示如何有效地管理和响应程序运行中的错误和异常情况。此外,本文还将讨论一些最佳实践,以帮助开发者编写更加健壮和易于维护的代码。 ####
|
1月前
|
安全 IDE Java
Java反射Reflect机制详解
Java反射(Reflection)机制是Java语言的重要特性之一,允许程序在运行时动态地获取类的信息,并对类进行操作,如创建实例、调用方法、访问字段等。反射机制极大地提高了Java程序的灵活性和动态性,但也带来了性能和安全方面的挑战。本文将详细介绍Java反射机制的基本概念、常用操作、应用场景以及其优缺点。 ## 基本概念 ### 什么是反射 反射是一种在程序运行时动态获取类的信息,并对类进行操作的机制。通过反射,程序可以在运行时获得类的字段、方法、构造函数等信息,并可以动态调用方法、创建实例和访问字段。 ### 反射的核心类 Java反射机制主要由以下几个类和接口组成,这些类
60 2
|
1月前
|
存储 缓存 安全
🌟Java零基础:深入解析Java序列化机制
【10月更文挑战第20天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
29 3
|
1月前
|
安全 Java UED
深入理解Java中的异常处理机制
【10月更文挑战第25天】在编程世界中,错误和意外是不可避免的。Java作为一种广泛使用的编程语言,其异常处理机制是确保程序健壮性和可靠性的关键。本文通过浅显易懂的语言和实际示例,引导读者了解Java异常处理的基本概念、分类以及如何有效地使用try-catch-finally语句来处理异常情况。我们将从一个简单的例子开始,逐步深入到异常处理的最佳实践,旨在帮助初学者和有经验的开发者更好地掌握这一重要技能。
28 2
|
1月前
|
Java 数据库连接 开发者
Java中的异常处理机制####
本文深入探讨了Java语言中异常处理的核心概念,通过实例解析了try-catch语句的工作原理,并讨论了finally块和throws关键字的使用场景。我们将了解如何在Java程序中有效地管理错误,提高代码的健壮性和可维护性。 ####
|
1月前
|
Java
Java中的反射机制与应用实例
【10月更文挑战第22天】Java作为一门面向对象的编程语言,提供了丰富的特性来支持对象的创建、操作和交互。其中,反射机制是Java的一项核心特性,它允许程序在运行时动态地获取类的信息、创建对象、调用方法、访问属性等。本文将从三个部分探讨Java中的反射机制及其应用实例:一是反射机制的基本概念和原理;二是反射机制在Java中的应用场景;三是通过实例深入理解反射机制的使用方法和技巧。
24 4
|
2月前
|
安全 Java 程序员
深入浅出Java中的异常处理机制
【10月更文挑战第20天】本文将带你一探Java的异常处理世界,通过浅显易懂的语言和生动的比喻,让你在轻松阅读中掌握Java异常处理的核心概念。我们将一起学习如何优雅地处理代码中不可预见的错误,确保程序的健壮性和稳定性。准备好了吗?让我们一起踏上这段旅程吧!
27 6