这篇文章就是简简单单的介绍反射是什么、怎么用,面向初学者,老鸟勿喷。不涉及深层的原理。因为我不懂。
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))
有了以上的知识,你就已经了解了最基本的反射知识并且能灵活使用反射了。其他的我以后补充。希望能帮助到初学者理解。