今天小编学习了Java里比较核心的反射原理,明白了反射是Java非常突出的一个动态相关机制。
解释一下,反射机制是Java在运行状态中,对于于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制,很多优秀的开源框架都是通过反射完成的。理解了反射,就是成为大神的第一步!
public class Simple {
public static void main(String[] args) {
Simple s=new Simple();
System.out.println(s.getName());
}
}
以上是一般人常用创建类对象实例化的方法,然后可以随意调用类中的一切方法。
然而在反射机制中,可以实现以下功能:
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;
- 生成动态代理;
获取源头Class(重点)
所有类的对象其实都是Class的实例。这个 Class 实例可以理解为类的模子,就是包含了类的结构信息,类似于图纸。我们日常生活中,需要创造一个产品,如想山寨一个iphone手机,怎么办?
有三种方式可以实现:
⑴买个iphone手机,拆的七零八落的,开始山寨;
⑵到iphone工厂参观,拿到iphone磨具,开始山寨;
⑶跑到美国盗取iphone的图纸,开始山寨,最后一种最暴力,最爽。
同理,获取类的Class对象也有三种方式
⑴Class.forName(”包名.类名”) //一般尽量采用该形式
(2)类.class
(3)对象.getClass()
获取Class对象
Class是一切的源头,所有伟大的事业都有一个不起眼的开头。而反射有三种出场方式:
第一种:对象.class
Source s=new Source();
Class<?>c1=s.getClass();
System.out.println(c1.getName());
第二种:类.class
Class<?>c2=Source.class;
System.out.println(c2.getName());
前两种看看就行,第三种最强最暴力:
Class<?> c3=Class.forName("com.myclass.Source");
System.out.println(c3.getName());
有了class对象,我们就有了一切,这就是反射的源头,接下来就是“庖丁解牛”。
获取修饰符
获取修饰符,使用 getModifiers() 即可,通过此方法可以获得整形数字,与修饰符一一对应, Modifier 类提供了 static 方法和常量来解码类和成员访问修饰符。
Class<?>clz=Class.forName("com.myClass.User");
//获得修饰符
int n=clz.getModifiers();
//使用Modifier转换为相应的字符串
System.out.println(Modifier.toString(n)
创建对象
根据Class对象,我们可以获得构造器,为实例化对象做准备。调用相应方法:
public class GetConstructor {
public static void main(String[] args) {
try {
Class<?>clz=Class.forName("com.myclass.User");
//1、获取所有的public 权限的构造器
Constructor<?>[]con=clz.getConstructors();
//注意查看构造器的顺序
for(Constructor<?> c:con){
System.out.println(c);
}
//2、获取所有的构造器
con=clz.getDeclaredConstructors();
System.out.println("--------------");
for(Constructor<?> c:con){
System.out.println(c);
}
System.out.println("----------------");
//3、获取指定的构造器(放入具体的类型)
Constructor<?> c=clz.getConstructor(String.class);
System.out.println(c);
//非public权限
System.out.println("----------------");
c=clz.getDeclaredConstructor(String.class,String.class);
System.out.println(c);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
实例化对象(重点)
创建对象的方式,有new 、克隆、反序列化,再加一种,根据Class对象,使用 newInstance() 或者构造器实例化对象。调用以下 newInstance() 即可。
Class<?> clz = Class.forName("com.myClass.User");
//第一种:通过newInstance()创建对象
User user=(User)clz.newInstance();
user.setUname("sad");
user.setUpwd("good");
//第二种:通过getDeclaredConstructors()创建对象,取得全部构造函数(注意顺序)
Constructor<?>[] cons=clz.getDeclaredConstructors();
for(Constructor<?>c:cons){
System.out.println(c);
}
//注意观察上面的输出结果,再实例化,否则参数容易出错
User u1=(User)cons[0].newInstance("sad","good");
User u2=(User)cons[1].newInstance("sad");
User u3=(User)cons[2].newInstance();
System.out.println(u1.getUname()+u1.getUpwd());
注意: newInstance() 是调用空构造,如果空构造不存在,会出现异常。由此可知,使用其他构造器创建对象比较麻烦,使用空构造非常简单。确保自定义类的空构造存在。
父类与接口
我们还可以通过方法获取父类或者父类接口
Class<?> clz =Class.forName("com.myClass.User");
//获取所有接口
Class<?>[] inters=clz.getInterfaces();
for(Class<?> in:inters){
System.out.println(in.getName());
}
//获取父类
Class<?> cls=clz.getSuperclass();
System.out.println("继承的父类为:"+cls.getName());
属性和方法
同样的我们可以通过相应的方法来获取类中的属性和方法,包括父类和接口中的。
属性
获取所有属性(包括父类或接口) ,使用 Field 即可操作, Field 作为描述属性的对象。
Class<?> clz = Class.forName("com.myClass.User");
//获取属性
System.out.println("===============本类属性==========");
// 取得本类的全部属性
Field[] field = clz.getDeclaredFields();
for (int i = 0; i < field.length; i++) {
// 1、权限修饰符
int mo = field[i].getModifiers();
String vis = Modifier.toString(mo);
// 2、属性类型
Class<?> type = field[i].getType();
//3、名字
String name = field[i].getName();
System.out.println(vis + " " + type.getName() + " "+ name + ";");
}
System.out.println("=========公开的属性包括接口或者父类属性======");
field = clz.getFields();
for (int i = 0; i < field.length; i++) {
System.out.println(field [i]);
}
数组
反射类不仅能操作类,也能操作数组。
//1、创建数组
Object obj =Array.newInstance(int.class, 5);
//2、获取大小
if(obj.getClass().isArray()){ //3、判断是否为数组
System.out.println(Array.getLength(obj));
//4、设置值
Array.set(obj,0, 100);
//5、获取值
System.out.println(Array.get(obj,0));
}
总结:在我看来,类是对对象的描述,有属性,有方法,而反射让我觉得这是一个对类的类,描述了类的名字,权限,成员属性,成员方法。了解反射可以进一步了解Java的底层!
莫等闲,白了少年头,空悲切。