JAVA中的反射
1.简介:
1.java提供的一套API。
2.提供了检查一个对象的内部结构的手段。
3.反射API可以:
3.1动态加载类.
3.2动态创建对象.
3.3动态访问属性.
3.4动态调用方法。
2.通过反射获取对象的相关属性的方法
1.通过反射可以检查对应的类型的内部结构
动态获取obj类型Object类提供了一个方法getClass()返回一个Class类。
Class cls=obj.getClass();
System.out.println("cls的类是"+cls);
2.检查对象类型中声明了那些属性
Class类提供了getDeclaredfields();返回一个Field[]数组。
Declared:声明的,定义的意思。
Fields:字段,属性的意思。
Field[] field=cls.getDeclaredFields();
//System.out.println(field.length);
for(Field f:field){
System.out.println("cls类中的属性"+f);
}
3.通过放射获取对象中指定的属性
Class类提供了getDeclaredField(string name)
name:指对象中的属性
try {
Field fie=cls.getDeclaredField("hash");
System.out.println("包含hash的属性是"+fie);
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
4.通过反射获取对象中的所有的方法
Class类提供了getDeclaredMethods()返回Methods[]数组
Method[] methods=cls.getDeclaredMethods();
//System.out.println(methods.length);
for(Method m:methods){
System.out.println("cls对象中的方法:"+m);
}
5.通过反射获取对象中指定的方法
Class类提供了getDeclaredMethod(String name,ParemterType type)
name:指方法的名字;
type:指该方法中的参数的类型,如果是多个参数则用“,”隔开;
try {
Method method=cls.getDeclaredMethod("valueOf",char[].class,int.class,int.class);
System.out.println("找到了"+method);
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
6.通过反射获取所有的构造方法
Class类提供了getDeclaredConstructors()返回Constructor[]数组
Constructor[] cons=cls.getDeclaredConstructors();
System.out.println(cons.length);
for(Constructor c:cons){
System.out.println(c);
}
7.通过反射获取指定的构造方法
Class类提供了getDeclaredConstructor(ParemterType type,…)返回Constructor
try {
Constructor con=cls.getDeclaredConstructor(byte[].class,int.class,int.class);
System.out.println(con);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
2.动态加载类
1.通过反射动态加载类,返回一个Class实例
通过反射动态加载类,Class类提供了一个静态方法ForName(string className) 返回一个class实例
public class ClassForNmaeReflect {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入类名:");//包名+类名
String className=scanner.next();
try {
Class cls=Class.forName(className);
//在Class类中提供了newInstance()来创建对象的实例化
Object obj=cls.newInstance();
System.out.println("输出:"+bj);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
自定义类Demo:
public class Demo {
private String name="bat";
public int age=1;
public void run(){
System.out.println("bat牛啊!");
}
private String run2(String name,int age){
System.out.println(name+",今年:"+age+"岁");
return "成功!";
}
static{
System.out.println("静态块");
}
public String toString() {
return "Demo [name=" + name + ", age=" + age + "]";
}
}
执行结果:
请输入类名:
day16.Demo
输出:静态块Demo
[name=bat, age=1]
2.通过反射动态加载类只加载一次
public class ClassForNmaeReflect02 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入类名:");//包名+类名
String className=scanner.next();
//动态加载类
try {
Class cls=Class.forName(className);
Class cls1=Class.forName(className);
Class cls2=Class.forName(className);
System.out.println(cls==cls1);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
执行结果:
请输入类名:
day16.Demo
静态块
true
3.通过反射获取对象中的属性值及其私有属性
1.Field提供了一个方法setAccessible(true),该方法可以打开原有的私有属性的访问权限,还可以打开任何不可见的属性,方法的访问权限在获取属性或者方法值之前打开该访问权限 。
2.在object对象上获取属性的值,Field提供了一个方法get(object obj),从而获取到对象中的指定属性。
3.属性名是用户运行期间输入的,输入的那个属性名这段程序就会输出哪个属性的值,也就是意味,程序与属性之间是松耦合关系。
public class ClassForNmaeReflect03 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入类名:");//包名+类名
String className=scanner.next();
System.out.println("请输入属性名:");//方法名或属性
String methodName=scanner.next();
//动态加载类
try {
Class cls=Class.forName(className);
//通过反射获取对象中指定的属性
Field field=cls.getDeclaredField(methodName);
//通过反射创建对象
Object obj=cls.newInstance();
/*
*field提供了一个方法setAccessible(true),该方法可以打开原有的私有属性
*的访问权限,还可以打开任何不可见的属性,方法的访问权限
*在获取属性或者方法值之前打开该访问权限
*/
field.setAccessible(true);
//在object对象上获取属性的值,field提供了一个方法get(object obj),
//从而获取到对象中的指定属性
Object ob=field.get(obj);//动态获取属性值
/*
* 属性名是用户运行期间输入的,输入的那个属性名这段程序就会输出哪个属性的值,
* 也就是意味,程序与属性之间是松耦合关系。
*/
System.out.println(field+",的值是"+ob);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
执行结果:
请输入类名:
day16.Demo
请输入属性名:
age
静态块
public int day16.Demo.age,的值是1
4.通过反射动态获取对象中的方法返回值
1.Method提供了invoke(OBject obj,Paremter(参数),…)获取方法体
public class ClassForNmaeReflect04 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入类名:");//包名+类名
String className=scanner.next();
System.out.println("请输入方法名:");//方法名或属性
String methodName=scanner.next();
//动态加载类
try {
Class cls=Class.forName(className);
//通过反射获取指定的方法
Method method=cls.getDeclaredMethod(methodName, String.class,int.class);
//通过反射创建对象实例化
Object obj=cls.newInstance();
//打开访问权限
method.setAccessible(true);
//Method提供了invoke(OBject obj,Paremter(参数),..)获取方法体
Object ob=method.invoke(obj,"超",20);
//获取方法的返回值,如果没有返回值,则返回null
System.out.println(ob);
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行结果:
请输入类名:
day16.Demo
请输入方法名:
run2
静态块
超,今年:20岁
成功!
2.getDeclaredMethod和getMethod区别:
getDeclaredMethod:获取当前类Class中的方法。
getMethod:获取当前类中的所有方法。
5.通过反射动态调用该对象的方法
1.设置抽象类HttpServlet
public abstract class HttpServlet {
public abstract void service(String name,int age);
}
2.LoginServlet继承抽象类HttpServlet并重写service方法
public class LoginServlet extends HttpServlet{
public void service(String name,int age){
System.out.println("这是LoginServlet()");
}
}
3.同过反射调用该对象的方法
public class ClassForNmaeReflect06 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入类名:");//包名+类名
String className=scanner.next();
try {
//动态加载类
Class cls=Class.forName(className);
//通过反射创建实例化
HttpServlet obj=(HttpServlet)cls.newInstance();
obj.service("liu",33);
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行结果:
请输入类名:
day16.LoginServlet
这是LoginServlet()