程序猿们经常说的一句话:反射反射。。。程序员的快乐
 
 
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
 

文章开始之前 提一下:

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

万物皆对象。但基本数据类型 和 使用static修饰的成员不是对象

但基本数据类型的封装类是对象

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,,Constructor  ... )的操作都是绕过编译,都是在运行时刻来执行的

凡事都是一把双刃剑,都有利弊两面,不可能有事物十全十美,反射是好,但也不要盲目使用

反射优缺点

优点:
(1)能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。 
(2)与Java动态编译相结合,可以实现无比强大的功能 
缺点: 
(1)使用反射的性能较低 
(2)使用反射相对来说不安全 
(3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性 

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

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

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

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

  1. Java 高级开发必修知识---内部类

    摘自:http://www.cnblogs.com/lsy131479/p/8798912.html Java 内部类分为: 1)成员内部类 2)静态嵌套类 3)方法内部类 4)匿名内部类 内部类的共 ...

  2. Java高级开发必会的50个性能优化的细节(珍藏版)

      在JAVA程序中,性能问题的大部分原因并不在于JAVA语言,而是程序本身.养成良好的编码习惯非常重要,能够显著地提升程序性能. ● 1. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短 ...

  3. Java高级开发工程师面试笔记

    最近在复习面试相关的知识点,然后做笔记,后期(大概在2018.02.01)会分享给大家,尽自己最大的努力做到最好,还希望到时候大家能给予建议和补充 ----------------2018.03.05 ...

  4. 近期Java高级开发岗面试总结

    原文出处:公众号:编程大道 作者:walking 近期Java高级开发岗面试总结 哈喽大家好,我是walking,这是我的公众号:编程大道. 很久没和大家见面了,文章更新的速度略有延后.这个公众号断断 ...

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

    地址 引言: 学习一个新的技术时,其实不在于跟着某个教程敲出了几行.几百行代码,这样你最多只能知其然而不知其所以然,进步缓慢且深度有限,最重要的是一开始就对整个学习路线有宏观.简洁的认识,确定大的学习 ...

  6. Java后台开发精选知识图谱

    1.引言: 学习一个新的技术时,其实不在于跟着某个教程敲出了几行.几百行代码,这样你最多只能知其然而不知其所以然,进步缓慢且深度有限,最重要的是一开始就对整个学习路线有宏观.简洁的认识,确定大的学习方 ...

  7. java web开发必备知识

    从各种招聘网站的要求上筛选出了一些java开发的一些基本的要求,对照自身看看有哪些缺陷. java基础 既然是java web开发,java SE肯定要学好了. 多线程,IO,集合等,对队列,缓存,消 ...

  8. java基础(十一 )-----反射——Java高级开发必须懂的

    本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...

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

        理解反射对学习Java框架有很大的帮助,如Spring框架的核心就是使用Java反射实现的,而且对做一些Java底层的操作会很有帮助.  一.Class类的使用         1.万事万物皆 ...

随机推荐

  1. [模拟赛] T3 最优序列

    Description 给出一个长度为n(n<=1000)的正整数序列,求一个子序列,使得原序列中任意长度为m的子串中被选出的元素不超过k(k<=m<=10)个,并且选出的元素之和最 ...

  2. 简单爬虫 -- 以爬取NASA AOD数据(TIFF文件)为例

    目录: 网站分析 爬取下载链接 爬取TIFF图片 1.网站分析 主页面:https://neo.sci.gsfc.nasa.gov/view.php?datasetId=MYDAL2_M_AER_OD ...

  3. android中与SQLite数据库相关的类

    为什么要在应用程序中使用数据库?数据库最主要的用途就是作为数据的存储容器,另外,由于可以很方便的将应用程序中的数据结构(比如C语言中的结构体)转化成数据库的表,这样我们就可以通过操作数据库来替代写一堆 ...

  4. Python中的PYTHONPATH环境变量

    PYTHONPATH是Python中一个重要的环境变量,用于在导入模块的时候搜索路径.可以通过如下方式访问: >>> import sys >>> sys.path ...

  5. 04_Python的数据类型1数值和字符串_Python编程之路

    上一节我们通过一个helloworld程序学习python的一些简单操作,还有输入与输出 这节我们来讲Python的数据类型与变量的操作 Python的交互器 在讲这个之前,我要先讲一下python的 ...

  6. 课后练习:C语言实现Linux命令——od

    课后练习:C语言实现Linux命令--od --------CONTENTS-------- 题目详情与分析 设计思路 遇到的问题及解决 待实现的设想与思考 学习反思与感悟 附1:myod.c「1.0 ...

  7. android数据库持久化框架, ormlite框架,

    前言 Android中内置了SQLite,但是对于数据库操作这块,非常的麻烦.其实可以试用第3方的数据库持久化框架对之进行结构上调整, 摆脱了访问数据库操作的细节,不用再去写复杂的SQL语句.虽然这样 ...

  8. 团队作业4——第一次项目冲刺(Alpha版本)2017.11.14

    第一次会议:2017-11-14 额--这几天比较忙,忘记上传了,今天补上 先上个图,O(∩_∩)O哈哈: 会议主要内容: 1. 讨论整体框架 2. 个人具体分工 3. 代码统一 具体分工: 成员 计 ...

  9. const volatile同时限定一个类型int a = 10

    const和volatile放在一起的意义在于: (1)本程序段中不能对a作修改,任何修改都是非法的,或者至少是粗心,编译器应该报错,防止这种粗心: (2)另一个程序段则完全有可能修改,因此编译器最好 ...

  10. android 自定义ScrollView实现背景图片伸缩(阻尼效果)

    android 自定义ScrollView实现强调内容背景图片伸缩(仿多米,qq空间背景的刷新) 看到一篇文章,自己更改了一下bug: 原文地址:http://www.aiuxian.com/arti ...