1.什么是反射?

  Reflection(反射)是被视为动态语言的关键,反射机制允许程序做执行期间借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象内部属性及方法

2.反射相关的主要API

java.lang.Class:代表一个类

  java.lang.reflect.Method:代表类的方法

  java.lang.reflect.Field:代表类的成员变量

  java.lang.reflect.Constructor:代表类的构造方法

3.简单入门示例代码

package day01.code;

import java.lang.reflect.Field;
import java.lang.reflect.Method; import org.junit.Test; public class TestReflection { // 有了反射,可以通过反射创建一个类的对象,并调用其中的结构
@Test
public void test2() throws Exception{
Class clazz=Person.class;
// 1.创建clazz对应的运行时类Person类的对象
Person person= (Person)clazz.newInstance();
System.out.println(person);
// 2.通过反射调用运行时类的指定的属性
// 2.1 调用public的属性
Field f1=clazz.getField("name");
f1.set(person, "lisi");
System.out.println(person);
// 2.2 调用非public的属性
Field f2= clazz.getDeclaredField("age");
f2.setAccessible(true);
f2.set(person, 20);
System.out.println(person);
// 3.通过反射调用运行时类的指定的方法
// 3.1 调用无参方法
Method m1=clazz.getMethod("show");
m1.invoke(person);
// 3.2 调用有参方法
Method m2=clazz.getMethod("display",String.class);
m2.invoke(person, "CHN");
} // 在有反射以前,如何创建一个类的对象,并调用其中的方法,属性
@Test
public void test1(){
Person person=new Person();
person.setAge(10);
person.setName("zhangsan");
System.out.println(person);
person.show();
person.display("CN");
}
}

4.反射的源头Class

  4.1 getClass()详解,此方法中Object类中被定义,会被所有的子类继承,调用此方法返回值的类型是一个Class类,此类的反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射出类的名称

  @Test
public void test3(){
Person person=new Person();
Class calzz= person.getClass(); // 通过运行时类的对象,调用其getClass(),返回其运行时类
System.out.println(calzz);
}

  4.2 反射原理解析

    我们创建了一个类,通过编译(javac.exe),生成对应的.class文件,之后我们使用java.exe加载(JVM的类加载器完成的)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存放在缓存区。那么这个运行时类本身就是一个Class的实例!

    4.2.1 每一个运行时类只加载一次

    4.2.2 有了Class的实例以后,我们才可以进行如下操作

        1)创建对应的运行时类的对象

        2)获取对应的运行时类的完整结构(属性,方法,构造器,内部类,父类,所在的包,异常,注解........)

        3) 调用对应的运行时类的指定的结构(属性,方法,构造器)

        4)反射的应用,动态代理

    正常方式:引入需要的“包类”名称->通过new实例化->取得实例化对象

    反射方式:实例化对象->getClass()方法->得到完整的“包类”名称

  4.3 获取Class的实例

    4.3.1 调用运行时类本身的.class属性

    @Test
public void test4(){
// 1.调用运行时类本身的.class属性
Class clazz=Person.class;
System.out.println(clazz.getName());
}

    4.3.2 通过运行时类的对象获取

  @Test
public void test5(){
// 通过运行时类的对象获取
Person person=new Person();
Class clazz= person.getClass();
System.out.println(clazz.getName());
}

    4.3.3 通过Class的静态方法获取

  @Test
public void Test6() throws Exception{
// 通过Class的静态方法获取
String className="day01.code.Person";
Class clazz= Class.forName(className);
System.out.println(clazz.getName());
}

    4.3.4 通过类的加载器

  @Test
public void test7() throws Exception{
// 通过类的加载器
String className="day01.code.Person";
ClassLoader classLoader=this.getClass().getClassLoader();
Class clazz= classLoader.loadClass(className);
System.out.println(clazz.getName());
}

  4.4 什么是类的加载器?(ClassLoader)

     解释:类加载器是用来把类(class)装载进内存的。JVM 规范定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)

    4.4.1 Bootstap Classloader 引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来加载核心类库,该加载器无法直接获取

    4.4.2 Extension Classloader 扩展类加载器:负责jre/lib/ext目录下的jar包或 –D java.ext.dirs 指定目录下的jar包装入工作库 .

    4.4.3 System Classloader 系统类加载器:负责java –classpath 或 –D java.class.path所指的目录下的类与jar包装入工作 ,是最常用的加载器

  4.5 有了Class对象,能做什么?

    4.5.1 newInstance() 作用: 创建对应的运行时类的对象,实际上就是调用类运行时类的空参的构造器。注:要想创建成功,1.要求对应的运行时类要有空参的构造器 2.构造器的权限修饰符的权限要足够(经验证同一个包下大于 private 即可)

  @Test
public void test1() throws Exception{
String className="day01.code.Person";
Class clazz= Class.forName(className);
// 创建运行时对象
Object obj=clazz.newInstance();
Person person=(Person)obj;
System.out.println(person);
}

    4.5.2 通过反射调用类的完整结构(实现的全部接口,所继承的父类,全部的构造器,全部的方法,全部的Field)

      4.5.2.1 Field

  // 获取对应的运行时类的属性
@Test
public void test1(){
Class clazz= Person.class;
// 1.getFields():只能获取到运行时类及其父类中声明为public的属性
Field[] fields=clazz.getFields();
for(int i=0;i<fields.length;i++){
System.out.println(fields[i]);
}
System.out.println();
// 2.getDeclaredFields():获取到运行时类本身声明的所有的属性
Field[] fields1=clazz.getDeclaredFields();
for (Field field : fields1) {
System.out.println(field.getName());
}
} // 权限修饰符 变量类型 变量名,获取属性的各个部分的内容
@Test
public void test2(){
Class clazz= Person.class;
Field[] fields1=clazz.getDeclaredFields();
for (Field field : fields1) {
// 1.获取每个属性的权限修饰符
int i= field.getModifiers();
String modifier= Modifier.toString(i);
System.out.print(modifier+" ");
// 2.获取属性的变量类型
Class type=field.getType();
System.out.print(type.getName()+" ");
// 3.获取属性名
System.out.println(field.getName());
}
}

      4.5.2.2 Method

  // 1.获取运行时类的方法
@Test
public void test1(){
Class clazz=Person.class;
// 1.getMethods():获取运行时类及其父类中所有声明为public的方法
Method[]m1=clazz.getMethods();
for (Method method : m1) {
System.out.println(method);
}
System.out.println();
// 2.getDeclaredMethods():获取运行时类本身声明的所有的方法
Method[]m2=clazz.getDeclaredMethods();
for (Method method : m2) {
System.out.println(method);
}
} // 注解 权限修饰符 返回值类型 方法名 形参列表 异常
@Test
public void test2(){
Class clazz=Person.class;
Method[]m2=clazz.getDeclaredMethods();
for (Method method : m2) {
// 1.注解
Annotation[] ann= method.getAnnotations();
for (Annotation annotation : ann) {
System.out.print(annotation+" ");
}
// 2.权限修饰符
String str= Modifier.toString(method.getModifiers());
System.out.print(str+" ");
// 3.返回值类型
Class returnType=method.getReturnType();
System.out.print(returnType.getName()+" ");
// 4.方法名
System.out.print(method.getName()+" ");
// 5.形参列表
System.out.print("(");
Class[]params=method.getParameterTypes();
for (Class p : params) {
System.out.print(p.getName());
}
System.out.print(")");
// 6.异常类型
Class[]exps= method.getExceptionTypes();
for (Class exp : exps) {
System.out.print(exp.getName()+" ");
}
System.out.println();
}
}

       4.5.2.3 构造器

  // 获取运行时类的构造器
@Test
public void test2()throws Exception{
String className="day01.code.Person";
Class clazz= Class.forName(className);
Constructor[]cons=clazz.getDeclaredConstructors();
for (Constructor constructor : cons) {
System.out.println(constructor);
}
}

        4.5.2.4 其他结构

  // 6.获取注解
@Test
public void test6(){
Class clazz=Person.class;
Annotation[]anns=clazz.getAnnotations();
for (Annotation annotation : anns) {
System.out.println(annotation);
}
} // 5.获取所在的包
@Test
public void test5(){
Class clazz=Person.class;
Package package1=clazz.getPackage();
System.out.println(package1);
} // 4.获取实现的接口
@Test
public void test4(){
Class clazz=Person.class;
Class[] interfaces=clazz.getInterfaces();
for (Class class1 : interfaces) {
System.out.println(class1);
}
} // 3.获取父类的泛型
@Test
public void test3(){
Class clazz=Person.class;
Type type=clazz.getGenericSuperclass();
ParameterizedType param=(ParameterizedType) type;
Type[]ars=param.getActualTypeArguments();
System.out.println(((Class)ars[0]).getName());
} // 2.获取带泛型的父类
@Test
public void test2(){
Class clazz=Person.class;
Type type=clazz.getGenericSuperclass();
System.out.println(type);
} // 1.获取运行时类的父类
@Test
public void test1(){
Class clazz= Person.class;
Class superClass=clazz.getSuperclass();
System.out.println(superClass);
}

    4.5.3 反射的各种操作

      4.5.3.1 调用运行时类指定的属性

  // 调用运行时类中指定的属性
@Test
public void test3() throws Exception{
Class clazz=Person.class;
// 1.获取指定的属性,属性权限是public的
Field name=clazz.getField("name");
// 2.创建运行时类的对象
Person p=(Person)clazz.newInstance();
System.out.println(p);
// 3.将运行时类的指定的属性赋值
name.set(p, "Jerry");
System.out.println(p);
System.out.println();
Field age= clazz.getDeclaredField("age");
// 由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性值可以被操作
age.setAccessible(true);
age.set(p, 10);
System.out.println(p);
}

      4.5.3.2 调用运行时类指定的方法

  // 调用运行时类中指定的方法
@Test
public void test3() throws Exception{
Class clazz=Person.class;
// getMethod(String methodName,Class...params):获取运行时类中声明为public的方法
Method m1=clazz.getMethod("show");
Person person=(Person)clazz.newInstance();
// 可以获取返回值
Object returnVal=m1.invoke(person);
System.out.println(returnVal); Method m2=clazz.getMethod("toString");
Object returnVal2=m2.invoke(person);
System.out.println(returnVal2); // 获取运行时类的静态方法
Method m3=clazz.getMethod("info");
m3.invoke(Person.class);
// getDeclaredMethod(String methodName,Class...params):获取运行时类中定义的方法
Method m4=clazz.getDeclaredMethod("display",String.class,Integer.class);
m4.setAccessible(true);
Object value= m4.invoke(person,"中国",10);
System.out.println(value);
}

      4.5.3.3 调用指定的构造器

  // 调用指定的构造器,创建运行时类的对象
@Test
public void test() throws Exception{
String className="day01.code.Person";
Class clazz= Class.forName(className);
Constructor cons= clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Person person=(Person)cons.newInstance("陆虎",10);
System.out.println(person);
}

    4.5.4 动态代理vs静态代理

      4.5.4.1 静态代理

package day01.code1;

// 静态代理
// 接口
interface ClothFactory{ void productCloth();
} // 被代理类
class NikeClothFactory implements ClothFactory{ @Override
public void productCloth() {
System.out.println("Nike工厂生成一批衣服");
} } // 代理类
class ProxyFactory implements ClothFactory{ ClothFactory cf; public ProxyFactory(ClothFactory cf) {
this.cf=cf;
} @Override
public void productCloth() {
System.out.println("代理类开始执行。。。");
this.cf.productCloth();
} } public class TestClothProduct { public static void main(String[]args){
NikeClothFactory nikeClothFactory=new NikeClothFactory();
ProxyFactory proxyFactory=new ProxyFactory(nikeClothFactory);
proxyFactory.productCloth();
}
}

     4.5.4.2 动态代理

package day01.code1;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; interface Subject{
void action();
}
// 被代理类
class RealSubject implements Subject{ @Override
public void action() {
System.out.println("被代理类方法开始执行");
} }
class MyInvocationHandler implements InvocationHandler{ Object obj;// 实现了接口的被代理类的对象的声明 // 1.给被代理的对象实例化 2.返回一个代理类的对象
public Object blind(Object obj){
this.obj=obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), this);
}
// 当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// method方法的返回值是returnVal
Object returnVal=method.invoke(obj, args);
return returnVal;
} } public class TestProxy { public static void main(String[]args){
// 1.被代理类的对象
RealSubject real=new RealSubject();
// 2.创建一个实现了InvacationHandler接口的类的对象
MyInvocationHandler handler=new MyInvocationHandler();
// 3.调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象
Object object=handler.blind(real);
// 4.此时subject就是代理类的对象
Subject subject=(Subject)object;
// 5.转到对InvocationHandler接口对实现类对invoke()方法的调用
subject.action(); // 再举一例
NikeClothFactory nikeClothFactory=new NikeClothFactory();
// proxyCloth即为代理类的对象
ClothFactory proxyCloth=(ClothFactory)handler.blind(nikeClothFactory);
proxyCloth.productCloth(); }
}

java学习笔记:反射的更多相关文章

  1. Java学习笔记--反射

    什么是Java反射 概念 java反射是指java能够在运行时确定类的类型信息,包括其方法.字段.构造函数等,并能够通过反射调用类或者类对象的方法.在Java中,java.lang.Class类与ja ...

  2. 0034 Java学习笔记-反射-初步2-操作对象

    通过反射创建对象 通过反射创建对象有两种方式,一种通过Class对象的newInstance()方法,一种是获取到Class对象的Constructor后,再调用newInstance()方法,前者要 ...

  3. 0033 Java学习笔记-反射-初步1

    先看看通过反射能干嘛 示例:修改对象的private实例变量 package testpack; import java.lang.reflect.Field; public class Test1 ...

  4. Java学习笔记--反射API

    反射API 1.反射API的介绍 通过反射API可以获取Java程序在运行时刻的内部结构.比如Java类中包含的构造方法.域和方法等元素,并可以与这些元素进行交换.     按照 一般地面向对象的设计 ...

  5. Java 学习笔记 反射与迭代器

    反射 使用反射获得类 Class cls = Class.forName("全类名") //包括包名 Class cls = xx.Class;//xx代表类名 使用反射获得构造方 ...

  6. JAVA 学习笔记 - 反射机制

    1.   JAVA反射机制的概念 2. 怎样实例化一个 Class对象 Class.forName(包名.类名); 对象.getClass(); 类.class; ================== ...

  7. Java学习笔记——反射

    反射就是把Java类中的各种成分映射成相应的java类. Class类-->java程序中的各个java类属于同一事物,描述这类事物的Java类名就是Class. Class.forName的作 ...

  8. Java学习笔记-反射机制

    Java反射机制实在运行状态时,对于任意一个类,都能够知道这个类的属性和方法,对于任意一个对象,都能够调用他的任意一个属性和方法 获取Class对象的三种方式 Object类中的getClass()方 ...

  9. 0035 Java学习笔记-注解

    什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...

  10. JAVA学习笔记—review基本知识[反射与异常]

    JAVA学习笔记—review基本知识[反射与异常] 1.异常: 1.1异常的分类: Java会将所有的异常封装成对象,其根本父类为Throwable. Throwable有两个子类:Error 和E ...

随机推荐

  1. 实用的两款jquery树形tree插件

    这里有两款非常实用的jquery tree控件: (1) ------------------------------------------1.(根据一讲师总结) ---zTree: jquery. ...

  2. [问题]安装express,已经加了-g,还是找不到express命令

    安装express时使用如下命令: npm install -g express 但是在命令行还是找不到express 手动将路径D:\Program Files (x86)\nodejs\node_ ...

  3. 基于.NET的微信SDK

    超级懒汉编写的基于.NET的微信SDK   一.前言 特别不喜欢麻烦的一个人,最近碰到了微信开发.下载下来了一些其他人写的微信开发“框架”,但是被恶心到了,实现的太臃肿啦. 最不喜欢的就是把微信返回的 ...

  4. .NET源码

    值得珍藏的.NET源码,不保存就没机会了 很早以前,我们通过http://referencesource.microsoft.com/netframework.aspx可以下载到.NET的各版本公开源 ...

  5. ThoughtWorks开发持续集成及部署利器:Go

    持续集成及部署利器:Go   Go是一款先进的持续集成和发布管理系统,由ThoughtWorks开发.(不要和Google的编程语言Go混淆了!)其前身为Cruise,是ThoughtWorks在做咨 ...

  6. iOS推送服务细节回顾

    iOS推送服务细节回顾 之前在做推送功能时候,就总结过一系列证书的制作,OC代码实现和服务器搭建等经验.又过了一段时间了,前前后后对推送服务做了多次的完善和优化,有iOS客户端的,还有本地服务器端的. ...

  7. try { var mergeFilePath = string.Format("{0}mergepdf.pdf", tempDownDir); PDFPrintHelper.MergePDFFile(pdfList, mergeFi

    winform 按顺序连续打印多个PDF文件   关于PDF打印的问题,前面有篇文章(点这里查看)也叙述过,今天来谈谈另外一种方法 其实方法很简单,因为需要把多个PDF文档按顺序连续打印,为此我们为什 ...

  8. TFS二次开发、C#知识点、SQL知识

    TFS二次开发.C#知识点.SQL知识总结目录   TFS二次开发系列 TFS二次开发系列:一.TFS体系结构和概念 TFS二次开发系列:二.TFS的安装 TFS二次开发系列:三.TFS二次开发的第一 ...

  9. GC算法精解(五分钟让你彻底明白标记/清除算法)

    GC算法精解(五分钟让你彻底明白标记/清除算法) 相信不少猿友看到标题就认为LZ是标题党了,不过既然您已经被LZ忽悠进来了,那就好好的享受一顿算法大餐吧.不过LZ丑话说前面哦,这篇文章应该能让各位彻底 ...

  10. 记录下自己写的gulp打包脚本

    var c = { rootPath: 'src',//项目文件夹 outputPath: 'output',//文件编译后的输出目录 revPath: 'manifest',//rev映射文件目录 ...