java反射是什么
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
一般功能性的类,都会采用动态加载的方式
一.Class类简单介绍
1.什么是Class类
Class类简单说就是任何一个类的类型,因为我们常说,java是面向对象的,一切都是对象,而对象又是它属于所属类的一个实例,那么它所属的类又是谁的实例呢?答案就是Class类。
简而言之,Class类就是java中所有类的类,或者说java中所有的类都是Class类的对象。
下面我们一起来看Class类的简单使用。
2.创建Class的对象的三种方法
注:MyClassTest 类声明
package fanshe;
public class MyClassTest {
MyClassTest() {}
public void print() {
System.out.println("MyClassTest.print()");
}
// 该静态方法用于验证疑问
public static void staticPrint() {
System.out.println("MyClassTest.staticPrint()");
}
}
// 1.通过类的隐含的静态属性class创建
**此方法说明每一个类默认有一个隐含的静态属性class**
Class c1 = MyClassTest.class;
// 2. 通过对象的getClass方法创建
MyClassTest t1 = new MyClassTest();
Class c2 = t1.getClass();
// 3. 通过 CLass类的Class.forName()方法创建
// 由参数指定要创建的类型
Class c3 = null;
try {
c3 = Class.forName("fanshe.MyClassTest");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
验证:
3.Class类的对象的使用
我们通过前面三种方式得到了Class类的对象,那么得到这个对象有什么用呢?
看如下代码:
try {
MyClassTest t4 = (MyClassTest)c1.newInstance();
// newInstance()方法需要该类有无参的构造方法支持
// 而且new出来的对象需要强转
t4.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
简单分析上述代码的作用
1)c1是一个Class类的关于MyTest类型的对象,我们想创建一个MyTest类型的对象可以通过new的方式
2)想通过c1这个对象创建MyTest类型的对象则需要调用Class类的newInstance()方法创建,但是创建的是模板类型 T ,所以要强转成MyTest类型,然后才能调用MyTest类型的print() 方法
附newInstance()方法的源代码的首行:
@CallerSensitive
public T newInstance() throws InstantiationException, IllegalAccessException {
4.一个疑问
我们通过前面三种方式得到了Class类的对象,而Class类是一切类的类型,从某种层面上来讲,似乎Class类的关于MyTest类型的对象和MyTest类是同一个层面上的,通常情况下,我们得到一个类的时候,我们可以直接使用这个类的一些静态方法和属性,那么我们这种方式得到的Class类的关于MyTest类型的对象行不行呢?
验证:
显然答案是不可以!!!
因为Class类的对象本质是属于Class类型的,只能调用Class类的方法和属性,这是面向对象的基础!
那么怎么才能通过某一个类的Class类的对象调用该类的方法呢?
请看第七部分,实战2,。
5.基本的内置类型,包括void都存在class属性
Class c5 = int.class;
Class c6 = double.class;
Class c7 = void.class;
Class c8 = String.class;
System.out.println(c5.getName());
System.out.println(c6.getName());
System.out.println(c7.getName());
System.out.println(c8.getName());
运行结果:
int
double
void
java.lang.String
6.实战1 ------ 通过反射获得类的所有信息,包括类的成员方法、成员变量、构造函数
package fanshe;
import java.lang.reflect.Method;
public class ClassUtil {
/**
*
* @param o 传递一个对象
*
*/
public static void getClassMessage(Object o ) {
Class c = o.getClass(); //得到的是所传递的对象的类类型
// 得到类的名称
System.out.println("类的名称:"+c.getName());
// 获得类的方法
Method[] methods = c.getMethods(); //获得所有public的方法,包括继承自父类的方法
//c.getDeclaredMethods()获得所有的自己声明的方法
for (int i =0;i<methods.length;i++) {
Class rt = methods[i].getReturnType(); //得到返回值的类类型,比如java.leng.Strig
System.out.print(rt.getSimpleName()+" "); //得到类名 比如String
System.out.print(methods[i].getName()+"("); //得到方法名
Class[] parmType = methods[i].getParameterTypes();
for(int j=0;j<parmType.length;j++) {
System.out.print(parmType[j].getSimpleName()+",");
}
System.out.println(")");
}
System.out.println("##############################");
// 同样的,我们来获取成员变量
Field[] fields = c.getDeclaredFields();
for(int i =0;i<fields.length;i++) {
Class returnType = fields[i].getType();
System.out.print(returnType.getSimpleName()+" ");
System.out.println(fields[i].getName());
}
}
/**
* 获取构造函数的信息
*/
public static void printConstructorMessage(Object o) throws NoSuchMethodException {
Class c = o.getClass();
Constructor[] cs = c.getDeclaredConstructors();
for (int i = 0; i <cs.length ; i++) {
System.out.print(cs[i].getName()+" (");
Class[] returnType = cs[i].getParameterTypes();
for (int j = 0; j < returnType.length ; j++) {
System.out.print(returnType[j].getSimpleName()+",");
}
System.out.println(")");
}
}
}
测试类:
public class Test {
public static void main(String[] args){
String s = "test";
ClassUtil.getClassMessage(s);
try {
ClassUtil.printConstructorMessage(s);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
运行结果(部分):
类的名称:java.lang.String
boolean equals(Object,)
String toString()
int hashCode()
int compareTo(String,)
int compareTo(Object,)
int indexOf(String,int,)
int indexOf(String,)
int indexOf(int,int,)
int indexOf(int,)
String valueOf(int,)
String valueOf(long,)
String valueOf(float,)
String valueOf(boolean,)
String valueOf(char[],)
String valueOf(char[],int,int,)
String valueOf(Object,)
String valueOf(char,)
String valueOf(double,)
char charAt(int,)
int codePointAt(int,)
int codePointBefore(int,)
int codePointCount(int,int,)
...
...
##############################
char[] value
int hash
long serialVersionUID
ObjectStreamField[] serialPersistentFields
Comparator CASE_INSENSITIVE_ORDER
##############################
java.lang.String (byte[],int,int,)
java.lang.String (byte[],Charset,)
java.lang.String (byte[],String,)
java.lang.String (byte[],int,int,Charset,)
java.lang.String (byte[],int,int,String,)
java.lang.String (char[],boolean,)
java.lang.String (StringBuilder,)
java.lang.String (StringBuffer,)
java.lang.String (byte[],)
java.lang.String (int[],int,int,)
java.lang.String ()
java.lang.String (char[],)
java.lang.String (String,)
java.lang.String (char[],int,int,)
java.lang.String (byte[],int,)
java.lang.String (byte[],int,int,int,)
7.实战2 ------ 通过反射调用指定类的对象的方法
package fanshe;
import java.lang.reflect.InvocationTargetException;
public class InvokeMethod {
/**
* 通过反射调用类的对象的方法
*/
public static void main(String[] args) {
A a = new A();
Class c = a.getClass();
try {
c.getMethod("print",int.class,int.class).invoke(a,10,20);
c.getMethod("print",String.class,String.class)
.invoke(a,"hello","world");
c.getMethod("print").invoke(a);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
class A {
public void print(int a,int b) {
System.out.println(a+"+"+b+"="+a+b);
}
public void print(String a,String b) {
System.out.println(a+",,"+b);
}
public void print() {
System.out.println("null");
}
}
8.实战3 ------ 通过反射实现同一个集合存放不同类型的元素
首先看这样一个代码:
显然,l1并不能存放10,因为10 不是String类型,那么我们怎么解决呢?
先看这样的一个测试:
运行结果为true!!!
这说明编译之后集合的泛型是去泛型化的,也就是说在编译之前,语法检查的时候,才会对集合将要存放的类型进行审查,而编译之后他们属于同一个类型!
下面看反射实现:
package fanshe;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<String> l1 = new ArrayList<>();
List<Integer> l2 = new ArrayList<>();
l1.add("test");
// l1.add(100);
Class c1 = l1.getClass();
Class c2 = l2.getClass();
System.out.println(c1==c2);//运行结果为true
try {
Method m = c1.getMethod("add",Object.class);
// 现在向l1中添加一个100
m.invoke(l1,100);
System.out.println("l1中的元素:"+l1);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
运行结果:
9.总结
<1>.得到指定类的类类型常用方法(三种)
<2>.类的类类型对象的常用方法(getMethods()、getReturnType()、getParameterTypes()…等)
<3>反射是在运行时加载对象,而不是编译时,所以可以绕过编译实现同一个结合存放不同类型数据