Java-反射浅谈
这篇文章就是简简单单的介绍反射是什么、怎么用,面向初学者,老鸟勿喷。不涉及深层的原理。因为我不懂。
1.嘛是反射?
我在自己学习反射的时候,看到了一个说法很有意思——
有反就有正。我们先来看看“正射”是什么:
我们先定义一个Apple类,定义构造函数和属性:
class Apple { private int age; public String name; public void setName(String name) { this.name = name; } private Apple() { } public Apple(int age, String name) { this.name = name; this.age = age; } public int getAge() { return age; } private void setAge(int age) { this.age = age; } }
然后在main函数中:
public static void main(String[] args) { Apple apple = new Apple(12, "青苹果"); }
这种我们最常用的建立对象的方式就是“正射”。来看看我们是怎么定义了这个对象的:
1.我们知道有一个类叫做Apple。
2.我们至少知道这个类的一个构造函数——至少要传入一个int一个String。
我们事先知道了这个类和这个类的信息来创建对象,就是“正”。反射,就是在不知道这个类的具体信息的前提下,来创建对象、获取类的方法属性等等。一个是睁着眼一个是闭着眼,这么说你总能听明白了吧。
2.怎么使用反射?
我们既然想操作一个类,就至少得知道他是谁吧,也就是说我们得获取一个“类对象”。
类对象,用来创建其他对象的对象。
这里我们有三种方式来创建类对象:
1.Class cls=Class.forName(String string):其中参数是类的全路径名。我们知道一个类的全路径名时可以用这种方式。
class ReflectDemo { public static void main(String[] args) { try { Class cls = Class.forName("Practice.Apple"); } catch (ClassNotFoundException e)//这个方法会抛出ClassNotFoundException,找不到你指定的类就会异常。 { e.printStackTrace(); } } }
2.xxx.class 适合编译之前就知道class的情况。
class ReflectDemo { public static void main(String[] args) { Class cls = Apple.class; } }
3.使用对象的getClass()方法。
class ReflectDemo { Apple apple = new Apple(); Class cls = apple.getClass(); }
三种方式各有各的使用场景。
好了,我们现在已经拿到了这个类的类对象,下一步我们就可以用反射建立这个类的对象了。
建立类对象有两种方式:
1.使用类对象的.newInstance()方法来获取一个使用无参的构造函数初始化的对象。
try { Class cls = Class.forName("Practice.Apple"); Apple apple = (Apple) cls.newInstance(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) //newInstance()抛出InstantiationException(如果此 Class 表示一个抽象类、接口、数组 // 类、基本类型或 void; 或者该类没有 null 构造方法) //与IllegalAccessException(如果该类或其 null 构造方法是不可访问的) { e.printStackTrace(); }
我装的是java11,newInstance()似乎是被要废弃了?
2.通过Constructor对象的newInstance()方法。这个方式我们可以指定构造方法。
public static void main(String[] args) { try { Class cls = Class.forName("Practice.Apple"); Constructor constructor = cls.getConstructor(int.class,String.class); Apple apple = (Apple) constructor.newInstance(13, "毒苹果"); } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) //getConstructor()会抛出NoSuchMethodException。 //newInstance()抛出InstantiationException,IllegalAccessException, //InvocationTargetException(当被调用的方法的内部抛出了异常而没有被捕获时,将由此异常接收) { e.printStackTrace(); } }
在getConstructor时我们要指定参数类型。注意是class类型。
对象有了,我们现在需要调用对象的属性or方法时怎么调用呢?
1.获取对象的属性
Field[] fields = cls.getFields();//cls是我们的类对象 for (Field field : fields) { System.out.println(field); }
getFields可以获取到所有除private的属性。若获取指定属性可以使用getField(String name)。
获取所有包括private的属性我们可以使用getDeclaredFields()。
2.获取对象的方法
Method[] methods = cls.getMethods(); for (Method method : methods) { System.out.println(method); }
道理同上,getDeclaredMethods()可以获取所有方法。
有了这些,我们就可以对对象进行操作了。
3.执行对象的方法
Method method = cls.getMethod("setAge", int.class); method.invoke(apple,10); System.out.println(apple.getAge());
分析代码:
首先我们指定了方法名来获取指定的方法(第一个参数是方法名,第二个是方法的参数的所属类。这里注意,若参数为int型的,要么写int.class,要么写Integer。Integer.class是不行的。)
接着我们调用方法的invoke(invoke,执行之意)。第一个参数是我们想在哪个对象上调用方法,第二个是参数值。(若方法为私有方法,我们虽然可以获取到但是不能执行。若想执行,则需要在执行前调用method.setAccessible(true))
有了以上的知识,你就已经了解了最基本的反射知识并且能灵活使用反射了。其他的我以后补充。希望能帮助到初学者理解。