一、概念
java加载class文件分两种情况:
(1)类型是编译器已知的,这种文件的.class文件在编译的时候,编译器会把.class文件打开(不加载)检查,称为Run- Time Type Identification 运行时类型识别
(2)从其它地方获取引用,然后动态的把这个未知类型的引用的对象的.class文件加载进jvm虚拟机里,称为反射;

在运行状态中,动态获取类信息(属性、方法)及动态调用类对象方法的功能称为java的反射机制。

二、反射API
Java反射包:java.lang.reflect.*
1、获取类
首先获取类,获取到类之后,Class类提供了很多获取类属性,方法,构造方法的api
(1)obj.getClass(),这个是Object类里面的方法;
(2)User.Class属性,任何的数据类型,基本数据类型或者抽象数据类型,都可以通过这种方式获取类;
(3)Class.forName(""),Class类提供了这样一个方法,让我们通过类名来获取到对象类,使用最多;

package reflect;

import reflect.test.model.User;

public class Main {

    public static void main(String[] args) throws ClassNotFoundException {

        //1.通过Object类里面的方法getClass()
User u = new User();
Class c = u.getClass();
System.out.println(c);//class reflect.test.model.User //2通过.Class属性
Class c2 = User.class;
System.out.println(c2);//class reflect.test.model.User //3.Class.forName("全路径名")
Class c3 = Class.forName("reflect.test.model.User");
System.out.println(c3);//class reflect.test.model.User
}
}

2、获取属性和方法

package reflect.test.model;

public class User {

    private String name;

    private int age;

    public User() {}
public User(String name,int age) {
this.name = name;
this.age = age;
} public int a = 100; private String str = "123456789"; public boolean dosomething(Integer a,Float b) {
System.out.println("dosomething");
return true;
} }
package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier; public class Main2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException { /************************获取所有的属性************************/
Class<?> c = Class.forName("reflect.test.model.User");
//getDeclaredFields 获取所有的属性
Field[] fs = c.getDeclaredFields(); // 定义可变长的字符串,用来存储属性
StringBuffer sb = new StringBuffer();
// 通过追加的方法,将每个属性拼接到此字符串中
// 最外边的public定义
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() + "{\n");
// 里边的每一个属性
for (Field field : fs) {
sb.append("\t");// 空格
sb.append(Modifier.toString(field.getModifiers()) + " ");// 获得属性的修饰符,例如public,static等等
sb.append(field.getType().getSimpleName() + " ");// 属性的类型的名字
sb.append(field.getName() + ";\n");// 属性的名字+回车
} sb.append("}"); System.out.println(sb); /***************************获取指定属性***********************/ //获取id属性
Field idF = null;
try {
idF = c.getDeclaredField("age");
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
//实例化这个类赋给o
Object o = null;
try {
o = c.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
//打破封装
idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
//给o对象的id属性赋值"110"
try {
//set
idF.set(o,110);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
//get
try {
System.out.println(idF.get(o));
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
} /***************************获取方法****************************/ //getDeclaredMethods() 获取所有的方法(不包含构造方法)
Method[] declaredMethods = c.getDeclaredMethods();
for (Method m:declaredMethods) {
System.out.println(m);
//getReturnType() 获得方法的放回类型
System.out.println(m.getReturnType());
//getParameterTypes() 获得方法的传入参数类型
Class<?>[] parameterTypes = m.getParameterTypes();
for(Class cc : parameterTypes) {
System.out.println(cc);
}
} //getDeclaredMethod("方法名",参数类型.class,……) 获得特定的方法
Method declaredMethod = c.getDeclaredMethod("dosomething", Integer.class,Float.class);
System.out.println(declaredMethod);
Method method = c.getMethod("dosomething", Integer.class,Float.class);
System.out.println(method);
//getDeclaredConstructors() 获取所有的构造方法
Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
for(Constructor ccc : declaredConstructors) {
System.out.println(ccc);
}
//getDeclaredConstructor(参数类型.class,……) 获取特定的构造方法
Constructor<?> declaredConstructor = c.getDeclaredConstructor(String.class,int.class);
System.out.println(declaredConstructor);
//getSuperclass() 获取某类的父类
Class<?> superclass = c.getSuperclass();
System.out.println(superclass);
//getInterfaces() 获取某类实现的接口
Class<?>[] interfaces = c.getInterfaces();
for(Class cccc: interfaces) {
System.out.println(cccc);
} } }

结果:

public class User{
private String name;
private int age;
public int a;
private String str;
}
110
public boolean reflect.test.model.User.dosomething(java.lang.Integer,java.lang.Float)
boolean
class java.lang.Integer
class java.lang.Float
public boolean reflect.test.model.User.dosomething(java.lang.Integer,java.lang.Float)
public boolean reflect.test.model.User.dosomething(java.lang.Integer,java.lang.Float)
public reflect.test.model.User()
public reflect.test.model.User(java.lang.String,int)
public reflect.test.model.User(java.lang.String,int)
class java.lang.Object

三、反射应用--动态代理

package reflect.test.intf;

public interface Interface {

    public void dosomething() ;
}
package reflect.test.intf.impl;

import reflect.test.intf.Interface;

public class InterfaceImpl implements Interface {

    @Override
public void dosomething() {
System.out.println("dosomething");
} }

1、静态代理

package reflect;

import reflect.test.intf.Interface;
import reflect.test.intf.impl.InterfaceImpl; /**
* 静态代理
*/
public class HandProxy implements Interface{ Interface inter = new InterfaceImpl(); @Override
public void dosomething() {
System.out.println("静态代理类");
inter.dosomething();
} }
package reflect;

public class TestHandProxy {

    public static void main(String[] args) {

        HandProxy p = new HandProxy();
p.dosomething();
} }
结果:
静态代理类
dosomething

2、动态代理

package reflect;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; /**
* 动态代理
*/
public class AutoProxy implements InvocationHandler{
private Object target; public Object bind(Object target) {
this.target = target;
/**
* 第一个是被代理类的类构造器,
* 第二个指的是被代理类的接口,也就是Interface接口,
* 第三个是实现这个代理的类,这里就是本类。
* 这个方法执行了下面三步:
1.生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码,然后用参数里的classLoader加载这个代理类。
2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler的子类传入。
3.返回这个代理类实例,因为我们构造的代理类实现了interfaces(也就是我们程序中传入的target.getClass().getInterfaces())里的所有接口,因此返回的代理类可以强转成Interface类型来调用接口中定义的方法。
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("动态代理");
result = method.invoke(target, args);
System.out.println("动态代理执行结束");
return result;
} }
package reflect;

import reflect.test.intf.Interface;
import reflect.test.intf.impl.InterfaceImpl; public class TestAutoProxy { public static void main(String[] args) {
Interface inter = new InterfaceImpl();
AutoProxy ap = new AutoProxy();
Interface obj = (Interface)ap.bind(inter);
obj.dosomething();
} }

结果:

动态代理
dosomething
动态代理执行结束

【Java语言特性学习之二】反射的更多相关文章

  1. 【Java语言特性学习之一】设计模式

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...

  2. 【Java语言特性学习之六】扩展知识点

    一.SPI机制 二.注解处理机制 三.java native关键字 https://www.cnblogs.com/KingIceMou/p/7239668.html

  3. 【Java语言特性学习之三】Java4种对象引用

    为了更灵活的控制对象的生命周期,在JDK1.2之后,引用被划分为(引用的级别和强度由高到低)强引用.软引用.弱引用.虚引用四种类型,每种类型有不同的生命周期,它们不同的地方就在于垃圾回收器对待它们会使 ...

  4. 【Java语言特性学习之四】常用集合

    java中常见的数据结构

  5. 【Java语言特性学习之五】版本差异新特性

  6. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  7. java语言特性概述

    一.前言 我们都知道java是面向对象的编程,其中四个基本特性:抽象.封装.继承.多态.这四个特性,概括起来可以这么理解,抽象.封装.继承是多态的基础,多态是抽象.封装.继承的表现. 二. JAVA ...

  8. [原]Java修炼 之 基础篇(一)Java语言特性

    学习软件开发,首先要选择的就是选择需要采用的编程语言,考虑语言本身的优缺点和实际需求,综合评价之后选择相关的语言进行系统开发.本篇博客开始就从近年来比较流行的Java开始为大家讲起. 背景 1995年 ...

  9. Java 语言特性

    介绍以下几种语言特性: Java5的特性 1.静态引用 2.可变参数 3.自动装箱和拆箱  包装类的缓存设计 4.枚举 一.静态引用(语法糖,不推荐使用,了解一下即可) 先看看普通的引用,就是impo ...

随机推荐

  1. PHPer的项目RESTful API设计规范是怎样的?

    RESTful 是目前最流行的 API 设计规范,用于 Web 数据接口的设计. 什么是RESTful RESTful是一种软件设计风格, 主要用于客户端与服务端交互的软件. 一般来说RESTful ...

  2. javascript 模块化 (切记:学习思想)

    模块化(切记:学习思想) 如果不用模块化编写代码,那么会具有以下问题: 代码杂乱无章,没有条理性,不便于维护,不便于复用 很多代码重复.逻辑重复 全局变量污染 不方便保护私有数据(闭包) 模块化的基本 ...

  3. 第一章 1.18 re模块

    方法使用 1. compile(正则表达式) - 编译创建正则表达式对象 re_obj = re.compile(r'\d{3}') re_obj.fullmatch('234') re.fullma ...

  4. 【计算机网络】HTTPS协议的传输细节及过程分析

    1. 介绍一下HTTPS协议? 1.1 基本概念 http默认采用80作为通讯端口,对于传输采用不加密的方式,https默认采用443,对于传输的数据进行加密传输. 1.2 密码学基础 明文: 明文指 ...

  5. clientHeight—scrollHeight—offsetHeight三者的区别

    clientHeight,scrollHeight,offsetHeight 这三个dom属性有时让人觉得相似但又不相似 以前对它们的理解也有一些模糊,现在总结一下,方便以后复习 clientHeig ...

  6. LinqMethod 实现 LeftJoin

    LinqMethod 实现 LeftJoin Intro 有时候我们想实现 leftJoin 但是 Linq 提供的 Join 相当于是 INNER JOIN,于是就打算实现一个 LeftJoin 的 ...

  7. python爬虫三大解析库之XPath解析库通俗易懂详讲

    目录 使用XPath解析库 @(这里写自定义目录标题) 使用XPath解析库 1.简介   XPath(全称XML Path Languang),即XML路径语言,是一种在XML文档中查找信息的语言. ...

  8. CTF 入门笔记

    站点:http://www.moctf.com/ web1:水题非常简单的题目,直接F12查看元素即可,在HTML代码中,flag被注释了. web2:水题 该题的核心 就是通过HTML代码对输入框进 ...

  9. 【LeetCode】1056-易混淆数

    易混淆数 给定一个数字 N,当它满足以下条件的时候返回 true:把原数字旋转180°以后得到新的数字.如 0, 1, 6, 8, 9 旋转 180° 以后,得到了新的数字 0, 1, 9, 8, 6 ...

  10. js 判断当前时间是否处于某个一个时间段内

    js 判断当前时间(或者所选时间)是否在某一时间段 我们可以使用 jutils - JavaScript常用函数库的 isDuringDate 函数来实现 传入 beginDateStr (开始时间) ...