博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java反射简解
阅读量:5248 次
发布时间:2019-06-14

本文共 5719 字,大约阅读时间需要 19 分钟。

1、首先一个问题,什么是类,类是不是对象?

我们总是说我们new一个对象出来

那么我们还没有new的时候,建造的那个java类是不是对象呢?

它是java.lang.Class的对象

 

对于反射我们首先要知道的就是什么是Class类

java.lang.Class到底是什么,有啥用。

首先我们要得到Class,我们有三种可以得到的方法,代码如下,c1,c2,c3就是我们需要的Class

//任何一个类都有一个隐含的成员变量叫做calssClass c1 = Man.class;        //通过对象的getClass方法获取classClass c2 = man1.getClass();        //c1和c2表示了Man的类类型,也就是class type        Class c3 = null;c3 = Class.forName("com.clazz.test.Man");

 

需要知道的是类的类类型是一样的,都指的是一个,所以c1,c2,c3都是一样的。都是相等的。

那我们现在已经拿到了Class,可以用它来干嘛呢?

我们可以通过类的类类型直接创建一个对象,也就是说,没有new了。

需要注意的是下面的代码中newInstance方法会调用类的无参构造方法

//通过类的类类型创建对象。Man man2 = (Man) c1.newInstance();

下面是所有的测试代码

package com.clazz.test;/** * Class类的描述测试 * @author XX * */public class ClazzDemo1 {    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException    {        //Man是java.lang.Class的对象        //任何一个类都是class类的实例对象                Man man1 = new Man();        //man1是Man类的实例对象                //任何一个类都有一个隐含的成员变量叫做calss        Class c1 = Man.class;                //通过对象的getClass方法获取class        Class c2 = man1.getClass();                //c1和c2表示了Man的类类型,也就是class type                Class c3 = null;        c3 = Class.forName("com.clazz.test.Man");                //通过类的类类型创建对象。        Man man2 = (Man) c1.newInstance();    }}class Man{    public Man(){        System.out.println("创建了这个类");    }}

 

 

2、静态加载类和动态加载类

new创建对象是静态加载,在编译时刻就需要加载所有可能使用到的类。

通过动态加载类,可以在运行时刻加载使用到的类

也就是我们的c3使用的方法

package com.clazz.test;public class DynamicLoadClass {    public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException    {        //静态加载类,直接new出对象,调用方法,一般都是使用这个,但是一旦没有Student类,编译就会报错        //而且如果需要使用老师对象那么代码需要重新写过很多,要把new对象重新写过,        Student s1 = new Student();        s1.speck();                //通过动态加载类,编译时刻,无论学生还是老师类存不存在,都可以编译通过,只有当运行时刻才进行加载        //好处是如果你需要新增一个类,直接实现IPeople接口,只要forName的名字正确即可,而且这个名字可以        //作为一个参数传进来然后进行修改        Class c1 = Class.forName("com.clazz.test.Student");        IPeople p1 = (IPeople) c1.newInstance();        p1.speck();    }}
package com.clazz.test;public class Student implements IPeople{    public void speck()    {        System.out.println("我是学生");    }}
package com.clazz.test;public interface IPeople {    public void speck();}

 

3通过反射拿到一个类的所有的信息

下面这个就是反射最基本的用法,也是反射最神奇的地方

package com.clazz.util;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import com.clazz.test.Student;/** * calss类的测试工具类 * @author XX * */public class ClazzUtil {    public static void main(String args[])    {        //通过反射能拿到类的所有方法信息        printAll(new Student());    }        /**     * 获取这个对象的信息并打印出来     */    public static void printAll(Object object)    {        Class c = object.getClass();                //打印该类的名字        System.out.println("类的名字" + c.getName());                //打印该类的所有方法(包含从父类继承来的)(不包含私有的方法)        Method[] ms = c.getMethods();        for (Method method : ms) {            System.out.println("方法:" + method.getName() + "          方法的返回值:" + method.getReturnType().getName());                        //获取方法的参数            Class
[] par = method.getParameterTypes(); for (Class
class1 : par) { System.out.println("方法的入参:" + class1.getName()); } } //打印该类的方法(不包含从父类继承来的)包含私有方法 Method[] ms2 = c.getDeclaredMethods(); for (Method method : ms2) { System.out.println("方法1:" + method.getName() + " 方法的返回值:" + method.getReturnType().getName()); } //获取成员变量(不包含私有变量) Field[] fs = c.getFields(); for (Field field : fs) { System.out.println("成员变量: " + field.getName()); } //获取成员变量(包含私有变量) Field[] fs1 = c.getDeclaredFields(); for (Field field : fs1) { System.out.println("成员变量: " + field.getName()); } //获取构造方法 Constructor[] con = c.getDeclaredConstructors(); for (Constructor constructor : con) { System.out.println("构造方法:" + constructor.getName()); } }}
package com.clazz.test;public class Student implements IPeople{    private int a1;    public int a12;        public void speck()    {        System.out.println("我是学生");    }        private void speck2()    {        System.out.println("我是学生");    }}

 

4通过反射调用类的方法

这个是反射的应用,通过反射调用一个类的方法

package com.clazz.test;import java.lang.reflect.Method;/** * @author XX * */public class ReflectMethod {    public static void main(String args[]) throws Exception    {        A a = new A();                Class c = a.getClass();                Method m = c.getMethod("add", int.class,int.class);                System.out.println(m.invoke(a, 1,2));    }}class A{    public int add(int a,int b)    {        return a+b;    }    private int minus(int a,int b)    {        return a-b;    }}

 

 

5利用反射解释ArrayList的泛型

 

package com.clazz.test;import java.lang.reflect.Method;import java.util.ArrayList;public class ArrayListRflect {        public static void main(String args[]) throws Exception    {        /**         * 下面的代码用于证明,在ArrayList中,泛型只在编译之前有效,编译之后泛型对于list的限制         * 是无效的。利用反射就能绕过编译这个阶段在ArrayList添加本不属于该泛型的值         */        ArrayList
list = new ArrayList
(); list.add("哈哈"); //list.add(1);如果原来这么写,编译会报错的 //那么怎么在list放个int的1呢? //获取list的类类型 Class c = list.getClass(); //通过类类型拿到方法 Method m = c.getMethod("add",Object.class); //通过反射调用方法 m.invoke(list, 1); System.out.println(list); //结果为:[哈哈, 1] //所以证明了上面的观点,也同时很好的证明了反射多神奇 }}

转载于:https://www.cnblogs.com/linkstar/p/5744444.html

你可能感兴趣的文章
linux grep 搜索查找
查看>>
Not enough free disk space on disk '/boot'(转载)
查看>>
android 签名
查看>>
vue项目中使用百度统计
查看>>
android:scaleType属性
查看>>
SuperEPC
查看>>
mysql-5.7 innodb 的并行任务调度详解
查看>>
shell脚本
查看>>
Upload Image to .NET Core 2.1 API
查看>>
Js时间处理
查看>>
Java项目xml相关配置
查看>>
三维变换概述
查看>>
第三次作业
查看>>
vue route 跳转
查看>>
【雷电】源代码分析(二)-- 进入游戏攻击
查看>>
Entityframework:“System.Data.Entity.Internal.AppConfig”的类型初始值设定项引发异常。...
查看>>
Linux中防火墙centos
查看>>
mysql新建用户,用户授权,删除用户,修改密码
查看>>
FancyCoverFlow
查看>>
JS博客
查看>>