【Java语言特性学习之二】反射

一、概念
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
动态代理执行结束

原文地址:https://www.cnblogs.com/cac2020/p/11996790.html

时间: 2024-10-06 20:46:35

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

【Java语言特性学习之四】JUC

一.JUC 简介 在Java5.0提供了java.util.concurrent(简称JUC)包,在此包中增加了并发编程常用工具类,包括线程池,异步IO和轻量级任务框架;还提供了设计用于多线程上下文中的Collection实现等.目的就是为了更好的支持高并发任务,让开发者利用这个包进行的多线程编程时可以有效的减少竞争条件和死锁线程. 按照功能可以大致划分如下:juc-locks 锁框架juc-atomic 原子类框架juc-sync(tools) 同步器框架juc-collections 集合框

Java Nio 特性学习(一)

Java NIO 特性学习 Java NIO 包含几个核心的组件: Channels Buffer Selectors Channels 可以理解为资源的一个流,通过这个流资源可以从Channel读取Data到一个Buffer中或者从一个Buffer中写入Data到Channel: Channel Implementations 集中Jdk7常用的Channel上线 FileChannel : 操作文件读取或者写入数据 DatagramChannel : 从一个网络UDP连接中读取或写入数据 S

Java语言编程学习之Lambda表达式设计和架构的原则[图]

Java语言编程学习之Lambda表达式设计和架构的原则[图]:大家都知道,Lambda表达式是对Java语言的一点简单改进,在JDK标准类库中,运行它的方式各种各样.但是大多数的Java代码都不是由开发JDK的程序猿写的,而是像我们这样的普通程序猿.很多人都会碰到过这样的情况:你实现了一个新功能或修复了一个缺陷,并且对自己的修改很满意.但其他人看了你的代码后--也许发生在代码审查环节,完全不买账!对于什么是好代码,什么是坏代码,存在分歧很正常!设计模式的改变设计模式是人们熟悉的另一种设计思想,

java语言特性概述

一.前言 我们都知道java是面向对象的编程,其中四个基本特性:抽象.封装.继承.多态.这四个特性,概括起来可以这么理解,抽象.封装.继承是多态的基础,多态是抽象.封装.继承的表现. 二. JAVA 语言特点    a) 跨平台,一次编译,到处运行.    b) 速度慢,但很稳定, 没有内存泄漏 (memory leakage),不容易出现错误.    c) 不适合对速度要求高的图形界面操作, 适合服务端应用.    C/S (Client/Server) -> B/S (Browser/Ser

Java语言特性详解

Java语言是一个支持网络计算的面向对象程序设计语言.Java语言吸收了Smalltalk语言和C++语言的优点,并增加了其它特性, 如支持并发程序设计.网络通信.和多媒体数据控制等.主要特性如下:        1) Java语言是简单的  Java语言的语法与C语言和C++语言很接近,使得大多数程序员很容易学习和使用Java.另一方面,Java丢弃了C++ 中很少使用的.很难理解的.令人迷惑的那些特性, 如操作符重载.多继承.自动的强制类型转换.特别地,Java语言不使用指针,并提供了自动的

Java语言中学习数组、运算符、流程控制的一些理解

一.数组 1.数组的概念及作用 数组是相同数据类型的元素的集合:   数组本身是引用数据类型,即对象.但是数组可以存储基本数据类型,也可以存储引用数据类型. 例如: int [] a = new int [] {1,2,3,4,5,6,}; String [] s = new String [] {"小兔","小小兔","小小小兔",} : Employee [] e = Employee [10];(Employee是自定义类). 2.数组的声

Java语言的学习

众所周知,Java是上个世纪的语言产物,到现在已经有多个分支,Java和OC.Swift一样都是面向对象的语言,目前学习Java是想接触一下后台的开发,当然iOS也不会丢掉,毕竟多学一点不是坏事. 今天遇到了这样一个情况,在写if判断的时候,在括号的后面加了分号,如下: int c = 100; if ( c != 100); { System.out.println("开始"); } 按理说括号里的内容是不会被打印的,但是结果是打印了,原因是在括号的后面加上了分号,编译器会认为这是结

《深入理解Java虚拟机》学习笔记(二)

垃圾回收的前提是判断对象是否存活,对象不再存活时将会被回收,下面是2种判断的方法. 引用计数法: 主流的Java虚拟机并没有使用引用计数法来管理内存,重要的原因就是循环引用的问题难以解决. 可达性分析法: 这个算法的基本思路是:通过一系列称为“GC Roots”的对象作为起始点,向下搜索,走过的路径称为引用链,当对象到GC Roots没有任何的引用链时,则认为对象是可以被回收的. Java中,可以作为GC Roots的对象包括: 1>虚拟机栈中引用的对象 2>方法区中静态属性引用的对象 3&g

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

java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新的解析一次, 第二种,即时解析,也就是转载到内存的字节码会被解析成本地机器码,并缓存起来以提高重用性,但是比较耗内存, 第三种,自适应优化解析,即将java将使用最贫乏的代码编译成本地机器码,而使用不贫乏的则保持字节码不变,一个自适应的优化器可以使得java虚拟机在80%-90%的时间里执行优化过的