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,一经查实,立即删除!

相关文章

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

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

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:"…

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

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

php 图片合成,PHP中多张图片合成一张图片例子

今天分享一段PHP中多张图片合成一张图片的代码实现,我们可以在图片合成,水印,九宫格等需求下使用到类似这样的图片合成效果,下面一起来看看例子吧。今天分享一段PHP中多张图片合成一张图片的代码实现,我们可以在图片合成&#xff…

php的cms是什么意思,phpcms是什么

phpcms是一款具备文章、下载、图片、分类信息、影视、商城、采集、财务等众多功能的强大、易用、可扩展的优秀网站管理软件;该软件采用模块化开发,支持多种分类方式,使其可方便实现个性化网站的设计、开发与维护。phpcms是一款具备文章、下载…

边缘检测滤波matlab,卷积滤波器与边缘检测

频率:对于声音,频率实际上是指声波振荡的速度高低频率高频图像是强度变化很大的图像。并且亮度级别从一个像素到下一个像素快速变化。低频图像可以是亮度相对均匀或变化非常慢的图像。这是一个例子中最容易看到的。大多数图像都有高频和低频成分。在上图…

php 读取 stl 文件,科学网—[转载]【源码】读取ASCII STL文件的STLReader - 刘春静的博文...

读取包含顶点和面的ASCII STL文件,并将其构造为矩阵“顶点”、“颜色”和“面”。之后,使用各小模块在Matlab上建立模型。Read ASCII STL file which contains vertexes and faces and structure it to matrixes "vertexes", "colors&quo…

dsm php,docker dsm是什么?

docker dsm是什么?docker dsm是:从DSM6.0开始如果装了docker的话可以看到下面的图:上图可以看到创建了一个新的DSM,名字为DDSM1,经试验功能和正式DSM一模一样。同时白裙一样可以QuickConnect。然后用Putty登录上去&…

php 5.6 文档,文件存储 | 进阶系列 | Laravel 5.6 中文文档

文件存储由 学院君 创建于3年前, 最后更新于 1年前版本号 #231608 views3 likes0 collects简介Laravel 基于 Frank de Jonge 开发的 PHP 包 Flysystem 提供了强大的文件系统抽象层。Laravel 集成 Flysystem 以便使用不同驱动简化对文件系统的操作,这些驱动包括本地文…

阐述oracle的体系结构,Oracle数据库逻辑体系结构详解

以前对Oracle数据库的了解大多数是集中在mysql,最近工作里面一直使用的是Oracle,虽然说在互联网行业mysql大行其道,但是一些传统行业或者是金融领域还是更加倾向于使用oracle,sqlserver这种大型数据库。为此还是有必要深入了解以下…

linux解锁文件.user.ini,Linux下解决网页服务器权限和.user.ini无法删除的问题

解决网页服务器权限问题在linux环境下搭建Nginx/apache网页服务器,在尝试访问页面时都会遇到这个问题,提示没有写入权限,或者必须访问网页服务器权限。这源自于linux对于权限的限制比较严格。所以网上无数的解决方法,无外乎一个提…

linux内核 lts长期演进,Linux Kernel 4.19 和 5.4 生命周期延长至 6 年

近日,Linux 内核开发及维护者 Greg Kroah-Hartman 宣布将 Linux 内核 4.19 和 5.4 版本的生命周期终止(EOL)支持从两年延长到六年,分别延长至 2024 和 2025 年。在这期间,它们能够继续向后移植 bug 并获得一些重要的安全修复程序。Linux 内核…

linux如何运行qt源码,Linux/Ubuntu下编译Qt4.8.2源码

本人所用的系统为Ubuntu 14,所下载的QT源码版本为4.8.2。以下是编译QT源码的基本步骤:2.解压代码输入指令: tar zxvf qt-everywhere-opensource-src-4.8.2.tar.gz,解压出QT源代码。3.执行./config生成makef…

linux启动过程中内核拷贝,轻松识破linux内核启动过程中的“”套路“”

内核启动流程相关的内容让很多热爱linux的小伙伴既爱又恨,因为这是了解linux系统基本构造的良好过程同时由于其本身复杂且底层,脑子中的脉络不是很清晰,本文就总结了一些优秀博文,以自己的理解来解构一下。本文的环境是CentOS 6.8…

linux wifi ip,Linux环境下使用WIFI模块:使用DHCP工具动态获得IP地址

使用DHCP工具动态获得IP地址实验版本及下载地址DHCP:dhcp-4.4.1.tar.gz链接: [https://www.isc.org/downloads/]编译安装DHCP配置编译选项解压完成后进入DHCP根文件目录,输入配置指令./configure --hostarm-linux ac_cv_file__dev_randomyes --with-rand…

linux创建a1的硬链接a2,Linux命令-重定向和软硬链接

echo功能说明:显示文字. 语 法:echo [-ne][字符串] 或 echo [–help][–version]参数:   -n 不要在最后自动换行重定向>是定向输出到文件,如果文件不存在,就创建文件;如果文件存在,就将其…

linux shell 博客,【博客侠】Linux Shell脚本系列:开始上手(1)

看标题大家应该知道,这是一个关于 Linux Shell 脚本的系列文章。通过本系列文章希望帮助 Linux 初学用户快速开始上手编写 Shell 脚本,能够利索的对脚本进行测试和使用。在接下来的首篇文章中,我们将介绍什么是 Shell,有哪些 Linu…

sql server linux性能,详细了解SQL Server 2008性能和性能优化

在SQL Server 2005或更早的版本中的中,表变量是不能作为存储过程的参数的。当多行数据到SQL Server需要发送多行数据到SQL Server ,开发者要么每次发送一列记录,或想出其他的变通方法,以满足需求。虽然在.net 2.0中提供了个SQLBul…

开发linux显卡驱动,显卡驱动开发DRM入门--Apple的学习笔记

由于之前的blog提及kmscube的源码我没有找到,所以只能在网上搜索了。DRM简介DRM是Linux目前主流的图形显示框架,同时DRM可以统一管理GPU和Display驱动,使得软件架构更为统一,方便管理和维护。而且drm是集成在linux kernel中的。DR…

android mvc使用方法,详细学习android mvc设计模式教程

MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 web 应用程序的模式。其分层有助于管理复杂的应用程序,因为可以在一个时间内专门关注一个方面。例如,可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序的测试更加容易…