java反射 虚拟机优化_面试官问我:Java反射是什么?我回答竟然不上来......

每天凌晨00点00分,第一时间与你相约

每日英文

We all have moments of desperation. But if we can face them head on, that’s when we find out just how strong we really are.

我们都有绝望的时候,只有在勇敢面对时,我们才知道我们有多坚强。

每日掏心话

记住该记住的,忘记该忘记的,改变能改变的,接受不能改变的。

来自:火星十一郎| 责编:乐乐

链接:cnblogs.com/hxsyl

5df24d624d57d5269d17d0bf8c7d0e7b.png

程序员小乐(ID:study_tech)第 935 次推文 图源:百度

往日回顾:程序员下班关闭显示器,却从不关电脑,你知道为什么吗?

正文

一.概念

反射就是把Java的各种成分映射成相应的Java类。

Class类的构造方法是private,由JVM创建。

反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。(来自Sun)

JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。

反射是从1.2就有的,后面的三大框架都会用到反射机制,涉及到类"Class",无法直接new CLass(),其对象是内存里的一份字节码.

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。关注公众号程序员小乐回复关键字“offer”获取算法面试题和答案

基本的 Java类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。Class 没有公共构造方法。

Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

Personp1=newPerson();

//下面的这三种方式都可以得到字节码

CLassc1=Date.class();

p1.getClass();

//若存在则加载,否则新建,往往使用第三种,类的名字在写源程序时不需要知道,到运行时再传递过来

Class.forName("java.lang.String");

Class.forName()字节码已经加载到java虚拟机中,去得到字节码;java虚拟机中还没有生成字节码 用类加载器进行加载,加载的字节码缓冲到虚拟机中。

考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。

importjava.lang.reflect.*;

publicclassDumpMethods{

publicstaticvoidmain(Stringargs[]){

try{

Classc=Class.forName("java.util.Stack");

Methodm[]=c.getDeclaredMethods();

for(inti=0;i

System.out.println(m[i].toString());

}

catch(Throwablee){

System.err.println(e);

}

}

}

publicsynchronizedjava.lang.Objectjava.util.Stack.pop()

publicjava.lang.Objectjava.util.Stack.push(java.lang.Object)

publicbooleanjava.util.Stack.empty()

publicsynchronizedjava.lang.Objectjava.util.Stack.peek()

publicsynchronizedintjava.util.Stack.search(java.lang.Object)

;i++)

这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。这个程序使用Class.forName载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。

以下示例使用 Class 对象来显示对象的类名:

voidprintClassName(Objectobj){

System.out.println("Theclassof"+obj+

"is"+obj.getClass().getName());

}

还可以使用一个类字面值(JLS Section 15.8.2)来获取指定类型(或 void)的 Class 对象。例如:

System.out.println("ThenameofclassFoois:"+Foo.class.getName());

在没有对象实例的时候,主要有两种办法。

//获得类类型的两种方式

Classcls1=Role.class;

Classcls2=Class.forName("yui.Role");

注意第二种方式中,forName中的参数一定是完整的类名(包名+类名),并且这个方法需要捕获异常。现在得到cls1就可以创建一个Role类的实例了,利用Class的newInstance方法相当于调用类的默认的构造器。

Objecto=cls1.newInstance();

//创建一个实例

//Objecto1=newRole();//与上面的方法等价

二.常用方法

1.isPrimitive(判断是否是基本类型的字节码)

publicclassTestReflect{

publicstaticvoidmain(String[]args){

//TODOAuto-generatedmethodstub

Stringstr="abc";

Classcls1=str.getClass();

Classcls2=String.class;

Classcls3=null;//必须要加上null

try{

cls3=Class.forName("java.lang.String");

}catch(ClassNotFoundExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

System.out.println(cls1==cls2);

System.out.println(cls1==cls3);

System.out.println(cls1.isPrimitive());

System.out.println(int.class.isPrimitive());//判定指定的 Class 对象是否表示一个基本类型。

System.out.println(int.class==Integer.class);

System.out.println(int.class==Integer.TYPE);

System.out.println(int[].class.isPrimitive());

System.out.println(int[].class.isArray());

}

}

结果:

true

true

false

true

false

true

false

true

2.getConstructor和getConstructors()

java中构造方法没有先后顺序,通过类型和参数个数区分。

publicclassTestReflect{

publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException{

//TODOAuto-generatedmethodstub

Stringstr="abc";

System.out.println(String.class.getConstructor(StringBuffer.class));

}

}

3.Filed类代表某一类中的一个成员变量。

importjava.lang.reflect.Field;

publicclassTestReflect{

publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException,NoSuchFieldException,IllegalArgumentException,Exception{

ReflectPointerrp1=newReflectPointer(3,4);

Fieldfieldx=rp1.getClass().getField("x");//必须是x或者y

System.out.println(fieldx.get(rp1));

/*

*private的成员变量必须使用getDeclaredField,并setAccessible(true),否则看得到拿不到

*/

Fieldfieldy=rp1.getClass().getDeclaredField("y");

fieldy.setAccessible(true);//暴力反射

System.out.println(fieldy.get(rp1));

}

}

classReflectPointer{

publicintx=0;

privateinty=0;

publicReflectPointer(intx,inty){//alt+shift+s相当于右键source

super();

//TODOAuto-generatedconstructorstub

this.x=x;

this.y=y;

}

}

三.典型例题

1.将所有String类型的成员变量里的b改成a。

importjava.lang.reflect.Field;

publicclassTestReflect{

publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException,NoSuchFieldException,IllegalArgumentException,Exception{

ReflectPointerrp1=newReflectPointer(3,4);

changeBtoA(rp1);

System.out.println(rp1);

}

privatestaticvoidchangeBtoA(Objectobj)throwsRuntimeException,Exception{

Field[]fields=obj.getClass().getFields();

for(Fieldfield:fields){

//if(field.getType().equals(String.class))

//由于字节码只有一份,用equals语义不准确

if(field.getType()==String.class){

StringoldValue=(String)field.get(obj);

StringnewValue=oldValue.replace('b','a');

field.set(obj,newValue);

}

}

}

}

classReflectPointer{

privateintx=0;

publicinty=0;

publicStringstr1="ball";

publicStringstr2="basketball";

publicStringstr3="itcat";

publicReflectPointer(intx,inty){//alt+shift+s相当于右键source

super();

//TODOAuto-generatedconstructorstub

this.x=x;

this.y=y;

}

@Override

publicStringtoString(){

return"ReflectPointer[str1="+str1+",str2="+str2+",str3="

+str3+"]";

}

}

2.写一个程序根据用户提供的类名,调用该类的里的main方法。

为什么要用反射的方式呢?

importjava.lang.reflect.Field;

importjava.lang.reflect.Method;

publicclassTestReflect{

publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException,NoSuchFieldException,IllegalArgumentException,Exception{

Stringstr=args[0];

/*

*这样会数组角标越界,因为压根没有这个字符数组

*需要右键在runas-configurations-arguments里输入b.Inter(完整类名)

*

*/

Methodm=Class.forName(str).getMethod("main",String[].class);

//下面这两种方式都可以,main方法需要一个参数

m.invoke(null,newObject[]{newString[]{"111","222","333"}});

m.invoke(null,(Object)newString[]{"111","222","333"});//这个可以说明,数组也是Object

/*

*m.invoke(null,newString[]{"111","222","333"})

*上面的不可以,因为java会自动拆包

*/

}

}

classInter{

publicstaticvoidmain(String[]args){

for(Objectobj:args){

System.out.println(obj);

}

}

}

3.模拟instanceof操作符

classS{

}

publicclassIsInstance{

publicstaticvoidmain(Stringargs[]){

try{

Classcls=Class.forName("S");

booleanb1=cls.isInstance(newInteger(37));

System.out.println(b1);

booleanb2=cls.isInstance(newS());

System.out.println(b2);

}

catch(Throwablee){

System.err.println(e);

}

}

}

在这个例子中创建了一个S 类的 Class 对象,然后检查一些对象是否是S的实例。Integer(37) 不是,但 new S()是。关注公众号程序员小乐回复关键字“Java”获取面试题和答案

四.Method类

代表类(不是对象)中的某一方法。

importjava.lang.reflect.Field;

importjava.lang.reflect.Method;

/*

*人在黑板上画圆,涉及三个对象,画圆需要圆心和半径,但是是私有的,画圆的方法

*分配给人不合适。

*

*司机踩刹车,司机只是给列车发出指令,刹车的动作还需要列车去完成。

*

*面试经常考面向对象的设计,比如人关门,人只是去推门。

*

*这就是专家模式:谁拥有数据,谁就是专家,方法就分配给谁

*/

publicclassTestReflect{

publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException,NoSuchFieldException,IllegalArgumentException,Exception{

Stringstr="shfsfs";

//包开头是com表示是sun内部用的,java打头的才是用户的

MethodmtCharAt=String.class.getMethod("charAt",int.class);

Objectch=mtCharAt.invoke(str,1);//若第一个参数是null,则肯定是静态方法

System.out.println(ch);

System.out.println(mtCharAt.invoke(str,newObject[]{2}));//1.4语法

}

}

五.数组的反射

Array工具类用于完成数组的反射操作。

同类型同纬度有相同的字节码。

int.class和Integer.class不是同一份字节码,Integer.TYPE,TYPE代表包装类对应的基本类的字节码 int.

importjava.util.Arrays;

/*

*从这个例子看出即便字节码相同但是对象也不一定相同,根本不是一回事

*

*/

publicclassTestReflect{

publicstaticvoidmain(String[]args)throwsSecurityException,NoSuchMethodException,NoSuchFieldException,IllegalArgumentException,Exception{

int[]a=newint[3];

int[]b=newint[]{4,5,5};//直接赋值后不可以指定长度,否则CE

int[][]c=newint[3][2];

String[]d=newString[]{"jjj","kkkk"};

System.out.println(a==b);//false

System.out.println(a.getClass()==b.getClass());//true

//System.out.println(a.getClass()==d.getClass());//比较字节码a和cd也没法比

System.out.println(a.getClass());//输出class[I

System.out.println(a.getClass().getName());//输出[I,中括号表示数组,I表示整数

System.out.println(a.getClass().getSuperclass());//输出classjava.lang.Object

System.out.println(d.getClass().getSuperclass());//输出classjava.lang.Object

//由于父类都是Object,下面都是可以的

Objectobj1=a;//不可是Object[]

Objectobj2=b;

Object[]obj3=c;//基本类型的一位数组只可以当做Object,非得还可以当做Object[]

Objectobj4=d;

//注意asList处理int[]和String[]的区别

System.out.println(Arrays.asList(b));//1.4没有可变参数,使用的是数组,[[I@1bc4459]

System.out.println(Arrays.asList(d));//[jjj,kkkk]

}

}

六.结束语

以上就是反射机制的简单的使用,显然学过spring的朋友一定明白了,为什么可以通过配置文件就可以让我们获得指定的方法和变量,在我们创建对象的时候都是通过传进string实现的,就好像你需要什么,我们去为你生产,还有我们一直在用Object,这就说明java语言的动态特性,依赖性大大的降低了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/528555.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql解压包安装linuex_CentOS下安装Apache,php,Mysql

第一步:通过yum安装php,mysql,httpd,这里默认使用CentOS提供的默认版本,版本较低。#yum install httpd mysql-server php php-devel php-mysql所有的安装包大小为25M,大概2分钟左右就能下载安装完成。第二步…

c java 开发效率高_Java 的开发效率究竟比 C++ 高在哪里?

如果选择C,那C 的难度与JAVA 比,那应该不在一个层次。因为 C 作者及委员会想给你带来足够的抽象能力,让你可以抽象这个世界;给你足够的自由与控制硬件的能力,及零开销的高性能。简单点说,C程序员如同神一般…

java sub,Java 9子软件包跨模块拆分

In Java 9, can I split sub-packages across modules? For example, can I have com.example.foo in one module and com.example.foo.bar in another module?This seems like a simple question, but for some reason Im not able to find a direct answer after some sear…

java矩阵类_151-矩阵类

[java]代码库import java.util.Scanner;import java.util.Arrays;public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);int r scan.nextInt();int c scan.nextInt();System.out.println("row:"r" column:"…

python3 for sum_Python for循环和“sum13”方法

我是一个刚开始学习Python的本地C程序员,我已经给出了以下的写作方法:Return the sum of the numbers in the array, returning 0 for an empty array. Except the number 13 is very unlucky, so it does not count and numbers that come immediately …

java调用c jni_Java调用C JNI

JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的一种方法就是JNI。JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在W…

java websphere mq_如何在java中使用WebSphere MQ?

Java中使用websphere websphere mq:用于传输信息 具有跨平台的功能。1 安装websphere mq并启动2 websphere mq建立queue Manager(如:MQSI_SAMPLE_QM)3 建立queue类型选择Local类型的(如lq)4 建立channels类型选择Server Connection(如BridgeChannel)以下…

java 序列化保存_保存到二进制/序列化Java

我必须报价,1.将帐户保存到二进制(序列化)文件中。2.从二进制(序列化)文件加载(重新创建)帐户。因此,首先,我正在查找确切的例子,而我却迷失了自己,在同样的情况下,人们提到xml,在我的脑海中&am…

java控制excel_java操作excel

1. 生成并下载excel文件controllerRequestMapping(value "/download", method RequestMethod.GET)public xxx downloadFile(HttpServletResponse response) {response.setContentType("application/octet-stream");response.setHeader("content-typ…

java 方法权限_Java控制访问权限的方法

这篇博客主要用来介绍Java中的访问权限.引入访问控制权限我们都知道,一个通用类库(如:JDK)开发出来的目的是让普通开发者重用以节省开发时间与精力,但是类库的设计不可能在刚开始就尽善尽美,普通开发者在对类库的使用过程中&#…

java套接字客户端_使用Java从客户端套接字读取数据(Read data from a client socket in Java)...

使用Java从客户端套接字读取数据(Read data from a client socket in Java)我编写了从客户端套接字发送/接收数据的代码。 发送数据步骤已成功完成,但是当我想从套接字读取数据时, readLine()方法阻止程序,而没有要读取的数据。这是我的代码&…

xml动态生成java_从XML文档动态生成Java类

考虑这种情况:我有一个名为person.xml的XML文件,其中包含以下数据.MrFoo28如果我想将这个XML读入Java对象,我将创建一个名为PersonBean的Java bean(使用属性的getter / setter):class Person{String name;int age;}我可以使用任何API来读取XML并填充Java…

java lpad oracle_Oracal的Lpad函数

2007-09-21 17:13 | pinty回复楼上,根据LEVEL的数决定输出“-”的个数,看下面的例子SELECT LEVEL, LPAD( ,2*(LEVEL - 1)) || lname "EMPLOYEE",emp_id, manager_emp_idFROM employeeSTART WITH emp_id 7839CONNECT BY NOCYCLE PRIOR emp_id …

用java输入学生姓名查询成绩_编写一个Java程序,提示用户输入学生数量,学生姓名和他们的成绩,并按照成绩的降序打印学生姓名...

importjava.util.Scanner;publicclassmyclass{publicstaticvoidmain(String[]args){ScannerinputnewScanner(System.in);System.out.print("请输入学生个数,学生姓名以及学生成绩");...import java.util.Scanner;public class myclass{public static void…

java对xml解析_Java中对xml的解析

// 1.通过DocumentBuilderFactor创建解析工厂DocumentBuilderFactory builderFactory DocumentBuilderFactory.newInstance();// 2.通过工厂获得解析器DocumentBuilder builder builderFactory.newDocumentBuilder();// 3.通过parser方法获取DocumentDocument document buil…

刻画小狗状态java_JAVA面向接口编程

JAVA面向接口编程小狗在不同环境条件下可能呈现不同的状态,小狗通过调用 cry()方法体现自己的当前的状 态。要求用接口封装小狗的状态。具体要求如下。• 编写一个接口 DogState,该接口有一个名字为 void showState()的方法。• 编写 Dog 类,…

java jdbc(mysql)驱动源码分析_JAVA JDBC(MySQL)驱动源码分析(二)

本文系转载,地址:http://blog.csdn.net/brilliancezhou/article/details/5425687上一篇中分析了Class.forName(“com.mysql.jdbc.Driver”)幕后所做的事情,也就是在Driver实现类中的静态块和构造函数,本篇主要来分析一下静态块的一…

java %3c%=a%%3e_跪求帮忙解析,急!!!

xml 这个参数的值,是被 urlencode 两次的东西。 php 不懂, Python 的话是用 urllib.unquote 就可以了。>>> s %3C%3Fxmlversion%3D%221.0%22encoding%3D%22gbk%22%3F%3E%253Ctask%253E%253Cuser%253E%253Coper%253Emod%253C%252Foper%253E%253…

java环境变量一闪而过_Java环境变量配置和Tomcat启动时cmd界面一闪而过问题

Java环境变量配置计算机 -> 属性 -> 高级系统设置 -> 环境变量 -> 系统变量中配置Java环境变量。配置JAVA_HOME,属于必配项,如果不配置,直接指定path路径利用工具可以进行Java项目开发,但是后期使用Tomcat开发会出现问…

ubuntu启动php-fpm_ubuntu安装php-fpm+xdebug

一、安装程序包1、sudo apt-get install php5-dev2、sudo apt-get install php5-xdebug二、修改php.ini配置文件; 修改/etc/php5/fpm/php.ini或在增加文件/etc/init.d/php5/conf.d/xdebug.ini; configuration for php Xdebug module;extentionxdebug.so[xdebug]zend_extension/…