反射
反射的操作是编译之后的操作---运行时刻的操作,所有下边方法的反射,变量的反射都是绕过编译,在运行时刻来执行的。
Class类的使用
- 一个类也属于对象,它是java.lang.Class类的对象
public class Foo {
public void print(int a,String b){
System.out.println("....");
}
public static void main(String []args){
Foo foo1=new Foo();
}
}
Class类的实例变量的表示<以上面的代码为例>
* Class c1=Foo.class;//这个代码也告诉我们,任何一个类都有一个隐含的静态成员变量class。
* Class c2=foo1.getClass();//已知该类的对象,通过getClass()方法来获取
* Class c3=null;
c3=Class.forName(“包名+类名”);
c1、c2、c3是Foo类的类类型,且c1=c2,c2=c3因为一个类只可能是Class类的一个实例变量。
我们可以通过(类类型)c1、c2、c3来创建Foo类的实例
Foo foo2=c1.newInstance();//前提是要有无参数的构造方法,因为通过这种方式创建类的对象时,它会默认去调用无参数的构造方法。
方法的反射
Method类,方法对象,一个方法就是一个Method对象。
方法的反射使用
* 获取方法:
Class c1=foo1.getClass();
Method[] ms=c1.getMethods();
getMethods()方法可以获取到所有的public方法,包括由父类继承而来的方法。
getDeclaredMethods()方法可以获取到该类自己声明的所有方法,不包含由父类继承而来的方法,不问访问权限。
getMethod()方法可以获取到public方法,包括由父类继承而来的方法。里边有两个参数(方法名,参数列表)
Method m=c1.getMethod("print",Class[]{int.class,String.class});
getDeclaredMethod()方法可以获取到该类自己声明的方法,不包含由父类继承而来的方法,不问访问权限。里边有两个参数(方法名,参数列表)
* 方法的反射操作
在使用反射之前,我们调用一个方法,通常都是这样来实现的:
foo1.print(6,"a");
在反射中,我们应该这么来做:
Method m=c1.getMethod("print",new Class[]{int.class,String.class});
Object o=m.invoke(foo1,new Object[]{6,"a"});//方法如果没有返回值,则返回空,如果有返回值,则返回具体的返回值。
成员变量的反射
成员变量的反射使用
Class c1=foo1.getClass();
Field[] fd=c1.getFields();
getFields()方法可以获取到所有的public变量
getDeclaredConstructors()方法可以获取到该类自己声明的所有构造方法
构造函数的反射
构造函数的反射使用
Class c1=foo1.getClass();
Constructor[] cs=c1.getConstructors();
getConstructors()方法可以获取到所有的public构造方法
getDeclaredFields()方法可以获取到该类声明的所有变量
通过Class,Method了解泛型的本质
一般情况下,我们进行集合的元素添加时都会经历编译时期。而编译之后,集合的泛型是去泛型化的。
去泛型化:
ArrayList list=new ArrayList();
ArrayList<String> list1 = new ArrayList<>();
Class c1=list.getClass();
Class c2=list1.getClass();
System.out.println(c1=c2);//结果为true
ArrayList list=new ArrayList();
ArrayList<String> list1 = new ArrayList<>();
list1.add(20);//这里会有错误,类型错误
而如果我们通过方法的反射来绕过编译时期:
ArrayList list=new ArrayList();
ArrayList<String> list1 = new ArrayList<>();
Class c1=list1.getClass()
Method m=null;
try {
m = c1.getMethod("add", Object.class);
m.invoke("add",20);//这样就绕过了编译
}catch (Exception e){
e.printStackTrace();
}
就可以将”20”添加到list1中了。
动态加载类
- 静态加载:编译时刻加载类
- 动态加载:运行时刻加载类–Class.forName()方法就包含了动态加载类
静态加载
通过new 来创建对象,是静态加载类,在编译时刻就需要加载所有可能用到的类。
动态加载
Class c4=double.class;//double数据类型的类类型
Class c5=Double.class;//Double类的类类型
类类型
基本数据类型都包含类类型
Void关键字同样具有类类型