主要内容:
Reflection(反射)被视为动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
反射相关的API:
(1)在Object类中定义了:public final Class getClass()
此方法被所有子类继承。
该方法返回一个Class类,此类是Java反射的源头。可以通过对象反射求出类的名称。
(2)Class 类可以描述所有的类。
(3)对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个类的有关信息。
(4)Class本身也是一个类。
(5)Class对象只能由系统建立。
(6)一个类在JVM中只会有一个Class实例。
(7)一个Class对象对应的是一个加载到JVM中的一个.class文件。
(8)每个类的实例都会记得自己是由哪个Class实例所生成。
(9)通过Class可以完整地得到一个类中的完整结构。
public class Test {
public static void main(String[] args) {
//实例化Class类对象的常用方法
Class c0 = Person.class; //通过类名.class创建指定类的Class实例
Class c1 = new Person().getClass(); //通过一个类的实例对象的.getClass()
try {
Class c2 = Class.forName("Person"); //通过Class的静态方法forName()
//使用全路径:包名.类名
//此方式为常用方式
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Person {
String name;
int age;
}
获取接口和父类:
public class Test {
public static void main(String[] args) {
try {
Class c = Class.forName("Student");
Class su = c.getSuperclass(); //获取父类
System.out.println(su.getName());
Class[] interfaces = c.getInterfaces(); //获取接口
for (Class f : interfaces) {
System.out.println(f.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Person {
String name;
int age;
}
class Student extends Person implements Move,Study {
String school;
public void showInfo() {
System.out.println("学校是:" + this.school);
}
@Override
public void moveType() {
System.out.println("骑自行车");
}
@Override
public void studyInfo() {
System.out.println("学英语");
}
}
//接口
interface Move {
void moveType();
}
interface Study {
void studyInfo();
}
获取全部构造器:
import java.lang.reflect.Constructor;
import java.lang.reflect.TypeVariable;
public class Test {
public static void main(String[] args) {
try {
Class c = Class.forName("Student");
Constructor[] cons = c.getConstructors(); //获取类的公有构造方法
for (Constructor cs : cons) {
System.out.println(cs.getName() + cs.getModifiers());
//getModifiers()取得返回方法的修饰符,返回1代表public,返回2代表private
}
c.getDeclaredConstructors(); //获取类的所有构造方法,包含公有和私有
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Student {
int age;
String name;
String school;
public Student() {
//
}
public Student(String school) {
this.school = school;
}
private Student(String name, int age) {
this.name = name;
this.age = age;
}
}
可以获取构造器、构造器的修饰符(1public还是2private)、构造器的参数类型。
那么,如何用反射的构造方法来创建对象?
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
try {
Class c = Class.forName("Student");
try {
Object obj = c.newInstance(); //相当于调用Student类的一个公有无参构造方法
Student stu = (Student)obj;
Constructor cons = c.getConstructor(String.class); //指定获取有一个String参数的公有构造方法
Object obj1 = cons.newInstance("清华大学");
Student stu1 = (Student) obj1;
//另外,用过反射机制可以强制调用私有构造方法
Constructor conss = c.getDeclaredConstructor(String.class,int.class);
conss.setAccessible(true); //解除封装
Student stu2 = (Student)conss.newInstance("清华大学",18);
}
catch (Exception e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Student {
int age;
String name;
String school;
public Student() {
System.out.println("调用的是public Student()");
}
public Student(String school) {
this.school = school;
System.out.println("调用的是public Student(String school)");
}
private Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("调用的是private Student(String name, int age)");
}
}
通过反射获取类的全部方法:
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
try {
Class student = Class.forName("Student");
// Method[] ms = student.getMethods(); //获取公有方法
Method[] ms = student.getDeclaredMethods(); //获取全部方法
for (Method m : ms) {
System.out.println("方法名:" + m.getName());
System.out.println("返回值类型:" + m.getReturnType());
System.out.println("修饰符:" + m.getModifiers());
Class[] pcs = m.getParameterTypes(); //获取方法的参数类型
if (pcs != null && pcs.length > 0) {
for (Class pc : pcs) {
System.out.println("参数类型:" + pc.getName());
}
}
System.out.println("========================");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Student {
String name;
private void test() {
System.out.println("test()方法");
}
public String getName() {
return this.name;
}
}
通过反射获取全部Field(属性)
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) {
try {
Class c = Class.forName("Student");
Field[] fields = c.getFields(); //获取公有属性,包含父类的公有属性
Field[] fields1 = c.getDeclaredFields(); //获取本类的所有属性 不包括父类的属性(公有也不包括)
for (Field f : fields1) {
System.out.println("修饰符:" + f.getModifiers());
System.out.println("属性的类型:" + f.getType());
System.out.println("属性的名称:" + f.getName());
System.out.println("=======================");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Person {
public int a;
}
class Student extends Person{
public String name;
public int age;
private int grades;
}
获取类所在的包
Package p = c.getPackage(); //c是某一个类的Class实例
package day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
try {
Class c = Class.forName("day14.Student");
//getMethod()和getMethods():加s的是返回很多方法的数组,不加是调用某一个指定的方法
Method m = c.getMethod("setInfo",String.class,String.class);
Constructor con = c.getConstructor();
Object obj = con.newInstance();
m.invoke(obj,"胡杨","清华大学");
//如果想要调用一个私有方法
Method m1 = c.getDeclaredMethod("test");
m1.setAccessible(true); //接触私有封装,下面可以强制调用私有的方法
m1.invoke(obj);
//调用一个重载方法
Method m2 = c.getMethod("setInfo", String.class);
m2.invoke(obj,"胡杨林");
//有返回值的方法
Method m3 = c.getMethod("getSchool");
String school = (String) m3.invoke(obj);
System.out.println(school);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Student {
String name;
String school;
public Student() {
//
}
public void setInfo(String name, String school) {
this.name = name;
this.school = school;
System.out.println("setInfo(String name, String school)方法");
}
private void test() {
System.out.println("私有方法");
}
public void setInfo(String name) {
this.name = name;
System.out.println("重载setInfo(String name, String school)方法");
}
public String getSchool() {
return this.school;
}
}
注意:不论调用哪个方法,都是调用的obj对象的方法。obj对象实际上就是Student对象。
package day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) {
try {
Class c = Class.forName("day14.Student");
Constructor cons = c.getConstructor();
Student stu = (Student) cons.newInstance();
Field f1 = c.getField("name");
f1.set(stu,"胡杨");
String name = (String) f1.get(stu);
System.out.println(name);
//私有属性
//注意是加Declared
Field f2 = c.getDeclaredField("grades");
f2.setAccessible(true);
f2.set(stu,80);
int scores = (int) f2.get(stu);
System.out.println(scores + "分");
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Student {
public Student() {
//
}
public String name;
public int age;
private int grades;
}
package day14;
public interface ITestDemo {
void test1();
void test2();
}
package day14;
public class TestDemoImpl implements ITestDemo {
@Override
public void test1() {
System.out.println("执行test1()方法");
}
@Override
public void test2() {
System.out.println("执行test2()方法");
}
}
package day14;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 动态代理类
*/
public class ProxyDemo implements InvocationHandler {
Object obj; //被代理的对象
public ProxyDemo(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println(method.getName() + "开始执行");
Object result = method.invoke(this.obj,objects);
System.out.println(method.getName() + "执行结束");
return result;
}
}
package day14;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
ITestDemo test = new TestDemoImpl();
test.test1();
test.test2();
System.out.println("===============================");
//若需要在执行test1()和test2()方法时需要加入一些东西
//要求在执行方法前打印test1或test2开始执行
//在执行方法后打印test1或test2执行完毕
//且打印的方法名要和当时调用的方法保一致
InvocationHandler handle = new ProxyDemo(test);
/**
* 第一个参数是代理对象的类加载器
* 第二个参数是被代理的对象的接口
* 第三个参数是代理对象
* 返回的值就是成功被代理后的对象,返回的是Object类型,需要根据情况转换类型
*/
ITestDemo t = (ITestDemo) Proxy.newProxyInstance(handle.getClass().getClassLoader(),test.getClass().getInterfaces(),handle);
t.test1();
t.test2();
/**
* 注意:如果一个对象想要通过Proxy.newProxyInstance()方法被代理,
* 那么这个对象的类一定要有相应的接口
* 就像本例中的ITestDemo接口和实现类TestDemoImpl
*/
}
}
动态代理的步骤:
newProxyInstance(ClassLoader loader,Class[] interfaces, InvocationHander h)
创建一个Subject接口代理。