反射
反射是Java被称作"准动态语言的关键",反射机制允许程序在执行期取得任何类的内部信息,并且可以直接操作任意对象的内部属性和方法。
在类加载完毕后,方法区中就产生了一个Class类型的队形(一个类只有一个Class对象),这个对象包含了该类的完整的结构信息。我们可以通过这个Class对象看到这个类的结构。
这个对象就像一面镜子,透过这个镜子看到类的结构,所以, 我们形象的称之为:反射
反射主要也就是在学习Class对象
反射的优缺点
优点:可以动态编译,很灵活
缺点:对性能有影响,使用反射是一种解释操作。我肯可以高速jvm,我们希望做什么并且它满足我们的要求。这类操作总是慢于执行相同的操作
Class类
在Object类中定义了以下的方法
public final Class getClass()
该方法可以返回调用对象的Class类。
我们得到Class对象后可以得到某个类完整的结构,包括属性、方法、构造器等。
获取Class类的实例的方法
1.若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高。
2.已知某个类的实例,调用该实例的getClass()方法获取Class对象
-
已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取, 可能抛出ClassNotFoundException
public class MyTest { public static void main(String[] args) throws ClassNotFoundException { MyClassTest myClassTest = new MyClassTest(); System.out.println("正常方法创建对象---------"); //获取Class对象的方法 Class class1 = MyClassTest.class;//已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高。 Class class2 = myClassTest.getClass();// 已知某个类的实例,调用该实例的getClass()方法获取Class对象 Class class3 = Class.forName("F:\\java\\demo\\反射\\src\\org\\westos\\demo\\MyTest.java");// 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取, } } class MyClassTest{ }
获取运行时类的完整结构
public class MyTest2 {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
//正常创建两个MyClassTest2对象
MyClassTest2 big = new MyClassTest2("大张", 15);
MyClassTest2 small = new MyClassTest2("小张", 5);
//获得Class对象
Class class1 = MyClassTest2.class;
//利用Class对象获得MyClassTest2类的所有信息
System.out.println("============================");
Field[] fields = class1.getFields();//获得所有public属性
Field name = class1.getDeclaredField("name");//获得指定属性
Field[] fields2 =class1.getDeclaredFields();//获得所有的属性
System.out.println("============================");
Constructor[] constructors = class1.getConstructors();//获得所有public构造器
Constructor[] constructors2 = class1.getDeclaredConstructors();//获得所有构造器
class1.getDeclaredConstructor(String.class,int.class);//获得指定构造器.因为构造器存在重载,获得指定构造器需要添加参数.参数为构造器的参数类型的class类型
System.out.println("============================");
Method[] methods = class1.getMethods();//返回当前类和被继承的类的public方法
Method[] declaredMethods = class1.getDeclaredMethods(); //获得当前类的所有方法
Method setName = class1.getDeclaredMethod("setName", String.class);//获得指定的方法.同上述构造方法一样.因为存在函数重载.所以需要添加方法名和方法的参数类型的class类型
}
}
class MyClassTest2 {
String name;
int age;
public MyClassTest2() {
}
MyClassTest2(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
利用Class对象操纵该类
public class MyTest3 {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//正常创建两个MyClassTest3对象
MyClassTest3 big = new MyClassTest3("大张", 15);
MyClassTest3 small = new MyClassTest3("小张", 5);
Class class1 = MyClassTest3.class;
Constructor constructor = class1.getDeclaredConstructor(String.class,int.class);
Field name = class1.getDeclaredField("name");
Method setName = class1.getMethod("setName", String.class);
//演示通过Class对象来对类进行操作
//1.演示创建对象
//1.1通过类的newInstance()方法创建对象
MyClassTest3 myClassTest3 = (MyClassTest3) class1.newInstance();
myClassTest3.setAge(15);
System.out.println(myClassTest3.getAge());
//1.2通过类的构造器创建对象
MyClassTest3 myClassTest31 = (MyClassTest3)constructor.newInstance("张晓", 38);
System.out.println(myClassTest31.getName());
//2.通过Class类来修改属性
System.out.println(big.getName());
name.set(big,"张三");
System.out.println(big.getName());//此处通过类成功的修改了对象big的属性.注意.因为一个类可以创建多个对象.所以在修改属性时需要添加参数.明确你想要修改的是哪一个对象的属性
//3.通过Class类来调用方法
setName.invoke(big,"张四");
System.out.println(big.getName());//此处通过invoke再次绕过了对象调用了该类的方法.修改了big的name属性.
}
}
class MyClassTest3 {
String name="LALAL";
int age=0;
public MyClassTest3() {
}
MyClassTest3(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
注意:在使用反射操作时。显示调用setAccessible为true,则可以访问private方法!所以会对程序的安全性造成极大的破坏。