Java中的反射(1)

Java中的反射

一、概念:

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

2、反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。

Oracle 官方对反射的解释是:

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
 The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

In a word,通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。

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

4、反射就是把java类中的各种成分映射成一个个的Java对象

例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

二、Class类的使用

1、在面向对象的世界里,万事万物皆对象。

Java语言中,静态的成员、普通的数据类型类是不是对象呢?

类是谁的对象呢?

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

基本数据类型 void关键字 都存在类类型

There is a class named Class

2.案例

package com.tedu.reflect;
public static ClassDemo{
	public static void main(String[] args){
		//Foo的实例对象如何表示
		Foo foo1=new Foo();
		//Foo这个类也是一个实例对象,Class类的实例对象,如何表示呢?
		//任何一个类都是Class的实例对象,这个实例对象有三种表达方式
			//1、实际告诉我们任何一个类都有一个隐含的静态成员
			Class c1=Foo.class;
			//2、已知该类的对象通过getClass方法
			Class c2=foo1.getClass();
			/*官网 c1,c2表示了Foo类的类类型(class type)
			*万事万物皆对象,类也是对象,是Class类的实例对象
			*这个对象我们称为该类的类类型
			**/
			//3、(有异常try.catch)
			Class c3=Class.forName("com.tedu.reflect.Foo");
		//通过类的类类型创建该类的对象实例——>通过c1/c2/c3创建的Foo的实例
				Foo foo=(Foo)c1.newInstanstance();//有异常try.catch
				
}
class Foo{

}
3.Class.forName(“类的全称”);

不仅代表了类的类类型,还代表了动态加载类

请大家区分编译和运行

编译时刻加载类是静态加载类,运行时刻加载类是动态加载类

//new创建对象是静态加载类,在编译时刻就需要加载所有的可能使用到的类

三、反射是什么呢?

当我们的程序在运行时,需要动态的加载一些类这些类可能之前用不到所以不用加载到jvm,而是在运行时根据需要才加载,这样的好处对于服务器来说不言而喻,举个例子我们的项目底层有时是用mysql,有时用oracle,需要动态地根据实际情况加载驱动类,这个时候反射就有用了,假设 com.java.dbtest.myqlConnection,com.java.dbtest.oracleConnection这两个类我们要用,这时候我们的程序就写得比较动态化,通过Class tc = Class.forName(“com.java.dbtest.TestConnection”);通过类的全类名让jvm在服务器中找到并加载这个类,而如果是oracle则传入的参数就变成另一个了。这时候就可以看到反射的好处了,这个动态性就体现出java的特性了!举多个例子,大家如果接触过spring,会发现当你配置各种各样的bean时,是以配置文件的形式配置的,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载,你的程序就能健壮地运行。

1、Java 反射机制主要提供了以下功能

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

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

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

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

反射的常用类和函数:Java反射机制的实现要借助于4个类:Class,Constructor,Field,Method;

其中class代表的是类对象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象,通过这四个对象我们可以粗略的看到一个类的各个组成部分。其中最核心的就是Class类,它是实现反射的基础,它包含的方法我们在第一部分已经进行了基本的阐述。应用反射时我们最关心的一般是一个类的构造器、属性和方法,下面我们主要介绍Class类中针对这三个元素的方法:

1、得到构造器的方法

Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数, 
Constructor[] getConstructors() -- 获得类的所有公共构造函数 
Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关) 
Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关) 

2、获得字段信息的方法

Field getField(String name) -- 获得命名的公共字段 
Field[] getFields() -- 获得类的所有公共字段 
Field getDeclaredField(String name) -- 获得类声明的命名的字段 
Field[] getDeclaredFields() -- 获得类声明的所有字段 

3、获得方法信息的方法

Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法 
Method[] getMethods() -- 获得类的所有公共方法 
Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法 
Method[] getDeclaredMethods() -- 获得类声明的所有方法 

在程序开发中使用反射并结合属性文件,可以达到程序代码与配置文件相分离的目的,反射机制让代码具有通用性,可变化的内容都是写到配置文件中,修改配置文件创建的对象不一样了,调用的方法也不同了,但Java代码不需要做任何改动。

如果我们想要得到对象的信息,一般需要“引入需要的‘包.类’的名称——通过new实例化——取得实例化对象”这样的过程。使用反射就可以变成“实例化对象——getClass()方法——得到完整的‘包.类’名称”这样的过程。

正常方法是通过一个类创建对象,反射方法就是通过一个对象找到一个类的信息。

四、 补充:

1、如果只希望一个类的静态代码块执行,其他一律不执行可以使用:

​ Class.forName(“完整类名”);

​ 这个方法的执行会导致类加载类时静态代码块执行

2、元注解中@Retention(RetentionPolity.SOURCE)表示该注解只被保留在Java源文件中

​ @Retention(RetentionPolity.CLASS)表示该注解被保留在CLASS文件中

​ @Retention(RetentionPolity.RUNTIME)表示该注解被保留在CLASS文件中并且可以被反射机制读取到

3、类路径:凡是在src下的都是类路径下,src是类的根路径

String path=Thread.currentThread().getContextClassLoader().getResource("相对路径").getPath();
Thread.currentThread()  当前线程对象
getContextClassLoader()  获得当前线程类加载器对象
getResource("相对路径")   获取资源,当前线程的类加载器默认从类的根路径下加载资源

采用以上代码,可以拿到一个文件的绝对路径

4、类加载器

专门负责加载的命令/工具 ClassLoader

JDK自带了三个类加载器

①启动类加载器(父加载器),专门加载:jre/lib/rt.jar

②扩展类加载器(母加载器),专门加载:jre/lib/ext/*.jar

③应用类加载器,加载classpath中的jar包(类)

双亲委派机制:为保证类加载安全,优先从启动类加载器加载,无法加载则通过扩展类加载器加载,无法加载才通过应用类加载器加载。

注:资料源自慕课网,知乎等平台,有错误之处希望大家及时指正,感谢大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值