一:介绍

1.大纲

  #1

  允许程序在执行期间,调用反射API取得任何类的内部信息,并且可以直接操作任何对象的内部属性和方法。

  #2

  学习反射,需要掌握的知识点:

    *实例化class类

    *获取类的完整结构

    *通过反射调用类的属性和方法

    *动态代理

2.涉及到的一些API

  java.lang.Class                             类

  java.lang.reflect.Field        属性

  java.lang.reflect.Method      方法

  java.lang.reflect.Constructor    构造器

二:简单反射的小示例(可以直接看后面的内容)

1.新建要反射的类Person

  这个要被反射的类中不含有父类,接口,注解等额外的部分,只是一个特别简单的可以被用来反射的类,用来做演示。

 package demo2;
public class Person1 {
//这里为了说明反射,权限为public
public String name;
//这里为了说明反射,做对比,权限为private
private int age; public Person1() {
super();
}
public Person1(String name) {
super();
this.name = name;
}
public Person1(int age) {
super();
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person1 [name=" + name + ", age=" + age + "]";
}
//两个普通的方法
//不带参数的函数
public void show(){
System.out.println("this is person class");
}
//带参数的函数
public void diaplay(String nation){
System.out.println("contry is "+nation);
} }

2.反射的测试

  这个部分包括建立反射源

  通过反射设置属性

  通过反射调用方法函数

 package demo2;

 import java.lang.reflect.Field;
import java.lang.reflect.Method; public class Test1 { public static void main(String[] args)throws Exception {
reflectMethod();
}
public static void reflectMethod()throws Exception{
//产生对应的类
Class clazz=Person1.class;
Person1 p=(Person1)clazz.newInstance();
System.out.println(p);
System.out.println("-------------------------"); //设置public权限的属性
Field f=clazz.getField("name");
f.set(p, "zhangsan");
System.out.println(p);
System.out.println("-------------------------"); //设置private权限的属性
Field f1=clazz.getDeclaredField("age");
f1.setAccessible(true);//增加访问权限
f1.set(p, 90);
System.out.println(p);
System.out.println("-------------------------"); //调用不带参数的函数方法
Method m=clazz.getMethod("show");
m.invoke(p);
System.out.println("-------------------------"); //调用带参数的函数方法
Method m1=clazz.getMethod("diaplay",String.class);
m1.invoke(p, "China");
}
}

3.运行结果

  

-----------------------------------------------------------------------------------------------#反射重点#---------------------------------------------------------------------------------------------------

三:实现Class类的四种实现方式(所有反射的基础源头---class类的获取)

1.介绍四种方式获取要反射类的class文件

  *用运行时类本身的.class获取

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

  *以class的静态方法获取

  *通过类的加载器获取

2.程序

 package demo2;

 import org.junit.Test;

 public class Test2 {
@Test
public void classMethod() throws ClassNotFoundException{
//通过类的class文件
Class c1=Person1.class;
System.out.println(c1); //通过运行时类的对象获取class文件
Person1 p=new Person1();
Class c2=p.getClass();
System.out.println(c2); //通过class的静态方法
String name="demo2.Person1";
Class c3=Class.forName(name);
System.out.println(c3); //通过类的加载器获得class
ClassLoader classLoader=this.getClass().getClassLoader();
Class c4=classLoader.loadClass(name);
System.out.println(c4);
} }

3.运行结果

  结果看到:四种方式都可以获得class类。

  

四:类的加载器(解释一下上面方式四中类的加载器,次要内容)

1.介绍

  

2.程序验证

 package demo2;
import org.junit.Test;
public class Test3 {
@Test
public void show(){
//systemClassLoader
ClassLoader c1=ClassLoader.getSystemClassLoader();
System.out.println(c1); //ExterSionClassLoader
ClassLoader c2=c1.getParent();
System.out.println(c2); //null(这一个类加载器不会被获取)
ClassLoader c3=c2.getParent();
System.out.println(c3); }
}

3.运行结果

  

4.在方式四种使用的是哪一个加载器(程序验证)

 package demo2;
import org.junit.Test;
public class Test4 {
@Test
public void method(){
String name="demo2.Person1";
ClassLoader classLoader=this.getClass().getClassLoader();
System.out.println(classLoader);
}
}

5.运行结果

  

五:创建运行时类对象(class文件的基础上)

1.要求

  要反射的类中有空参的构造器(最好是这样)

  构造器的权限为public

2.程序实现解释

 package demo2;
public class Test5 {
public static void main(String[] args)throws Exception {
Class c=Person1.class;
Object obj=c.newInstance();
Person1 p=(Person1)obj;
System.out.println(p);
}
}

3.运行结果

  

六:重新构建复杂的即将被反射的类

1.构建复杂的类对象

  包含:

    *父类

    *多接口

    *注解

    *内部类

    *异常

首先是父类:

 package com.at.java;

 public class Creature<T>{
public double weight;
public void breath(){
System.out.println("呼吸");
}
}

自定义接口:

 package com.at.java;

 import java.io.Serializable;
public interface MyInterface extends Serializable{ }

自定义注解:

 package com.at.java;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}

反射的类:

 package com.at.java;

 @MyAnnotation(value = "atguigu")
public class Person extends Creature<String> implements Comparable,MyInterface{
public String name;
private int age;
int id;
public Person() {
super();
}
public Person(String name) {
super();
this.name = name;
}
private Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@MyAnnotation(value = "abc123")
public void show(){
System.out.println("this is person");
} private Integer display(String nation,Integer i) throws Exception{
System.out.println("国籍:" + nation);
return i;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
} public static void info(){
System.out.println("信息");
} class Bird{ } }

七:获取以及调用类的属性

  包括:

    *所有属性的获取

    *指定属性的调用

1.获取对应类运行时的属性

  包括两种;

    *getFields():只能获取到运行时类中及其父类中声明为public的属性

    *getDeclaredFields():获取运行时类本身声明的所有的属性

 package com.at.java;
import java.lang.reflect.Field;
public class Test1 {
public static void main(String[] args){
get1();
System.out.println("###################");
get2();
}
/**
* getFields():只能获取到运行时类中及其父类中声明为public的属性
*/
public static void get1(){
Class clazz=Person.class;
Field[] f=clazz.getFields();
for(int i=0;i<f.length;i++){
System.out.println(f[i].getName());
}
}
/**
* getDeclaredFields():获取运行时类本身声明的所有的属性
*/
public static void get2(){
Class clazz=Person.class;
Field[] f=clazz.getDeclaredFields();
for(Field ff:f){
System.out.println(ff.getName());
}
}
}

2.运行结果

  使用###进行将两种方式进行隔离。

  

3.获取对应类运行时的属性的各个部分的内容

  主要包括:

    *权限

    *变量名

    *变量名

 package com.at.java;

 import java.lang.reflect.Field;
import java.lang.reflect.Modifier; public class Test2 { public static void main(String[] args) {
get2(); }
/**
* getDeclaredFields():获取运行时类本身声明的所有的属性的各个部分
*/
public static void get2(){
Class clazz=Person.class;
Field[] f=clazz.getDeclaredFields();
for(Field ff:f){
//属性权限
int num=ff.getModifiers();
String str=Modifier.toString(num);
System.out.print(str+"\t"); //属性类型
Class type=ff.getType();
System.out.print(type.getName()+"\t"); //属性变量名
System.out.println(ff.getName());
}
} }

4.运行结果

  

5.调用设置指定属性

  注意点事权限问题

 package com.at.java;

 import java.lang.reflect.Field;

 public class Test6 {
public static void main(String[] args)throws Exception {
Class clazz=Person.class;
/**
* 属性权限为public
*/
Field name = clazz.getField("name");
Person p = (Person)clazz.newInstance();
//将运行时类的指定的属性赋值
name.set(p,"Jerry");
System.out.println(p);
//将运行时类的指定的属性赋值后再取出
System.out.println("name="+name.get(p)); System.out.println("########################");
/**
* 属性权限为private
*/
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);//由于属性权限修饰符的限制,需要在操作前使得此属性可被操作。
age.set(p,10);
System.out.println(p); System.out.println("#######################");
/**
* 属性的权限为默认default
* 这个set时不需要setAccessible(true)。
*/
Field id = clazz.getDeclaredField("id");
id.set(p,3);
System.out.println(p);
}
}

6.运行结果

  

八:获取与调用对应类运行时的方法

  包括两种:

    *获取所有方法

    *调用指定方法

1.获取对应类运行时的方法

  包括两种:

    *getMethods():获取运行时类及其父类中所有的声明为public的方法

    *getDeclaredMethods():获取运行时类本身声明的所有的方法

 package com.at.java;
import java.lang.reflect.Method;
public class Test3 {
public static void main(String[] args) {
get1();
System.out.println("#############");
get2();
}
/**
* getMethods():获取运行时类及其父类中所有的声明为public的方法
*/
public static void get1(){
Class clazz=Person.class;
Method[] m=clazz.getMethods();
for(Method mm: m){
System.out.println(mm.getName());
}
}
/**
* getDeclaredMethods():获取运行时类本身声明的所有的方法
*/
public static void get2(){
Class clazz=Person.class;
Method[] m=clazz.getDeclaredMethods();
for(Method mm:m){
System.out.println(mm.getName());
}
}
}

2.运行结果

  

3.获取对应类运行时的方法的各个部分

  包括:

    *注解

    *权限

    *返回类型

    *方法名

    *参数列表

    *异常类型

 package com.at.java;

 import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier; public class Test4 { public static void main(String[] args) {
get2();
}
/**
* 注解 权限修饰符 返回值类型 方法名 形参列表 异常
*/
public static void get2(){
Class clazz = Person.class;
Method[] m2 = clazz.getDeclaredMethods();
for(Method m : m2){
//1.注解
Annotation[] ann = m.getAnnotations();
for(Annotation a : ann){
System.out.println(a);
} //2.权限修饰符
String str = Modifier.toString(m.getModifiers());
System.out.print(str + " "); //3.返回值类型
Class returnType = m.getReturnType();
System.out.print(returnType.getName() + " "); //4.方法名
System.out.print(m.getName() + " "); //5.形参列表
System.out.print("(");
Class[] params = m.getParameterTypes();
for(int i = 0;i < params.length;i++){
System.out.print(params[i].getName() + " args-" + i + " ");
}
System.out.print(")"); //6.异常类型
Class[] exps = m.getExceptionTypes();
if(exps.length != 0){
System.out.print("throws ");
}
for(int i = 0;i < exps.length;i++){
System.out.print(exps[i].getName() + " ");
}
System.out.println();
}
}
}

4.运行结果

  

5.调用指定方法

 package com.at.java;
import java.lang.reflect.Method;
public class Test7 {
public static void main(String[] args) throws Exception{
Class clazz = Person.class;
Person p = (Person)clazz.newInstance();
/**
* public
*/
Method m1 = clazz.getMethod("show");
Object returnVal = m1.invoke(p);
System.out.println(returnVal); //因为返回值为void,所以打印为null Method m2 = clazz.getMethod("toString");
Object returnVal1 = m2.invoke(p); //因为返回值为string,所以这样调用不会有什么现象
System.out.println(returnVal1); //没有现象,所以打印就是打印返回值 /**
* private
* 同时,这是带参数的函数
*/
Method m4 = clazz.getDeclaredMethod("display",String.class,Integer.class);
m4.setAccessible(true);
Object value = m4.invoke(p,"CHN",10);
System.out.println(value); /**
* static 方法,单独提出来
*/
Method m3 = clazz.getMethod("info");
m3.invoke(Person.class);
}
}

6.运行结果

  

九:获取构造器

  包括:

    *所有的构造器

    *调用指定的构造器

1.获取所有的构造器

 package com.at.java;
import java.lang.reflect.Constructor;
public class Test8 {
public static void main(String[] args) throws Exception{
String className = "com.at.java.Person";
Class clazz = Class.forName(className);
/**
* 获取所有的构造器
*/
Constructor[] cons = clazz.getDeclaredConstructors();
for(Constructor c : cons){
System.out.println(c);
}
}
}

2.运行结果

  

3.调用指定的构造器

 package com.at.java;
import java.lang.reflect.Constructor;
public class Test9 {
public static void main(String[] args)throws Exception{
String className = "com.at.java.Person";
Class clazz = Class.forName(className);
/**
* 调用String,int的构造器
*/
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Person p = (Person)cons.newInstance("罗伟",20);
System.out.println(p);
}
}

4.运行结果

  

十:获取其他的内容(父类,接口,注解,包,)

1.程序

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

2.运行结果

  

十一:动态代理

1.静态代理

 /**
* 静态代理模式
*/
package com.at.java1;
//接口
interface ClothFactory{
void productCloth();
} //被代理类
class NikeClothFactory implements ClothFactory{
@Override
public void productCloth() {
System.out.println("Nike");
}
public void productCloth2() {
System.out.println("Nike2");
}
} //代理类
class ProxyFactory implements ClothFactory{
//引用
ClothFactory cf;
public ProxyFactory(ClothFactory cf){ //创建代理类的对象时,实际传入一个被代理类的对象
this.cf = cf;
} @Override
public void productCloth() {
System.out.println("一共$1000");
cf.productCloth(); //实际在代理类中执行的还是被代理类的方法
} } public class TestClothProduct {
public static void main(String[] args) {
NikeClothFactory nike = new NikeClothFactory();
ProxyFactory proxy = new ProxyFactory(nike); //将被代理类传入代理类中
proxy.productCloth();
}
}

2.运行结果

  

3.动态代理

 /**
* 动态代理
*/
package com.at.java1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//接口
interface Subject {
void action();
}
//被代理类
class RealSubject implements Subject {
public void action() {
System.out.println("我是被代理类,记得要执行我哦!");
}
} //代理类
//动态代理都要实现接口InvocationHandler
class MyInvocationHandler implements InvocationHandler {
Object obj;
//①给被代理的对象实例化②返回一个代理类的对象
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 {
Object returnVal = method.invoke(obj, args);
return returnVal;
}
} public class TestProxy {
public static void main(String[] args) {
RealSubject real = new RealSubject();
MyInvocationHandler handler = new MyInvocationHandler();
//动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象。
Object obj = handler.blind(real);
Subject sub = (Subject)obj;
sub.action();
}
}

4.运行结果

  

十二:动态代理与静态代理的区别

  2017.12.21,今天查看了一下他们之间的区别,在这篇文章中解释的挺好的,就没有重新整理,直接粘贴一下链接。

  http://blog.csdn.net/hejingyuan6/article/details/36203505。

  在这篇文章中,这一段比我上面的程序写的更好理解:

  

  

java 的反射机制的更多相关文章

  1. Java 类反射机制分析

    Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...

  2. java的反射机制

    一.java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动, ...

  3. Java中反射机制和Class.forName、实例对象.class(属性)、实例对象getClass()的区别

    一.Java的反射机制   每个Java程序执行前都必须经过编译.加载.连接.和初始化这几个阶段,后三个阶段如下图:   其中

  4. java笔记--反射机制之基础总结与详解

    一.反射之实例化Class类的5种方式: java的数据类型可以分为两类,即引用类型和原始类型(即基本数据类型). 对于每种类型的对象,java虚拟机会实例化不可变的java.lang.Class对象 ...

  5. JAVA的反射机制学习笔记(二)

    上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了.自己的步伐全然被打乱了~不能继续被动下去.得又一次找到自己的节奏. 4.获取类的Constructor 通过反射机制得到 ...

  6. java笔录---反射机制(1)

    引言   为了方便记忆java的反射机制,在这里仔细的总结了一下.主要是怕以后忘记了,这样也方便回忆.因为最近利用空余时间深入的了解spring和Mybatis框架,   像spring中核心模块IO ...

  7. Java高新技术 反射机制

     Java高新技术 反射机制 知识概要:                   (1)反射的基石 (2)反射 (3)Constructor类 (4)Field类 (5)Method类 (6)用反射方 ...

  8. java的反射机制浅谈(转)

    原文链接:java的反射机制浅谈 一.java的反射机制浅谈 1.何谓反射机制 根据网文,java中的反射机制可以如此定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性 ...

  9. 【转】Java利用反射机制访问私有化构造器

    Java利用反射机制访问私有化构造器 博客分类: java   我们都知道,当一个类的构造方法被设为私有的时候(private),在其他类中是无法用new来实例化一个对象的. 但是有一种方法可以把带有 ...

  10. 【转】java原理—反射机制

    一.什么是反射:反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语言 ...

随机推荐

  1. js中全局变量修改后的值不生效【jsp页面中各个js中内容的加载顺序】

    一个老项目中,一个jsp文件中有很多个js文件, 现在要在页面上的一个地方判断一个状态,因为一直找不到原来是在哪里修改的那个状态,所以决定不找了,而是在比较靠前引入的一个js中定义一个全局变量,然后在 ...

  2. spring的controller默认是单例还是多例

    转: spring的controller默认是单例还是多例 先看看spring的bean作用域有几种,分别有啥不同. spring bean作用域有以下5个: singleton:单例模式,当spri ...

  3. gulpfile.js不断更新中...

    Gulp压缩合并js/css文件,压缩图片,以及热更新教程 var gulp = require('gulp');var concat = require('gulp-concat');//- 多个文 ...

  4. 如何通过卡面标识区分SD卡的速度等级

    现在很多设备都可以插存储卡,而比较流行的就是SD(Secure Digital Memory Card)卡和Micro SD(原名TF,Trans-flash Card )卡,这两种卡主要就是尺寸不同 ...

  5. Codeforces #55D-Beautiful numbers (数位dp)

    D. Beautiful numbers time limit per test 4 seconds memory limit per test 256 megabytes input standar ...

  6. SQL语句(十四)子查询

    --1. 使用IN关键字 --例1 查询系别人数不足5人的系别中学生的学号.姓名和系别 --系别人数不足5人的系别 ==>选择条件 select Sdept from Student Group ...

  7. Brief History of Machine Learning

    Brief History of Machine Learning My subjective ML timeline Since the initial standpoint of science, ...

  8. nginx php上传大文件的设置(php-fpm)

    对于lnmp架构的大文件上传的问题,有几个地方需要修改,另外还有几个参数如果更改过需要注意,下面是详细的需要注意的地方: nginx的修改              send_timeout    6 ...

  9. 仿QQ聊天图文混排流程图【适用于XMPP】

      图文混排流程图.graffle4.8 KB   下面附上图片素材: 表情.zip692.5 KB     下面是字符串与图片的详细对应关系:                 "[呲牙]& ...

  10. 数链剖分(Housewife Wind )

     题目链接:https://vjudge.net/contest/279350#problem/B 题目大意:给你n,q,s.n指的是有n个点,q代表有q次询问,s代表的是起点.然后接下来会有n-1条 ...