欢迎访问 生活随笔!

凯发k8官方网

当前位置: 凯发k8官方网 > 编程语言 > java >内容正文

java

java反射机制详解-凯发k8官方网

发布时间:2024/10/14 java 42 豆豆
凯发k8官方网 收集整理的这篇文章主要介绍了 java反射机制详解_java反射机制详解 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

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

1、关于class

1、class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的method,描述字段的filed,描述构造器的constructor等属性

2、对象照镜子后(反射)可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。

3、对于每个类而言,jre 都为其保留一个不变的 class 类型的对象。

一个 class 对象包含了特定某个类的有关信息。

4、class 对象只能由系统建立对象

5、一个类在 jvm 中只会有一个class实例

package com.java.reflection;

public class person {

string name;

private int age;

public person() {

system.out.println("无参构造器");

}

public person(string name, int age) {

system.out.println("有参构造器");

this.name = name;

this.age = age;

}

public string getname() {

return name;

}

public void setname(string name) {

this.name = name;

}

public int getage() {

return age;

}

public void setage(int age) {

this.age = age;

}

@override

public string tostring() {

return "person{" 

"name='"   name   '\'' 

", age="   age 

'}';

}

}

2、反射机制获取类有三种方法

/**

* 反射机制获取类有三种方法

*/

@test

public void testgetclass() throws classnotfoundexception {

class clazz = null;

//1 直接通过类名.class的方式得到

clazz = person.class;

system.out.println("通过类名: "   clazz);

//2 通过对象的getclass()方法获取,这个使用的少(一般是传的是object,不知道是什么类型的时候才用)

object obj = new person();

clazz = obj.getclass();

system.out.println("通过getclass(): "   clazz);

//3 通过全类名获取,用的比较多,但可能抛出classnotfoundexception异常

clazz = class.forname("com.java.reflection.person");

system.out.println("通过全类名获取: "   clazz);

}

通过类名: class com.java.reflection.person

无参构造器

通过getclass(): class com.java.reflection.person

通过全类名获取: class com.java.reflection.person

3、利用newinstance创建对象:调用的类必须有无参的构造器

/**

* class类的newinstance()方法,创建类的一个对象。

*/

@test

public void testnewinstance()

throws classnotfoundexception, illegalaccessexception, instantiationexception {

class clazz = class.forname("com.java.reflection.person");

//使用class类的newinstance()方法创建类的一个对象

//实际调用的类的那个 无参数的构造器(这就是为什么写的类的时候,要写一个无参数的构造器,就是给反射用的)

//一般的,一个类若声明了带参数的构造器,也要声明一个无参数的构造器

object obj = clazz.newinstance();

system.out.println(obj);

}

无参构造器

person{name='null', age=0}

4、classloader类加载器

/**

* classloader类装载器

*/

@test

public void testclassloader1() throws classnotfoundexception, ioexception {

//1、获取一个系统的类加载器

classloader classloader = classloader.getsystemclassloader();

system.out.println("系统的类加载器-->"   classloader);

//2、获取系统类加载器的父类加载器(扩展类加载器(extensions classloader))

classloader = classloader.getparent();

system.out.println("扩展类加载器-->"   classloader);

//3、获取扩展类加载器的父类加载器

//输出为null,无法被java程序直接引用

classloader = classloader.getparent();

system.out.println("启动类加载器-->"   classloader);

//

//4、测试当前类由哪个类加载器进行加载 ,结果就是系统的类加载器

classloader = class.forname("com.java.reflection.person").getclassloader();

system.out.println("当前类由哪个类加载器进行加载-->" classloader);

//5、测试jdk提供的object类由哪个类加载器负责加载的

classloader = class.forname("java.lang.object").getclassloader();

system.out.println("jdk提供的object类由哪个类加载器加载-->"   classloader);

}

系统的类加载器-->sun.misc.launcher$appclassloader@43be2d65

扩展类加载器-->sun.misc.launcher$extclassloader@7a9664a1

启动类加载器-->null

当前类由哪个类加载器进行加载-->sun.misc.launcher$appclassloader@43be2d65

jdk提供的object类由哪个类加载器加载-->null

4.1、getresourceasstream方法

@test

public void testgetresourceasstream() throws classnotfoundexception, ioexception {

//          这么写的话,文件需要放到src目录下

//       inputstream in = new fileinputstream("test.properties");

//5、关于类加载器的一个主要方法

//调用getresourceasstream 获取类路径下的文件对应的输入流

inputstream in = this.getclass().getclassloader()

.getresourceasstream("com/java/reflection/test.properties");

system.out.println("in: "  in);

properties properties = new properties();

properties.load(in);

string driverclass = properties.getproperty("dirver");

string jdbcurl = properties.getproperty("jdbcurl");

//中文可能会出现乱码,需要转换一下

string user = new string(properties.getproperty("user").getbytes("iso-8859-1"), "utf-8");

string password = properties.getproperty("password");

system.out.println("diverclass: " driverclass);

system.out.println("user: "   user);

}

test.properties内容如下:

dirver=com.mysql.jdbc.driver;

jdbcurl=jdbc:mysql://192.168.42.108:3306/test

user=测试

password=993803

结果:

in: java.io.bufferedinputstream@2aca0115

diverclass: com.mysql.jdbc.driver;

user: 测试

5、method: 对应类中的方法

public class person {

private string name;

private int age;

//新增一个私有方法

private void privatemthod(){

}

public person() {

system.out.println("无参构造器");

}

public person(string name, int age) {

system.out.println("有参构造器");

this.name = name;

this.age = age;

}

public string getname() {

return name;

}

public void setname(string name) {

this.name = name;

}

/**

*

* @param age  类型用integer,不用int

*/

public void setname(string name , int age){

system.out.println("name: "   name);

system.out.println("age:"  age);

}

public int getage() {

return age;

}

public void setage(int age) {

this.age = age;

}

@override

public string tostring() {

return "person{" 

"name='"   name   '\'' 

", age="   age 

'}';

}

}

@test

public void testmethod() throws classnotfoundexception, nosuchmethodexception,

illegalaccessexception, instantiationexception, invocationtargetexception {

class clazz = class.forname("com.java.reflection.person");

//1、得到clazz 对应的类中有哪些方法,不能获取private方法

method[] methods =clazz.getmethods();

system.out.print("        getmethods: ");

for (method method : methods){

system.out.print(method.getname()   ", ");

}

//2、获取所有的方法(且只获取当着类声明的方法,包括private方法)

method[] methods2 = clazz.getdeclaredmethods();

system.out.print("\ngetdeclaredmethods: ");

for (method method : methods2){

system.out.print(method.getname()   ", ");

}

//3、获取指定的方法

method method = clazz.getdeclaredmethod("setname",string.class);//第一个参数是方法名,后面的是方法里的参数

system.out.println("\nmethod : "   method);

method method2 = clazz.getdeclaredmethod("setname",string.class ,int.class);//第一个参数是方法名,后面的是方法里的参数

system.out.println("method2: "   method2);

//4、执行方法!

object obj = clazz.newinstance();

method2.invoke(obj, "changwen", 22);

}

getmethods: tostring, getname, setname, setname, setage,

getage, wait, wait, wait, equals, hashcode, getclass, notify, notifyall,

getdeclaredmethods: tostring, getname, setname, setname, setage, getage, privatemthod,

method : public void com.java.reflection.person.setname(java.lang.string)

method2: public void com.java.reflection.person.setname(java.lang.string,int)

无参构造器

name: changwen

age:22

6、invoke方法

public class personinvoke {

public personinvoke() {

}

private string method2() {

return "person private string method2";

}

}

public class studentinvoke extends personinvoke{

private void method1(integer age) {

system.out.println("student private void method1, age=:"  age);

}

}

获取当前类的父类定义的私有方法

/**

* 获取当前类的父类中定义的私有方法

* 直接调用getsuperclass()

*/

@test

public void testgetsuperclass() throws exception {

string classname = "com.java.reflection.studentinvoke";

class clazz = class.forname(classname);

class superclazz = clazz.getsuperclass();

system.out.println(superclazz);

//输出结果:class com.java.reflection.personinvoke

}

另一种写法

/**

* @param classname  某个类的全类名

* @param methodname 类的一个方法的方法名,该方法也可能是私有方法

* @param args  调用该方法需要传入的参数 ...可变参数的意思

* @return 调用方法后的返回值

*/

public object invoke(string classname, string methodname, object ... args) {

object obj = null;

try {

obj = class.forname(classname).newinstance();

return invoke(obj, methodname, args);

} catch (instantiationexception e) {

e.printstacktrace();

} catch (illegalaccessexception e) {

e.printstacktrace();

} catch (classnotfoundexception e) {

e.printstacktrace();

}

return invoke(null, methodname, args);

}

/**

* @param obj  方法执行的那个对象

* @param methodname 类的一个方法的方法名,该方法也可能是私有方法,还可能是该方法在父类中定义的私有方法

* @param args  调用该方法需要传入的参数 ...可变参数的意思

* @return 调用方法后的返回值

*/

public object invoke(object obj, string methodname, object ... args) {

//1、获取method对象

class [] parametertypes = new class[args.length];

for (int i=0 ; i

parametertypes[i] = args[i].getclass();

}

try {

//2、执行method方法

method method = getmethod(obj.getclass(), methodname,parametertypes);

//通过反射执行private方法

method.setaccessible(true);

//3、返回方法的返回值

return method.invoke(obj,args);

} catch (exception e) {

}

return null;

}

/**

* 获取clazz 的methodname 方法, 该方法可能是私有方法,还可能是父类中的私有方法

*/

public method getmethod(class clazz, string methodname, class ... parametertypes) {

//注意这个循环里的内容!!!

for (; clazz != object.class; clazz = clazz.getsuperclass()){

try {

return clazz.getdeclaredmethod(methodname, parametertypes);

} catch (exception e) { //这里要写exception,不然会出错,应该是有部分异常没有捕获

}

}

return null;

}

测试:

@test

public void testinvoke2() {

object obj = new studentinvoke();

invoke(obj, "method1", 10);

object result = invoke(obj, "method2");

system.out.println(result);

}

private void method1,age:10

person private string method2

7、field字段

public class person {

public string name;

private integer age;

public person() {

}

public person(string name, integer age) {

this.name = name;

this.age = age;

}

}

/**

* field: 封装了字段的信息

*/

@test

public void testfield() throws

classnotfoundexception, nosuchfieldexception, illegalaccessexception {

class clazz = class.forname("com.java.reflection.person");

//1、获取字段

//1.1 获取field的数组,私有字段也能获取

field[] fields = clazz.getdeclaredfields();

for (field field: fields) {

system.out.print(field.getname()   ", ");

}

//1.2 获取指定名字的field(如果是私有的,见下面的4)

field field = clazz.getdeclaredfield("name");

system.out.println("\n获取指定field名=: "   field.getname());

person person = new person("abc", 12);

//2、获取指定对象的field的值

object val = field.get(person);

system.out.println("获取指定对象字段'name'的field的值=: "   val);

//3、设置指定对象的field的值

field.set(person, "changwen2");

system.out.println("设置指定对象字段'name'的field的值=: "   person.name);

//4、若该字段是私有的,需要调用setaccessible(true)方法

field field2 = clazz.getdeclaredfield("age");

field2.setaccessible(true);

system.out.println("获取指定私有字段名=: "   field2.getname());

}

name, age,

获取指定field名=: name

获取指定对象字段'name'的field的值=: abc

设置指定对象字段'name'的field的值=: changwen2

获取指定私有字段名=: age

/**

* 一个实例:

* 反射获取一个继承person2的student类

* 设置字段"age"=20(该字段可能为私有,可能在其父类中)

*/

@test

public void testclassfield() throws classnotfoundexception, illegalaccessexception, instantiationexception {

string classname = "com.java.reflection.student";

string fieldname = "age";  //可能为私有,可能在其父类中

object val = 20;

//创建classname 对应类的对象,并为其fieldname赋值为val

class clazz = class.forname(classname);

field field = null;

for (class clazz2 = clazz; clazz2 != object.class; clazz2 = clazz2.getsuperclass()){

try {

field = clazz2.getdeclaredfield(fieldname);

} catch (exception e) {

}

}

object obj = clazz.newinstance();

assert field != null;

field.setaccessible(true);

field.set(obj, val);

student stu = (student) obj;

system.out.println("age = "   stu.getage());

}

8、构造器(constructor)

/**

* 构造器:开发用的比较少

*/

@test

public void testconstructor() throws classnotfoundexception, nosuchmethodexception,

illegalaccessexception, invocationtargetexception, instantiationexception {

string classname = "com.java.reflection.person";

class clazz = (class) class.forname(classname);

//1.获取constructor对象

constructor[] constructors =

(constructor[]) class.forname(classname).getconstructors();

for (constructor constructor: constructors) {

system.out.println(constructor);

}

constructor constructor = clazz.getconstructor(string.class, integer.class);

system.out.println("指定的-->"   constructor);

//2.调用构造器的newinstance()方法创建对象

object obj= constructor.newinstance("changwen", 11);

}

public com.java.reflection.person()

public com.java.reflection.person(java.lang.string,java.lang.integer)

指定的-->public com.java.reflection.person(java.lang.string,java.lang.integer)

9、注解(annotation)

•从 jdk5.0 开始,java 增加了对元数据(metadata)的支持,也就是annotation(注释)

•annotation其实就是代码里的特殊标记,这些标记可以在编译,类加载, 运行时被读取,并执行相应的处理.通过使用annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息.

•annotation 可以像修饰符一样被使用,可用于修饰包,类,构造器, 方法,成员变量, 参数,局部变量的声明,这些信息被保存在annotation的 “name=value”对中.

•annotation能被用来为程序元素(类,方法,成员变量等)设置元数据

基本的 annotation

•使用 annotation时要在其前面增加@符号,并把该annotation 当成一个修饰符使用.用于修饰它支持的程序元素

•三个基本的annotation:

–@override:限定重写父类方法,该注释只能用于方法

–@deprecated:用于表示某个程序元素(类,方法等)已过时

–@suppresswarnings:抑制编译器警告.

自定义 annotation

•定义新的 annotation类型使用@interface关键字

•annotation 的成员变量在annotation 定义中以无参数方法的形式来声明.其方法名和返回值定义了该成员的名字和类型.

•可以在定义annotation的成员变量时为其指定初始值,指定成员变量的初始值可使用default关键字

•没有成员定义的annotation称为标记;包含成员变量的annotation称为元数据annotation

@retention(retentionpolicy.runtime) //运行时检验

@target(value = {elementtype.method})  //作用在方法上

public @interface agevalidator {

int min();

int max();

}

/**

* 通过反射才能获取注解

*/

@test

public void testannotation() throws exception {

//这样的方式不能使用注解

person3 person3 = new person3();

person3.setage(10);*/

string classname = "com.java.reflection.person3";

class clazz = class.forname(classname);

object obj = clazz.newinstance();

method method = clazz.getdeclaredmethod("setage",integer.class);

int val =40;

//获取注解

annotation annotation = method.getannotation(agevalidator.class);

if (annotation != null){

if (annotation instanceof agevalidator){

agevalidator agevalidator = (agevalidator) annotation;

if (valagevalidator.max()){

throw new runtimeexception("数值超出范围");

}

}

}

method.invoke(obj, val);

system.out.println(obj);

}

提取 annotation信息

•jdk5.0 在 java.lang.reflect包下新增了 annotatedelement接口,该接口代表程序中可以接受注释的程序元素

•当一个 annotation类型被定义为运行时annotation后,该注释才是运行时可见,当 class文件被载入时保存在 class文件中的 annotation才会被虚拟机读取

•程序可以调用annotationelement对象的如下方法来访问 annotation信息

–获取 annotation实例:

•getannotation(class annotationclass)

jdk 的元annotation

•jdk 的元annotation 用于修饰其他annotation 定义

•@retention:只能用于修饰一个 annotation定义,用于指定该 annotation可以保留多长时间,@rentention包含一个retentionpolicy类型的成员变量,使用 @rentention时必须为该 value成员变量指定值:

–retentionpolicy.class:编译器将把注释记录在 class文件中.当运行 java程序时,jvm 不会保留注释.这是默认值

–retentionpolicy.runtime:编译器将把注释记录在class文件中. 当运行 java 程序时, jvm 会保留注释. 程序可以通过反射获取该注释

–retentionpolicy.source:编译器直接丢弃这种策略的注释

•@target: 用于修饰annotation 定义,用于指定被修饰的 annotation能用于修饰哪些程序元素.@target 也包含一个名为 value的成员变量.

•@documented:用于指定被该元 annotation修饰的 annotation类将被 javadoc工具提取成文档.

•@inherited:被它修饰的 annotation将具有继承性.如果某个类使用了被@inherited 修饰的annotation, 则其子类将自动具有该注释

总结

以上是凯发k8官方网为你收集整理的java反射机制详解_java反射机制详解的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得凯发k8官方网网站内容还不错,欢迎将凯发k8官方网推荐给好友。

网站地图