一、概念
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. Linux 部署 nginx

    nginx搭建 1. 清除之前nginx环境 #查看nginx进程 ps -ef|grep nginx #找到nginx相对应的位置 whereis nginx #停止nginx服务 /usr/loc ...

  2. Linux目录结构-下部

    第1章 /etc目录 1.1 /etc/inittab 1.1.1 查看当前系统的运行级别 [root@nfsnobody ~]# runlevel N 3##查看系统当前运行级别 后面的数字表示当前 ...

  3. Docker容器 MySQL中文乱码解决方案

    docker exec进入容器 sudo docker exec -it 588340b778f6 bash 执行以下命令,将 character-set-server=utf8 写入mysql配置文 ...

  4. 百度ai语音识别

    //语音识别功能 var APP_ID = "149**323"; var API_KEY = "N1Po****o6WPUeU8er"; var SECRET ...

  5. 你见过的最全面的 Python 重点

    由于总结了太多的东西,所以篇幅有点长,这也是我"缝缝补补"总结了好久的东西. Py2 VS Py3 print成为了函数,python2是关键字 不再有unicode对象,默认st ...

  6. 工具类ToastUtil 避免在子线程中使用抛异常 "Can't create handler inside thread that has not called Looper.prepare()"

    package com.example.kbr.utils; import android.view.Gravity; import android.widget.Toast; import io.r ...

  7. 【LeetCode】70. 爬楼梯

    爬楼梯 假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意: 给定 n 是一个正整数. 示例 1: 输入: 2 输出: 2 解 ...

  8. CGROUP九大子系统

    blkio -- 这个子系统为块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB 等等). cpu -- 这个子系统使用调度程序提供对 CPU 的 cgroup 任务访问. cpuacct ...

  9. svn 在Windows下用TortoiseSVN checkout 时报认证错误

    TortoiseSVN 第一次 checkout(检出)时,需要输入用户名密码,如果第一次你保存了你的用户名密码,那么这个检出的项目以后就会用这个用户名密码,如果你的密码改了之后,就会报一个认证错误的 ...

  10. 1、mongoDB服务器的搭建与连接

    下载----编译----安装之后: 1.首先,创建一个mongodb_simple的目录,进入到目录中. 2.创建文件夹:data,用来存储数据库的数据文件. 3.创建文件夹:log,用来存储数据库的 ...