一.概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
二.Class类的使用
在面向对象的世界中万事万物皆对象,在java中除了普通数据(但有封装类)和静态类(属于类)不是对象外 其它都为对象。
那么类是对象吗?是谁的对象呢?类是对象,是java.lang.class的对象。
反射机制获取类的3中方法
首先我们可以看看class的源代码,会发现这行代码
私有的构造方法,只有java虚拟机才能创建对象 所以我们不可以通过new 来创建对象
但是还有三种其它的方法可以创建对象
package reflect;
/**
* @author scx
*Class类的使用
*/
public class Main {
public static void main(String[] args) {
Fool fool=new Fool();
//第一种方式 任何一个类都有一个隐含的静态成员变量class
Class c1=Fool.class;
//第二种方式 可以通过类的对象getClass方法
Class c2=fool.getClass();
//第三种方式 通过完整的包名和类名
Class c3=null;
try {
c3=Class.forName("reflect.Fool");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*
* c1,c2,c3代表了Fool类的类类型 是class的实例对象
* 这个对象我们称为该类的类类型
*/
System.out.println("c1="+c1);
System.out.println("c2="+c2);
System.out.println("c3="+c3);
}
}
//Fool 是java.lang.class的对象
class Fool{}
运行结果
c1=class reflect.Fool
c2=class reflect.Fool
c3=class reflect.Fool
三.创建对象使用 newInstance方法
try {
Fool fool2=(Fool) c1.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
四.动态加载类
1.什么是动态加载类 什么是静态加载类
Class.forName 不仅表示类的类类型,还代表了动态加载类。编译时加载是静态加载类,
运行时加载是动态加载类。
请大家区分编译 运行。
2.为何要使用动态加载类
我们写了一个程序 并没有写A类和B类以及start方法
public class Main{
public static void main(String args[]){
if("A".equals(args[0])){
A a=new A();
a.start();
}
if("B".equals(args[0])){
B b=new B();
b.start();
}
}
}
编译:
我们会发现,我们并不一定用到A功能或B功能,可是编译却不能通过。而在日常的项目中,如果我们写了100个功能,因为一个功能的原因而导致所有功能不能使用,明显使我们不希望的。在这里,为什么会在编译时报错呢?new 是静态加载类,在编译时刻就需要加载所有可能使用到的功能。所以会报错。而在日常中我们希望用到哪个就加载哪个,不用不加载,就需要动态加载类。
使用动态加载类时,我们不用定义100种功能,只需要通过实现某种标准(实现某个接口)。
代码:
public class Main{
public static void main(String args[]){
try{
Class c=Class.forName(args[0]);
All a=(All)c.newInstance();
a.start();
}catch(Exception e){
e.printStackTrace();
}
}
}
class A implements All{
public void start(){
System.out.println("A....START");
}
}
class B implements All{
public void start(){
System.out.println("B....START");
}
}
//接口
interface All{
public void start();
}
总结:推荐大家使用动态加载类。原因如上,即节省了代码,又简洁方便,安全。
学习java反射的时候 看到了这 理解的比较浅显 ,肯定有许多要补充的。慢慢学习 慢慢积累 欢迎评论
五.获取类的方法信息
getMethods()方法获取的是所有的public的函数 包括父类继承
getDeclaredMethods()方法获取的是所有该类自己声明的方法
package reflect;
import java.lang.reflect.Method;
public class ClassDemo {
public static void main(String[] args) {
//获取类的信息 首先获取类类型
Class c=Book.class;
//获取包名+类名
System.out.println(c.getName());
//获取类名
System.out.println(c.getSimpleName());
/*
* Method类 方法对象
* 一个成员就是一个Method对象
* getMethods()方法获取的是所有的public的函数 包括父类继承
* getDeclaredMethods()方法获取的是所有该类自己声明的方法
*/
Method []ms=c.getDeclaredMethods();
for(Method method:ms){
//得到方法的返回值类型的类类型
Class returnType=method.getReturnType();
System.out.print("返回值类型:"+returnType+"\t");
//得到方法的名称
System.out.print(method.getName()+"(");
//获取参数的类类型
Class[] paramTypes=method.getParameterTypes();
for (Class paramType : paramTypes) {
System.out.print(paramType.getName()+" ");
}
System.out.println(")");
}
}
}
class Book extends Rect{
private int price;
private String name;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Rect{
private int width;
private int height;
public void setRect(int width,int height){
this.width=width;
this.height=height;
}
}
运行结果:
当然还有获得类的成员变量 构造方法 ,实现接口,父类,访问权限,包名,等等。
只要我们记得 无论获得什么 首先要获取类的类类型 ,其它通过阅读api文档 轻而易举~
六.获取指定的方法
getDeclaredMethod(name, parameterTypes) name为方法名 parameterTypes为参数类型数组
举个例子
package reflect;
import java.lang.reflect.Method;
public class MethodDemo1 {
public static void main(String[] args) throws Exception {
/*
* 若想获取print方法 首先获得类的信息 若想获得类的信息 首先获取类类型
*/
A a = new A();
Class c = A.class;
Method m1 = c.getDeclaredMethod("print", int.class, int.class);
// 方法的反射操作 invoke方法 第一个参数为要操作的对象
Object o = m1.invoke(a, 5, 6);// 和a1.print(5,6) 同样效果
Method m2=c.getDeclaredMethod("print",String.class,String.class);
Object o2=m2.invoke(a,"Hello","World");//和a1.print(Hello,World) 同样效果
Method m3=c.getDeclaredMethod("print");
Object o3=m3.invoke(a);//和a1.print() 同样效果
}
}
class A {
public void print(){
System.out.println("A");
}
public void print(int a, int b) {
System.out.println(a + b);
}
public void print(String a, String b) {
System.out.println(a.toLowerCase() + b.toUpperCase());
}
}
运行结果:
11
helloWORLD
A