目录
一、认识反射
1.什么是反射
Java反射就是在运行状态中,对任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为动态语言的一个关键性质。一句话:反射指的是对象的反向处理。根据 对象 倒退 类 的组成。
2.反射的功能 :
a.可以判断运行对象所属的类
b.可以判断运行时对象所具有的成员变量和方法
c.通过反射甚至可以调用private的方法
d.生产动态代理
二、反射的作用
有了反射,我们便可以更灵活的编写代码,代码就可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等。
PS:但是需要注意的是反射使用不当会造成很高的资源消耗
三、反射的具体实现与操作
1.得到Class的三种方式
I. 任何类的对象可以通过调用Object类提供的getClass()取得该类Class对象. 该方法常用于:比如你传过来一个Object类,而我并不在知具体的什么类,用此方法
(对象名.getClass())
Person per = new Person();
Class c1 = per.getClass();
II.“类名称.class”可以直接根据某个具体类来取得其Class对象 . 该方法最安全可靠,程序性更高
(类名称.class)
Class c2 = Person.class;
III.调用Class类的静态方法Class.forName(String className)传入类的全名称来取得其Class对象 ,可能会抛出ClassNotFoundException异常
(Class.forName(类的全名称))
Class c3 = Class.forName("Refalct.Person");
PS: 一个类在JVM中只会有一个Class实例,即上面获取的c1,c2,c3进行equals比较,全部都是true
2.实例化方法
在class类中有如下方法:只能调用类中无参构造,且无参构造必须是public权限
public T newInstance() throws InstantiationException, IllegalAccessException
//正向: Person per = new Person();
//反射:
//1.取得类的Class对象
Class cls = Class.forName("Refalct.Person");
//2.通过反射取得Date类实例化对象
Person p = (Person)cls.newInstance()
3.构造方法
a.取得类中指定参数类型的构造方法
public Constructor<T> getConstructor(Class<?> . . . parameterTypes):获得类的特定构造方法
public Constructor<T> getDeclearConstructor(Class<?> . . . parameterTypes):可以取得类中特定的构造方法,包含私有构造
------------------------------------------------------------------------------------------------------------------------------------------
b.取得类中所有构造方法
public Constructor<T>[] getConstructors throws SecurityException :只能取得类中public权限的构造方法
public Constructor<T>[] getDeclearConstructors throws SecurityException:可以取得类中全部构造方法,包含私有构造
package Reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
class Person{
private Person(){}
protected Person(int age, String name){}
public Person(int age){}
}
public class Text {
public static void main(String[] args){
try {
Class cls = Class.forName("Reflect.Person");
Constructor[] cons1 = cls.getConstructors();
for (Constructor c:cons1) {
System.out.println(c);
}
System.out.println("----------------");
Constructor[] cons2 = cls.getDeclaredConstructors();
for (Constructor c:cons2) {
System.out.println(c);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
result:
public Reflect.Person(int)
----------------
private Reflect.Person()
protected Reflect.Person(int,java.lang.String)
public Reflect.Person(int)
Constructor类提供了实例化对象的方法: public T newInstance(Object . . . initargs):可以调用类中其他有参构造
4.普通方法
a.取得类中指定名称的普通方法 (既要传名称也要传属性,因为可能存在方法重载)
public Method getMethod(String name, Class<?> . . . paramterTypes) 在本类以及父类中找指定名字及参数的public权限方法
public Method getDeclaredMethod(String name, Class<?> . . . paramterTypes) : 在本类中找指定名字及参数的方法,包含私有方法
b.取得类中全部普通方法
public Method[] getMethods() throws SecurityException : 取得本类以及父类中所有public方法
public Method[] getDeclaredMethods() throws SecurityException:取得本类中全部普通方法,包含私有方法
package Reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
class Person{
private void test(){}
protected void fun(){}
public void hh(){}
}
class Student extends Person{
private void test1(){}
protected void fun1(){}
public void hh1(){}
}
public class Text {
public static void main(String[] args){
try {
Class cls = Class.forName("Reflect.Student");
//取得本类
Method[] m1 = cls.getMethods();
for (Method m:m1) {
System.out.println(m);
}
System.out.println("------------------------------------------------");
Method[] m2 = cls.getDeclaredMethods();
for (Method m:m2) {
System.out.println(m);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public void Reflect.Student.hh1()
public void Reflect.Person.hh()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
。。。。。。
------------------------------------------------
private void Reflect.Student.test1()
protected void Reflect.Student.fun1()
public void Reflect.Student.hh1()
PS: Method类中提供调用类中普通方法的API : public Object invoke(Object obj, Object . . . args)
class Person{
private String name;
private int 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;}
@Override
public String toString() {
return "Person{" +"name='" + name + '\'' +", age=" + age + '}';
}
}
public class Text{
public static void main(String[] args) throws Exception{
try {
//1.拿到PersonClass对象
Class cls = Class.forName("Reflect.Person");
//2.创建Person实例化对象
Person per = (Person) cls.newInstance();
//3.拿到setName的Method对象
Method setMethod = cls.getMethod("setName", String.class);
Method setMethod2 = cls.getMethod("setAge", int.class);
//4.通过invoke进行调用
setMethod.invoke(per,"lmd");
setMethod2.invoke(per,18);
System.out.println(per);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
result:Person{name='lmd', age=18}
5.属性
(1)取得类中指定属性
public Field getField(String name) throws NosuchFieldException,SecurityException 取得本类及父类中指定名称的public权限属性
public Field getDeclaredField(String name) throws NosuchFieldException,SecurityException 取得本类中指定名称的普通属性,包含私有属性
(2)取得类中全部属性
public Field[] getFields() throws SecurityException : 取得本类及父类中所有的public属性
public Field[] getDeclaredFields() throws SecurityException : 取得本类中全部的普通属性,包含私有属性
Feild提供设置与取得属性
(3)设置属性
public void set(Object obj, Object value)
(4)取得属性
public Object get(Object obj)
(5)取得属性的类型
public Class<?> getType()
package Reflect;
import java.lang.reflect.*;
class Person{
public String name;
private int age;
}
public class Text {
public static void main(String[] args){
try {
Class cls = Class.forName("Reflect.Person");
//获得类的public类型的属性
Field[] fields = cls.getFields();
for (Field f:fields) {
System.out.println(f.getName());
}
System.out.println("-------");
//获得类的所有属性
Field[] fields2 = cls.getDeclaredFields();
for (Field f:fields2) {
System.out.println(f.getName());
}
System.out.println("**********************");
//获得指定的属性
Field f = cls.getField("name");
System.out.println(f);
//获得指定的私有属性
Field f2 = cls.getDeclaredField("age");
System.out.println(f2);
System.out.println("**********************");
Person per = new Person();
//动态设置封装方法,
f2.setAccessible(true);
f2.set(per,20);
System.out.println(f2.get(per));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
result:
name
-------
name
age
**********************
public java.lang.String Reflect.Person.name
private int Reflect.Person.age
**********************
20
6. 反射取得父类、父接口信息
a.取得类的包名称
public Package getPackage( )
b.取得父类的Class对象
public native Class<? super T> getSuperClass( ) //父类只可能有一个
c.取得实现的父接口
public Class<?>[] getInterfaces( ) //因为父接口可能有多个,所有使用数组来实现返回值的获取
package Reflect;
import java.lang.reflect.*;
class Person{}
interface Inews{}
interface Imessage{}
class Student extends Person implements Inews,Imessage{}
public class Text {
public static void main(String[] args){
//取得类的Class对象
Class cls = Person.class;
//1.取得父类的class对象
System.out.println(cls.getPackage().getName());
Class cls2 = Student.class;
//2.取得父类信息
System.out.println(cls2.getSuperclass().getName());
//3.取得父接口
Class[] cls3 = cls2.getInterfaces();
for(Class ll: cls3){
System.out.println(ll.getName());
}
}
}
result:
Reflect
Reflect.Person
Reflect.Inews
Reflect.Imessage
四、ClassLoader类加载器
1. 认识classLoader
类加载器:通过一个类的全名称,来获取此类的二进制字节流。实现这个操作的代码模块称为类加载器。
JDK中内置的三大类加载器
(1) Bootstarp(启动类加载器):
I. 使用C++实现,是JVM的一部分。其他所有的类加载器均使用java实现
II. 负责将存放于 JAVA_HOME\lib 目录下的能被JVM识别的类库(eg: rt.jar)加载到JVM中。
III.启动类加载器,无法被 java 程序直接引用。
(2) ExtClassLoader(扩展类加载器):
I. 使用Java实现,并且可以被Java程序直接引用
II. 加载 JAVA_HOME\lib\ext 目录下能被识别的类库
(3) AppClassLoader(应用程序类加载器):
I. 负责加载用户路径(classpath)上指定的类库
II.如果应用程序中没有自定义类加载器,则此加载器就是java程序中默认的类加载器
2. 类加载器双亲委派模型 ---- JDK1.2引入
2.1 定义:
JDK内置的三种类加载器与用户自定义的类加载器之间的层次关系称为类加载器的双亲委派模型。
要求除了顶层的父类加载器外,其余的类加载其都应有自己的父类加载器。
2.2 执行流程:
如果一个类加载器收到了类加载请求,它首先不会自己去尝试加载此类,而是把类加载器请求委托给父类加载器完成,每一个层次类加载器均是如此。只有当父类加载器无法完成加载请求时(在自己搜索范围内没有找到此类),子加载器才会尝试自己去加载。
2.3 意义:
双亲委派模型保证了java程序稳定运行,java中基础类库一定由顶层Bootstrap类加载器加载,因此,诸如Object等核心类在各种类加载器环境下都是同一个类。
五、总结
灵活使用反射能让我们代码更加灵活,eg:JDBC原生代码注册驱动有反射的实现。
但是事务都有两面性,反射也会消耗系统的性能,增加复杂性等,要注意合理使用!