老生常谈Java反射机制(必看篇)
什么是反射机制
反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。这个能特定我们不常看到,但是在其他的比如C或者C++语言中很不就存在这个特性。一个常见的例子是在JavaBean中,一些组件可以通过一个构造器来操作。这个构造器就是用的反射在动态加载的时候来获取的java中类的属性的。
主要的类
Class类的实例表示正在运行的Java应用程序中的类和接口。Class没有公共的构造方法,Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的
Constructor提供关于类的单个构造方法的信息以及对它的访问权限(主要提供的是对构造方法使用)
Method提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)
Field主要提供对类中的成员变量的访问和使用
Class
Class类也使用了泛型,即是Class
常用的方法
getConstructor(Class[]params)获取公共的(public)的构造方法,并且限定其中的参数个数和类型可以获得不同的公共构造方法
Constructor[]getConstructors()返回所有的公共(public)的构造方法
getDeclaredConstructor(Class[]params)获取所有指定的构造方法,但是需要注意的是当获取私有的构造方法的时候需要使用setAccessible设置访问权限为true才能进行构造,否则出现异常
Constructor[]getDeclaredConstructors()返所有的构造方法包括public和private,protected修饰的
TnewInstance()返回的是一个调用默认的构造方法(publicclass_name())实例化的一个Object对象,如果使用泛型那么就返回T类型的,反之返回的是Object需要强制转换才能使用这个对象调用成员函数和成员变量
ClassforName(Stringclass_name)返回class对象,每一个对都有一个方象法返回Class对象(test.class)
PackagegetPackage()返回此类所在的包名(packagedemo)当然也可以使用Package.getName()获得包的名字(demo)比如constructor.getPackage().getName()
intgetModifiers()返回的是类的修饰符的整数类型(修饰符的类型有publicprivateprotected)其中得到整数可以使用Modifier中toString(intnum)得到public,private,protected的类型,比如Modifier.toString(class1.getModifiers())
*MethodgetMethod(Stringname,Class>...parameterTypes)返回指定参数的方法Method对象,注意这里仅仅是返回的时公共的方法(public)比如:Methodmethod=class1.getMethod("display",newClass[]{int.class})这里的display是方法的名字,有一个参数,类型为int
Method[]getMethods()获取所有的公共的方法(public)返回的是一个数组(Method)
MethodgetDeclaredMethod(Stringname,Class>...parameterTypes)返回所有的指定的参数的方法(public,private,protected,但是不包括继承的),其中参数可以为null(无参数)
Method[]getDeclaredMethods()获取所有的方法
FieldgetField(Stringname)指定名字的公共成员变量(public)
Field[]getFields()获取所有的公共的成员变量
FieldgetDeclaredField(Stringname)获取所有的指定名称的成员变量(public,protected,private),同样在调用私有成员变量的时候需要先设置访问的权限,field.setAccessible(true)
Field[]getDeclaredFields()获取所有的成员变量(public,protected,private)
getSuperclass()返回表示此Class所表示的实体(类、接口、基本类型或void)的超类的Class。
URLgetResource(Stringname)查找指定名称的资源(图片,文件...)注意这个资源一定要和指定类在一个包中,否则返回null,比如查找Test类下的airplane.png图片:Test.class.getResource("airplane.png")这里返回的将是绝对路径
获取Class的对象并且实例化
使用Class.forName(StringclassName)其中className一定是包含包的名字,下面的demo就是包的名字,Test是类的名字。这是最常用的方法,学过JDBC的都知道加载驱动的时候就是使用的Class.forName()
/*
*第一种使用forName(StringclassName),其中className一定是包含包的名字,下面的demo就是包的名字,Test是类的名字
*/
Classcls=Class.forName("demo.Test");
Testtest=(Test)cls.newInstance();//这里只是使用了默认的构造方法实例化对象
使用类名.class
Classcls=Test.class;
使用对象.getClass()
Testtest=newTest(); Classcls=test.getClass();
Constructor
主要是用来对类的构造方法进行操作的,可以看出这个也使用了泛型,和上面的Class是一样的,注意这里如果没有使用泛型,那么原本放回T类型的现在都是返回Object
常用的方法
TnewInstance(Objectparms)使用带有参数的构造方法实例化对象,如果使用了泛型,那么返回的就是T类型的,反之返回的是Object类型的,需要强制转换
getName()以字符串的形式返回构造方法的名称,具体的路径包含包名(demo.Test)
intgetModifiers()和Class类中的方法一样
Method
主要提供的是对类中的方法的操作
常用的方法
Objectinvoke(Objectobj,objectargs)使用得到的Method对象调用方法,obj是类的已经构造好的对象,如果是静态方法直接写null,因为静态方法的调用不需要对象,返回值是Object类型的,如果接受返回值,需要使用强制转换成相应的类型,args是传入的参数,如果有多个参数,那么可以直接在后面用逗号添加或者直接创建数组newObject[]{22,"chenjiabing"}比如:method.invoke(test,22,"chenjiabing")method.invoke(test,newObject[]{22,"chenjiabing"})注意:如果调用的private类型的方法,那么需要在前面设置访问的权限,method.setAccessible(true)
StringgetName()返回此方法的名字(display)
ModifiergetModifiers()返回此方法的修饰符的类型表示的整数(public,private...),可以使用Modifier.toString()转换成字符串形式
ClassgetReturnType()返回这个方法的返回类型
StringtoString()返回这个方法表示的字符串的形式
Field
主要提供对类的成员变量的操作
常用方法
StringgetName()返回变量名字
Objectget(Objectobj)返回此变量在指定对象中的值,因为在构造对象的时候每一个传入的变量的值都不一样,因此需要使用对象obj。obj表示传入的对象,返回的Object类型,因此需要强制转换
voidset(Objectobj,Objectvalue)改变obj对象上的变量的值为value
ModifiergetModifiers()返回整数表示修饰的类型
StringgetType()获取变量的类型(int,String,doublefloat.....)
Modifier
Modifier类提供了static方法和常量,对类和成员访问修饰符进行解码。修饰符集被表示为整数,用不同的位位置(bitposition)表示不同的修饰符。
常用的方法
staticStringtoString(intmode)将代表修饰符的整数形式转换为字符串形式的修饰符,比如将1转换成public
staticisInterface(intmode)如果整数参数包括interface修饰符,则返回true,否则返回false
staticisStatic(intmode)
staticisPrivate(intmode)
staticisPublic(intmode)
staticisAbstract(intmode)
实例
Modifier.toString(Test.class.getModifiers())//得到Test类的修饰符
使用
有了上面的铺垫,我们就可以使用上面的这些类进行操作了,在进行操作之前,我们需要先定义一个类Test,放在demo包下,内容如下
packagedemo;
importjava.util.jar.Attributes.Name;
importjavax.print.attribute.standard.MediaSize.NA;
publicclassTest{
publicStringname;
privateintage;
publicTest(){
this.name="陈加兵";
this.age=23;
}
publicTest(Stringname,intage){
this.name=name;
this.age=age;
}
publicvoiddisplay(){
System.out.println("name="+this.name+"----age="+this.age);
}
publicvoidset(Stringname,intage){
this.name=name;
this.age=age;
}
privateintgetAge(){
returnthis.age;
}
}
实例化对象
使用Class默认的构造newInstance()
Classclass1=Class.forName("demo.Test");//静态加载Class
Testtest=(Test)class1.newInstance();//调用默认的构造方法(publicTest())实例化对象,由于没有使用泛型,因此需要强转
test.display();//调用display方法
使用Class中的getConstructor()方法构造对象,需要注意的使用private类型构造方法时一定要先设置访问权限为true-constructor.setAccessible(true);
/*
*调用publicTest(Stringname,intage)得到Constructor的两种形式
*1.Constructorconstructor=class1.getConstructor(newClass[]{String.class,int.class});
*2.Constructorconstructor=class1.getConstructor(String.class,int.class);这个和上面的是一样的,就是使用的参数形式不一样
*
*
*
*
*使用newInstance()构造对象的两种方式
*1.Testtest=(Test)constructor.newInstance(newObject[]{"chenjiabing",22});
*2.Testtest=(Test)constructor.newInstance("chenjiabing",22);只是形式不同而已,不过我还是喜欢上面的形式
*
*/
/*
*调用publicTest(Stringname,intage)
*Class.getConstructor()得到的是公共的构造方法,如果有私有的构造方法,那么就会报错,这时就要使用getDeclaredConstructor(Class>...parameterTypes)
*Testtest=(Test)constructor.newInstance("陈加兵",22);
*
*
*调用publicTest()
*Constructorconstructor=class1.getConstructor(null);
*Testtest=(Test)constructor.newInstance(null);
*
*
*调用privateTest(intage)
*Constructorconstructor=class1.getDeclaredConstructor(newClass[]{int.class});
constructor.setAccessible(true);//因为private类型是不可以直接访问的,因此需要设置访问权限为true
Testtest=(Test)constructor.newInstance(newObject[]{1000});
*/
Classclass1=Class.forName("demo.Test");
//访问publicTest(Stringname,intage)
//Constructorconstructor=class1.getConstructor(newClass[]{String.class,int.class});
//Testtest=(Test)constructor.newInstance("陈加兵",22);
//访问默认的构造方法
//Constructorconstructor=class1.getConstructor(null);
//Testtest=(Test)constructor.newInstance(null);
//访问private类型的构造方法
Constructorconstructor=class1.getDeclaredConstructor(newClass[]{int.class});
constructor.setAccessible(true);
Testtest=(Test)constructor.newInstance(newObject[]{1000});
test.display();
成员方法的操作
使用Class.getMethod()和Class.getDeclaredMethod()方法获取方法,这两个方法的区别前面已经说过了,注意的是调用私有成员方法的之前一定要设置访问权限(method.setAccessible(true))
Method类中的其他方法前面也已经说过了,详细使用请自己尝试
/*
*获取Method对象的两种方式:
*1.Methodmethod_set=class1.getMethod("set",newClass[]{String.class,int.class});
*2.Methodmethod_set=class1.getMethod("set",String.class,int.class);
*
*
*使用Method.invoke()调用方法的两种方式
*1.Objecto=method_set.invoke(test,newObject[]{"陈加兵",200});
*2.Objectobject=method_set.invoke(test,"陈加兵",2000);
*/
/*
*获取公共方法(public):
*1.Methodmethod=class1.getMethod("display",null);//publicvoiddisplay()
*2.Methodmethod_set=class1.getMethod("set",newClass[]{String.class,int.class});//获取publicvoidset(Stringname,intage)
*
*
*获取私有方法(private,protected)
*1.Methodmethod_getAge=class1.getDeclaredMethod("getAge",null);
*/
//使用构造方法构造一个Test对象
Classclass1=Class.forName("demo.Test");
Constructorconstructor=class1.getDeclaredConstructor(newClass[]{String.class,int.class});
Testtest=constructor.newInstance(newObject[]{"陈加兵",22});
Methodmethod=class1.getMethod("display",null);//获取publicvoiddisplay()方法的Method对象
Objectobj=method.invoke(test,null);//调用方法display
//获取publicvoidset(Stringname,intage)
//Methodmethod_set=class1.getMethod("set",newClass[]{String.class,int.class});
Methodmethod_set=class1.getMethod("set",String.class,int.class);
//Objecto=method_set.invoke(test,newObject[]{"陈加兵",200});
Objectobject=method_set.invoke(test,"陈加兵",2000);
test.display();
//获取私有方法privateintgetAge()
Methodmethod_getAge=class1.getDeclaredMethod("getAge",null);
method_getAge.setAccessible(true);//必须设置访问权限为true
//判断返回值类型是否为int类型的
if("int".equals(method_getAge.getReturnType().toString()))
{
intReturnData=(int)method_getAge.invoke(test,null);//调用并且获取返回值
System.out.println(ReturnData);
}
成员变量的操作
主要使用的Field类,前面已经详细的说过了
/*
*获取public修饰的成员变量:
*1.Fieldfield=class1.getField("name");//获取public的成员变量name的Filed对象
*
*获取private,protected修饰的成员变量:
*1.Fieldfield2=class1.getDeclaredField("age");
*/
Classclass1=Class.forName("demo.Test");
Testtest=newTest("陈加兵",1000);
Fieldfield=class1.getField("name");//获取public的成员变量name的Filed对象
System.out.println(field.get(test));//获得test对象中的name属性的值
//获取privateintage的Field对象
Fieldfield2=class1.getDeclaredField("age");
field2.setAccessible(true);//设置访问权限
System.out.println(field2.get(test));
以上这篇老生常谈Java反射机制(必看篇)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。