Java 高级开发必修知识---反射

文章开始之前 提一下:

java反射操作其实就是主要围绕Class,Field,Methon等几个类来操作其中的方法

Class类的使用

1) 在面向对象的世界里,万事万物皆对象

A. Java语言中,普通数据类型,静态成员不是对象,其他皆对象

B. 每一个类也是对象

C. 类是java.lang.Class类的实例对象

There is a class named Class

对象的表示:

普通类对象表示:

Foo foo = new Foo();

Class类实例对象表示:

//Foo也是一个实例对象,是Class类的实例对象

任何一个类都是Class的实例对象,这个实例对象有三种表达方式

1. 任何一个类都有一个隐含的静态成员变量class:

Class c1 = Foo.class;

2. 已经指定该类的对象通过getClass方法

Foo foo = new Foo();

Class c2 = foo.getClass();

官网:c1/c2 表示了Foo类的类类型(class type)

一个类,本身就是一个对象,它是Class类的对象

万事万物皆对象,类也是对象,是Class类的实例对象,这个对象我们称为该类的类类型

3. ForName(“类的全称”);

Class c3 = null;

c3=Class.forName(“包名+.某类名”);

不管是那种表达方式,都是Class类的对象,都是Foo类的类类型。所以:

C1=c2=c3

完全可以通过类的类类型创建该类的对象(创建Foo的实例对象,但要做强制类型转换,向下转型)

前提要求:需要有无参数的构造方法

Comont comont = new Comont();
Class c1 = comont.getClass();
Class c2 = Comont.class;
try {
Comont c = (Comont) c2.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(c1 == c2);
comont.start();

动态加载类

Class.forName(“类的全称”);

1. 不仅表示了类的类类型,还代表动态加载类

2. 编译时刻加载类是静态加载类,运行时刻加载类是动态加载类

(1) New 对象是静态加载类,在变异时刻就需要加载所有的可能使用到的类

(2) 动态加载类,在运行时刻加载

编译不会报错

运行时刻报错。找不到该类

Class c = Class.forName(arg[0]);

共同实现接口类 cc = (共同实现接口类) c.newInstance();

3. 使用记事本开发可明显区分

Java 类 要运行类:动态加载类,不需要重新编译测试类,直接运行即可

功能性的类:尽量使用动态加载

基本数据类型也有类类型

Class c1 = int.class;
Class c2 = String.class;//String类的字节码

数据类型和包装类的类类型不同

Void也是类

Class c3 = void.class;

基本数据类型

Void关键字

都存在类类型

方法也是对象,方法是Method的对象

反射:某类的字节码表示

获取方法信息

1. c.getName()

(1) 基本数据类型返回类型名

(2) 类返回包名+类名类的名称

2. c1.getSimpleName()

(1) 返回不带包名的类的名称

栗子:通过反射可以获取到任何类的信息

需求:打印类的信息,获取类的 成员函数

package cn.pro;

import java.lang.reflect.Method;

/**
 *
 * @author: 房上的猫
 *
 * @time: 下午5:34:45
 *
 * @博客地址: https://www.cnblogs.com/lsy131479/
 *
 */

public class mymain {
    public static void printClassMessage(Object obj) {
        // 要获取类的信息 首先要获取类的类类型
        // 形参obj 该对象所属类的信息
        Class c = obj.getClass();// 传递的是哪个子类的对象 c就是该        子类的类类型
        // getClass()方法:native修饰代表 存在不是java 代码 ,调度        外用 ///该方法java内调用底层c语言实现

        // 获取累的名称
        System.out.println("类的名称是:" + c.getName());
        // Method类是方法对象
        // 一个成员方法就是一个Method
        // getMethods()方法获取的是所有的public修饰的函数,包括父类        继承而来的
        Method[] ms = c.getMethods();
        // c.getDeclaredMethods()获取的是所有该类自己声明的方法,不        问访问权限.所有。所有。所有
        String[] name = new String[ms.length];
        for (int i = 0; i < ms.length; i++) {
            // 得到方法的返回值类型--得到的是返回值类型的类类型
            Class returnType = ms[i].getReturnType();
            // 得到返回值名字
            String returnName = returnType.getName();
            // 得到方法的名称
            name[i] = ms[i].getName();
            // 获取参数列表类型--得到的是参数列表的类型的类类型
            Class[] parameterTypes = ms[i].getParameterTypes();
Int params=parameterTypes.length;
String[] paramNames = new String[params];
            for (int j = 0; j < params; j++) {
                // 得到参数列表名
                paramNames[j] = ms[j].getName();
            }
        }
    }
}

通过反射可以获取任何类的类信息

比较牛逼

获取类的成员变量构造函数信息

成员变量也是对象

是Java.lang.reflect.Field的对象

Field类封装了关于成员变量的操作

栗子:通过反射可以获取到任何类的信息

需求:打印类的信息,获取类的成员变量

package cn.reflect;

import java.lang.reflect.Field;

/**
 *
 * @author: 房上的猫
 *
 * @time: 下午3:49:32
 *
 * @博客地址: https://www.cnblogs.com/lsy131479/
 *
 */

public class myField {
    public static void printFieldMessage(Object obj) {
        Class c = obj.getClass();
        // getFidlds() 方法获取的是类的所有的public的成员变量信息
        Field[] fs = c.getFields();

        // getDeclaredFields() 获取的是该类自己声明的成员信息 不问访问权限.所有。所有。所有
        // Field[] fs = c.getDeclaredFields();

        for (Field field : fs) {
            // 得到成员变量的类型的类类型
            Class fieldType = field.getType();
            // 得到成员变量类型的名字
            String typeName = fieldType.getName();
            // 得到成员变量的名字
            String fieldName = field.getName();
            //

        }

    }
}

构造函数也是对象

是Java.lang.Constructor的对象 其中封装了构造函数的信息

栗子:通过反射可以获取到任何类的信息

需求:打印类的信息,获取类的构造函数信息

package cn.reflect;

import java.lang.reflect.Constructor;

/**
 *
 * @author: 房上的猫
 *
 * @time: 下午3:49:32
 *
 * @博客地址: https://www.cnblogs.com/lsy131479/
 *
 */

public class myCon {
    public static void printConMessage(Object obj) {
        Class c = obj.getClass();
        // getConstructors() 获得所有的共有的构造方法
        Constructor[] cs = c.getConstructors();
        // getDeclaredConstructors() 得到所有的构造方法(必须是自己声明的) 不问访问权限.所有。所有。所有
        // Constructor[] cs = c.getDeclaredConstructors();
        for (Constructor constructor : cs) {
            // 获取构造函数名
            String name = constructor.getName();
            // 获取构造函数的参数列表------>得到的是参数列表的类类型
            Class[] parameterTypes = constructor.getParameterTypes();
            for (Class class1 : parameterTypes) {
                // 获取构造函数参数列表名
                String name2 = class1.getName();
            }
        }
    }
}

其他

Class类还可以获取类的其他信息,这里将不再详细讲解

想要了解的可以创建Class类的实例对象

Class c = obj.getClass();

c.get...

自行查看并尝试

或阅读帮助文档,查看Class类的所有API

记住一点:在任何情况下想要获取一个类的信息,首先要得到这个类的类类型

得到类的类类型,得到这个类的类信息就轻而易举得到了

方法的反射

1. 如何获取某个方法?

方法的名称和方法的参数列表才能唯一决定某个方法

2. 方法反射的操作

Method.invoke(对象,参数列表)

栗子:

package cn.reflect;

import java.lang.reflect.Method;

/**
 *
 * @author: 房上的猫
 *
 * @time: 下午4:25:25
 *
 * @博客地址: https://www.cnblogs.com/lsy131479/
 *
 */

public class MethodDemo1 {
    public static void main(String[] args) throws Exception {

        // 要获取print(int,int)方法
        A a = new A();
        /*
         * 1.要获取一个方法就是要获取一个类的信息,获取类的信息首先要获取类的类类型
         */

        Class c = a.getClass();
        /*
         * 2.获取方法 名称和参数列表
         *
         * getMethod(name, parameterTypes)获取的是public的方法
         *
         * c.getDeclaredMethod(name, parameterTypes)获取的是所有自己声明的方法 不问访问权限
         *
         *
         * 参数解析: 1.name:方法名 2.parameterTypes:参数列表类型(0或多个)
         */
        Method m = c.getMethod("print", new Class[] { int.class, int.class });

        /*
         * 方法的反射操作
         *
         * a.print(10,20);方法的反射操作是用m对象来进行方法调用 和a.print调用的效果
         *
         * 方法如果没有返回值返回null 有返回值返回具体的返回值 返回object类型,需要做强制类型转换
         */

        Object o = m.invoke(a, new Object[] { 10, 20 });
        // 就等于调用了print(int,int)方法

        /*
         * 如果方法无参数列表则:
         *
         * c.getMethod("print"); m.invoke(a);
         */

    }
}

class A {
    public void print(int a, int b) {
        System.out.println(a + b);
    }

    public void print(String a, String b) {
        // a的大写形式 and b的小写形式
        System.out.println(a.toUpperCase() + "," + b.toLowerCase());
    }
}

升华操作:

通过反射了解集合泛型的本质

通过Class,Method来认识泛型的本质

相信读者们看到这里心中一定会有这样两个疑问:

什么是泛型?

泛型什么时候有效?

 那我们探讨一下这两个话题:

 

package cn.reflect;

import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 *
 * @author: 房上的猫
 *
 * @time: 下午6:31:38
 *
 * @博客地址: https://www.cnblogs.com/lsy131479/
 *
 */

public class MethodDemo2 {
    public static void main(String[] args) {
        // 普通集合
        ArrayList list = new ArrayList<>();

        // 泛型集合 集合内只能存放‘<>‘尖括号内类型的值
        ArrayList<String> list1 = new ArrayList<>();
        // 集合的泛型防止错误输入

        // 利用反射了解集合泛型
        Class c1 = list.getClass();
        Class c2 = list1.getClass();
        list1.add("1");
        System.out.println(c1 == c2);
        /*
         * 反射的操作都是编译之后的操作(运行时)
         *
         * c1==c2结果返回true 表示两个集合类运行时都是同一类类型
         *
         * 说明编译之后集合的泛型是去泛型化的(编译完之后就没有泛型存在了)
         *
         * java中集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译就无效了
         *
         * 验证:可以通过方法的反射来操作,绕过编译
         */
        try {
            Method m = c2.getMethod("add", Object.class);
            m.invoke(list1, 100);// 大胆猜想:绕过编译操作就绕过了泛型
            // 集合大小返回2 .说明:绕过编译阶段后可以向泛型集合添加任何类型的值
            System.out.println(list1.size());
            // 尝试查看泛型集合内的值 发现值已经添加进去
            System.out.println(list1);

            /*
             * 在这里如果使用for增强遍历将会抛异常
             *
             * 因为后面添加的100是int类型的值
             *
             * 而集合泛型是String类型
             *
             * 使用for增强遍历内部其实做出的操作是:集合的每个值都使用一个集合泛型类型的数据类型来接受遍历
             * 而int类型使用String类型来接受,众所周知将会报错(这里的泛型类型是String)
             *
             * 会有类型转换错误
             */
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

结论:

反射(Class,Method,Field  ... )的操作都是绕过编译,都是在运行时刻来执行的

ok...到此为止!!!后续如果有新的想法将会继续总结。。敬请期待 

(C) 房上的猫 。 保留所有权利。
 https://www.cnblogs.com/lsy131479/

如需转载,请注明出处!!!

原文地址:https://www.cnblogs.com/lsy131479/p/8798217.html

时间: 2024-11-07 22:43:55

Java 高级开发必修知识---反射的相关文章

Java高级开发工程师面试考纲

如果要应聘高级开发工程师职务,仅仅懂得Java的基础知识是远远不够的,还必须懂得常用数据结构.算法.网络.操作系统等知识.因此本文不会讲解具体的技术,笔者综合自己应聘各大公司的经历,整理了一份大公司对Java高级开发工程师职位的考核纲要,希望可以帮助到需要的人. 当前,市面上有<Java XX宝典>类似的图书,而且图书中的内容都着重在讲解Java最为基础的部分,最严重的是,里面有着大量错误的内容,极具误导性.另外,网上也有各种各样的Java面试题,很多也是着重在Java语言基础上.实际上,如果

(转)Java高级开发工程师面试考纲

当前,市面上有<Java XX宝典>类似的图书,而且图书中的内容都着重在讲解Java最为基础的部分,最严重的是,里面有着大量错误的内容,极具误导性.另外,网上也有各种各样的Java面试题,很多也是着重在Java语言基础上.实际上,如果要应聘高级开发工程师职务,仅仅懂得Java的基础知识是远远不够的,还必须懂得常用数据结构.算法.网络.操作系统等知识.因此本文不会讲解具体的技术,笔者综合自己应聘各大公司的经历,整理了一份大公司对Java高级开发工程师职位的考核纲要,希望可以帮助到需要的人. 1

最新Java高级开发工程师面试考纲

当前,市面上有<Java XX宝典>类似的图书,而且图书中的内容都着重在讲解Java最为基础的部分,最严重的是,里面有着大量错误的内容,极具误导性.另外,网上也有各种各样的Java面试题,很多也是着重在Java语言基础上.实际上,如果要应聘高级开发工程师职务,仅仅懂得Java的基础知识是远远不够的,还必须懂得常用数据结构.算法.网络.操作系统等知识.因此本文不会讲解具体的技术,笔者综合自己应聘各大公司的经历,整理了一份大公司对Java高级开发工程师职位的考核纲要,希望可以帮助到需要的人. 1.

【分享】Java后台开发精选知识图谱

地址 引言: 学习一个新的技术时,其实不在于跟着某个教程敲出了几行.几百行代码,这样你最多只能知其然而不知其所以然,进步缓慢且深度有限,最重要的是一开始就对整个学习路线有宏观.简洁的认识,确定大的学习方向,这样才能事半功倍. 我们经常会遇到这样的情况: 一开始学习一门新技术的时候,面对着很多很多陌生的名词,无从下手,一度想要放弃. 本文首先会给出关于java后台开发和前端适配的一些建议学习路线,接着简单解释一些应用到的高频技术,帮助大家理解和学习,算是一个入门篇. Java后台开发知识一览 1.

反射----Java高级开发必须懂的

定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 1.在面向对象的世界里,万事万物皆对象. java语言中,静态的成员.普通数据类型是不是对象呢?不是 类是谁的对象呢?类是对象,类是java.lang,Class类的实例对象. 好比,自定义一个student对象,student是Student类的实例对象. 任何一个类,都是Cla

慕课网_反射——Java高级开发必须懂的

第1章 Class类的使用 1-1 Class类的使用 (15:18) 第2章 动态加载类 2-1 Java 动态加载类 (13:19) 第3章 获取方法信息 3-1 Java 获取方法信息 (17:06) 第4章 获取成员变量构造函数信息 4-1 Java 获取成员变量构造函数信息 (14:44) 第5章 方法反射的基本操作 5-1 Java 方法反射的基本操作 (13:55) import java.lang.reflect.Method; public class Hello { publ

Java高级开发工程师面试考纲 转

转 http://www.sanesee.com/article/java-engineer-interview-of-content-tree 1 Java基础 1.1 Collection和Map (1)掌握Collection和Map的继承体系. (2)掌握ArrayList.LinkedList.Vector.Stack.PriorityQueue.HashSet.LinkedHashSet.TreeSet.HashMap.LinkedHashMap.TreeMap.WeakHashMa

java 测试开发基础知识(类加载,JVM等)

写在开头: 面试的时候别人很可能会问你的java原理,.class load 原理, jvm机制,这些都是Java的底层知识,特整理如下: 1. 首先,编写一个java程序,大家会用ide编写一个例如helloworld.java的文件, 程序是能够识别这个文件的,但是计算机不行,所以需要一个编译的过程: 执行java.exe , 例如 在cmd的窗口执行:   $java  helloworld.java , 这个时候你会发现在同级目录系生成了一个helloworld.class的可执行文件,

《深入理解Java虚拟机》-----第7章 虚拟机类加载机制——Java高级开发必须懂的

代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言发展的一大步. 7.1 概述 上一章我们了解了Class文件存储格式的具体细节,在Class文件中描述的各种信息,最终都需要加载到虚拟机中之后才能运行和使用.而虚拟机如何加载这些Class文件?Class文件中的信息进入到虚拟机后会发生什么变化?这些都是本章将要讲解的内容. 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载