java反射机制
java中较为重要的就是反射机制,那么什么是反射机制呢?举个简单的例子来说,正常情况下,如果已经有一个类,则肯定可以通过类创建对象;那么如果现在要求通过一个对象找到一个类的名称,此时就需要用到反射机制,如果要完成反射操作,则首先应该认识的就是Class类。
在反射的学习中一定要把握一个概念,一切操作都将使用Object完成,类、数组的引用都可以使用Object接收。只有把握了这个概念,才能更清楚的掌握反射机制的作用。
认识Class类
在正常情况下,需要先有一个类的完整路径引用之后才可以按照固定的格式产生实例对象,但是在java中也允许通过一个实例化对象找到一个类的完整信息,那么这就是Class类的功能。
public class Demo{
public static void main(String[] args){
Demo demo=new Demo();
System.out.print(demo.getClass().getName());
}
}
结果:
myTest.Demo
从结果可以发现,通过一个对象得到了对象所在的完整的“包.类”名称,那么getClass类是从哪里定义的呢,
任何一个类如果没有明确的声明继承自哪个父类时,则默认继承Object类,所以getClass()方法是Object类
中的:
public final native Class<?> getClass();
以上方法返回值的类型是一个Class类,实际上此类是java反射的源头。所谓的反射从程序的运行结果来看也
很好理解,即可以通过对象反射求出类的名称。
所有类的对象实际上都是Class类的实例
在java中Object类是一切类的父类那么所有类的对象实际上也就是java.lang.Class类的实例,所以所有对象都可以转变为java.lang.Class类型表示。
Class本身表示一个类的本身,通过Class可以完整的得到一个类中的完整结构,包括此类中方法定义、属性定义等
在Class类中本身没有定义任何的构造方法,所以如果要使用则首先必须通过forName()方法实例化对象,除此之外,也可以使用“类.Class”或“对象.getClass()”方法实例化。
public class Demo{
public static void main(String[] args){
Class<?> c1=null;
Class<?> c2=null;
Class<?> c3=null;
try {
//最常用形式
c1=Class.forName("myTest.Demo");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
c2=new Demo().getClass();
c3=Demo.class;
System.out.println("类的名称为:"+c1.getName());
System.out.println("类的名称为:"+c2.getName());
System.out.println("类的名称为:"+c3.getName());
}
}
结果:
类的名称为:myTest.Demo
类的名称为:myTest.Demo
类的名称为:myTest.Demo
从结果看,三种实例化Class对象的方式是一样的,但是使用forName()静态方法实例化Class对象是比较
常用的,应该重点掌握。
除了forName()方式外,另外两种“对象.getClass()”和“类.class”都需要导入一个明确的类,如果一个类
操作不明确时,使用起来可能会受到一些限制,但是forName传入时,只需要以字符串的方式传入即可,这样
就让程序具备了更大的灵活性,所以此方法是最常见的方法。
Class类的使用
实际上Class类在开发中最常用的用法就是实例化对象的操作,即可以根据一个给定的字符串(此字符串包含了完整的“包.类”的路径)来实例化一个类的对象。
1.通过无参构造实例化对象
public class Person{
private String name;
private int age;
public Person() {
System.out.println("我是构造方法...");
}
public Person(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;
}
@Override
public boolean equals(Object obj) {
if(this==obj) {
return true;
}
if(!(obj instanceof Person)) {
return false;
}
Person p=(Person) obj;
if(this.name.equals(p.name)&&this.age==p.age) {
return true;
}else {
return false;
}
}
@Override
public int hashCode() {
return this.name.hashCode()*this.age;
}
@Override
public String toString() {
return "姓名:"+this.name+";"+"年龄:"+this.age;
}
}
public class Demo{
public static void main(String[] args){
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Person p=null;
try {
p=(Person) c.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
p.setName("zhangsan");
p.setAge(15);
System.out.println(p);
}
}
结果:
我是构造方法...
姓名:zhangsan;年龄:15
从成宿的运行结果来看,通过Class/forName()方法实例化Class对象之后,直接调用newInstance()方法
就可以根据传入的完整“包.类”名称的方式进行对象的实例化操作,完全取代了之前使用new的操作方式。
但在使用上注意一点,被实例对象的类中必须存在无参构造方法,如果不存在,则肯定无法实例化。
各种高级应用中都提倡类中存在无参的构造方法
在实际的java开发中,反射是最为重要的操作原理,在现在的开发设计中大量的应用了反射处理机制,如
Struts,Spring框架等,在大部分的操作中基本上都是操作无参的构造方法,所以在开发中一定要保留无参
构造方法。
2.调用有参构造方法实例化
如果没有无参构造方法,可以通过其他方式进行实例化操作,只是在操作时需要明确的调用类中的构造方法,
并将参数传递进去之后,才可以进行实例化操作。步骤如下:
(1):通过Class类中的getConstructors()方法,取得本类中全部的构造方法。
(2):向构造方法中传递一个对象数组进去,里面包含了构造方法所需要的各个参数。
(3):之后通过Constructor实例化对象
public class Person{
private String name;
private int age;
/*public Person() {
System.out.println("我是构造方法...");
}*/
public Person(String name,int age) {
this.name=name;
this.age=age;
System.out.println("我是有参构造方法...");
}
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 boolean equals(Object obj) {
if(this==obj) {
return true;
}
if(!(obj instanceof Person)) {
return false;
}
Person p=(Person) obj;
if(this.name.equals(p.name)&&this.age==p.age) {
return true;
}else {
return false;
}
}
@Override
public int hashCode() {
return this.name.hashCode()*this.age;
}
@Override
public String toString() {
return "姓名:"+this.name+";"+"年龄:"+this.age;
}
}
public class Demo{
public static void main(String[] args){
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Person p=null;
Constructor<?> cons[]=null;//声明一个构造方法数组
cons=c.getConstructors();//通过反射取得全部构造方法
try {
//因为只有一个构造方法所以数组下标为0
p=(Person) cons[0].newInstance("lisi",40);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException
| InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(p);
}
}
结果:
我是有参构造方法...
姓名:lisi;年龄:40
反射的应用-取得类的结构
反射的应用不仅可以实例化,还可以通过反射得到一个类的完整结构,那么这就要使用到java.lang.reflect包一下的几个类
Constructor:表示类中的构造方法
Field:表示类中的属性
Method:表示类中的方法
这三个类都是AccessibleObject类的子类
准备操作:
一个接口类China:
public interface China{
public static final String NATIONAL="China";
public static final String ANTHOR="张三";
public void sayChina();
public String sayHello(String name,int age);
}
一个实现类Person:
public class Person implements China{
private String name;
private int age;
public Person() {
System.out.println("我是构造方法...");
}
public Person(String name,int age) {
this.name=name;
this.age=age;
System.out.println("我是有参构造方法...");
}
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 "姓名:"+this.name+";"+"年龄:"+this.age;
}
@Override
public void sayChina() {
System.out.println("作者:"+ANTHOR+"--"+"国籍:"+NATIONAL);
}
@Override
public String sayHello(String name, int age) {
// TODO Auto-generated method stub
return name+",您好,我今年"+age+"岁了。";
}
}
1.取得所实现的全部接口:
要取得一个类所实现的全部接口,则必须使用Class类中的getInterfaces()方法。
public Class<?>[] getInterfaces()
getInterfaces()方法返回一个Class类的对象数组,之后直接利用Class类中的getName()方法输出即可。
public class Demo{
public static void main(String[] args){
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Class<?> cla[]=c.getInterfaces();
for(int i=0;i<cla.length;i++) {
System.out.println("实现的接口有--"+cla[i].getName());
}
}
}
结果:
实现的接口有--myTest.China
因为接口是类的特殊形式,而且一个类可以实现多个接口,所以此时以Class数组的形式将全部的接口对象返回
并利用循环的方式将内容依次输出。
3.取得父类
一个类可以实现多个接口,但只能继承一个父类,所以如果要取得一个类的父类,可以直接使用Class类中
的getSuperClass()方法
public native Class<? super T> getSuperclass()
getSuperClass()方法返回的是Class实例,和之前得到接口一样,可以通过getName()方法取得名称。
public class Demo{
public static void main(String[] args){
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Class<?> cla=c.getSuperclass();
System.out.println("父类是--"+cla.getName());
}
}结果:
父类是--java.lang.Object
因为没有直接继承父类,所以父类是Object
4.取得全部构造方法
public class Demo{
public static void main(String[] args){
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Constructor<?> cla[]=c.getConstructors();
for(int i=0;i<cla.length;i++) {
System.out.println("构造方法是--"+cla[i]);
}
}
}
结果:
构造方法是--public myTest.Person()
构造方法是--public myTest.Person(java.lang.String,int)
实例:取得全部构造方法、类型、权限
public class Demo{
public static void main(String[] args){
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Constructor<?> cla[]=c.getConstructors();
for(int i=0;i<cla.length;i++) {
Class<?>[] type=cla[i].getParameterTypes();
System.out.print("构造方法");
int mo=cla[i].getModifiers();//取出权限
System.out.print(Modifier.toString(mo)+" ");
String conStr=cla[i].getName();
System.out.print(conStr);
System.out.print("(");
for(int j=0;j<type.length;j++) {
System.out.print(type[j].getName()+" arg"+i);
if(j<type.length-1) {
System.out.print(",");
}
}
System.out.println("){}");
}
}
}
结果:
构造方法public myTest.Person(){}
构造方法public myTest.Person(java.lang.String arg1,int arg1){}
5.取得全部方法
要取得一个类中的全部方法,可以使用Class类中的getMethods()方法,此方法返回一个Method类的对象
数组。如果想进一步取得方法的信息,如方法的参数、异常等,则就必须依靠Method类
public class Demo{
public static void main(String[] args){
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Method m[]=c.getMethods();
for(int i=0;i<m.length;i++) {
//得到方法的返回值类型
m[i].getReturnType();
//得到全部参数类型
m[i].getParameterTypes();
//得到方法的修饰符
m[i].getModifiers();
//得到方法的名称
m[i].getName();
//得到全部的异常
m[i].getExceptionTypes();
}
}
}
在IDE中输入一个“.”就可以联想到相关的方法。这就是利用反射机制实现的。
6.得到类的全部属性
public Field[] getDeclaredFields() throws SecurityException
以上方法返回的都是Field数组,每一个Field对象表示类中的一个属性,要取得进一步属性的信息就要看
Field的方法。
public class Demo{
public static void main(String[] args){
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//或得类中的属性
Field f[]=c.getDeclaredFields();
for(int i=0;i<f.length;i++) {
//获得属性的类型
f[i].getType();
//或得属性的修饰字符
f[i].getModifiers();
}
//获得普通代码块的属性
c.getFields();
}
}
java反射机制的深入应用
反射除了可以取得一个类的完整结构外,还可以调用类中的指定方法或指定属性,并且可以通过反射完成对数组的操作。
1.通过Class类的getMethod(String name,Class...parameterTypes)方法取得一个Method的对象,
并设置此方法操作时所需要的参数类型。
2.之后才可以使用invoke进行调用,并向方法中传入要设置的参数。
public class Demo{
public static void main(String[] args) throws Exception{
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Method mc=c.getMethod("sayChina");
mc.invoke(c.newInstance());
}
}
结果:
我是构造方法...
作者:张三--国籍:China
通过Class类中的getMethod()方法,根据一个类中的方法名称取得Method对象,并通过invoke调用指定的
方法,但是在使用invoke方法时,必须传入一个类的实例化对象,因为在sayChina()方法上没有任何的参
数,所以此处没有设置参数类型和参数内容
调用有参方法
public class Demo{
public static void main(String[] args) throws Exception{
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Method mc=c.getMethod("sayHello",String.class,int.class);
String rv=null;
rv=(String) mc.invoke(c.newInstance(),"wangwu",60);
System.out.print(rv);
}
}
结果:
我是构造方法...
wangwu,您好,我今年60岁了。
因为sayHello()方法本身要接收两个参数,所以在使用getMethod()方法调用时,除了要指定方法的调用
名称,也同样指定了参数类型,因为sayHello()方法调用之后存在返回值,而且返回值类型是String,所以
使用了一个字符串接收返回值内容。
实例:调用getter和setter方法
一直的概念是“类的属性必须封装,封装之后的属性要通过setter和getter方法”设置取得,下面演示怎么调用
Person类中的setter和getter方法。
public class Person implements China{
private String name;
private int age;
public Person() {
System.out.println("我是构造方法...");
}
public Person(String name,int age) {
this.name=name;
this.age=age;
System.out.println("我是有参构造方法...");
}
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 "姓名:"+this.name+";"+"年龄:"+this.age;
}
@Override
public void sayChina() {
System.out.println("作者:"+ANTHOR+"--"+"国籍:"+NATIONAL);
}
@Override
public String sayHello(String name, int age) {
// TODO Auto-generated method stub
return name+",您好,我今年"+age+"岁了。";
}
}
public class Demo{
public static void main(String[] args) throws Exception{
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Object o=c.newInstance();
setter(o, "name", "张三", String.class);
setter(o, "age", 30, int.class);
System.out.println("姓名:");
getter(o, "name");
System.out.println("年龄:");
getter(o, "age");
}
public static void setter(Object obj,String str,Object val,Class<?> type)
throws Exception {
Method m=obj.getClass().getMethod("set"+initStr(str), type);
m.invoke(obj, val);
}
public static void getter(Object obj,String str) throws Exception{
Method m=obj.getClass().getMethod("get"+initStr(str));
System.out.println(m.invoke(obj));
}
public static String initStr(String old) {
String str=old.substring(0,1).toUpperCase()+old.substring(1);
return str;//单词首字母大写
}
}
结果:
我是构造方法...
姓名:
张三
年龄:
30
实例:通过反射操作属性
在反射操作中,虽然可以使用Method调用类中的setter个getter方法设置和取得属性,但是这样操作毕竟很
麻烦,所以在反射机制中也可以直接通过Field类操作类中的属性,通过Field类提供的set和get方法就可以
完成设置和取得属性的操作,但是在操作前首先注意的是,在类中所有的属性已经设置成私有的访问权限,
所以在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要擦操作的属性
设置成可以 被外部访问。
public class Demo{
public static void main(String[] args) throws Exception{
Class<?> c=null;
try {
c=Class.forName("myTest.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Object o=c.newInstance();
Field nameField=null;
Field ageField=null;
nameField=c.getDeclaredField("name");
ageField=c.getDeclaredField("age");
nameField.setAccessible(true);
nameField.set(o, "lisi");
ageField.setAccessible(true);
ageField.set(o, 14);
System.out.println("姓名:"+nameField.get(o));
System.out.println("年龄:"+ageField.get(o));
}
}
结果:
姓名:lisi
年龄:14
通过反射操作数组
反射机制不仅只能用在类上,还可以用在任意的引用数据类型的数据上,这就包括数组,可以通过以下方式取得一个数组的Class对象。
public native Class<?> getComponentType();
在反射操作包java.lang.reflect中使用Array类表示一个数组,可以通过此类取得数组长度和数组内容的操作。
实例:取得数组信息,并修改数组
public class Demo{
public static void main(String[] args) throws Exception{
int temp[]= {1,2,3,4};
Class<?> cl=temp.getClass().getComponentType();
System.out.println("类型:"+cl.getName());
System.out.println("长度:"+Array.getLength(temp));
System.out.println("第一个内容:"+Array.get(temp,0));
//修改第一个内容
Array.set(temp, 0, 5);
System.out.println("第一个内容:"+Array.get(temp,0));
}
}
结果:
类型:int
长度:4
第一个内容:1
第一个内容:5
动态代理
之前所讲解的代理类属于静态代理,因为每一个代理类只能为一个接口服务,这样一来程序开发中必然产生很多个代理。最好的做法是通过一个代理类完成全部的代理功能。那么此时就必须使用动态代理来完成。
在java中想要实现动态代理机制,则需要java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类的支持。
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
在接口中指定义了一个invoke方法,此方法中有三个参数,参数意义如下:
Object proxy:被代理的对象
Method method:要调用的方法
Object[] args:方法调用时所需要的参数。
Proxy是专门完成代理的操作类,可以通过此类为一个和多个接口动态的生成实现类。
Proxy类提供了如下方法:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
通过newProxyInstance可以动态的生成实现类,此方法参数意义如下:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler 接口子类的实例
类加载器
在Proxy类的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在java中主要有三种加载器:
Bootstrapt ClassLoader:此加载器采用C++编写,一般开发中是看不到的。
Extension ClassLoader:用来进行拓展类的加载,一般对应的是jre\lib\ext目录中的类。
AppClassLoader:加载classpath指定的类,是最常用的一种加载器。
实例:取得加载器
public class Demo{
public static void main(String[] args) throws Exception{
Person p=new Person();
String cl=p.getClass().getClassLoader().getClass().getName();
System.out.println(cl);
}
}
结果:
我是构造方法...
sun.misc.Launcher$AppClassLoader
从结果来看,默认的ClassLoader就是AppClassLoader
如果要完成动态代理,首先定义一个InvocationHandler接口的子类,已完成代理的具体操作。
public interface China{
public static final String NATIONAL="China";
public static final String ANTHOR="张三";
public void sayChina();
public String sayHello(String name,int age);
}
public class Person implements China{
private String name;
private int age;
public Person() {
System.out.println("我是构造方法...");
}
public Person(String name,int age) {
this.name=name;
this.age=age;
System.out.println("我是有参构造方法...");
}
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 "姓名:"+this.name+";"+"年龄:"+this.age;
}
@Override
public void sayChina() {
System.out.println("作者:"+ANTHOR+"--"+"国籍:"+NATIONAL);
}
@Override
public String sayHello(String name, int age) {
// TODO Auto-generated method stub
return name+",您好,我今年"+age+"岁了。";
}
}
public class MyInvoHandler implements InvocationHandler{
private Object obj;
public Object bind(Object obj) {
this.obj=obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object temp=method.invoke(this.obj, args);
return temp;
}
}
public class Demo{
public static void main(String[] args) throws Exception{
MyInvoHandler myInvoke=new MyInvoHandler();
China china=(China) myInvoke.bind(new Person());
String str=china.sayHello("老师", 7);
System.out.println(str);
}
}
结果:
我是构造方法...
老师,您好,我今年7岁了。
完成的功能与之前的静态代理没什么不同,所以在一般的开发中很少会使用这种动态代理的机制,但在编写一些
底层代码或者是一些框架(如Spring Framework)时这种动态代理就比较常用了。
类的声明周期
在一个类编译完成之后,下一步就要开始使用类,如果要使用类肯定离不开JVM。在程序执行中,JVM通过装载、链接、初始化3个步骤完成 。类的装载就是通过类的加载器,把.Class二进制文件装入JVM方法区,并在堆区创建描述该类的java.lang.Class对象,用来封装数据。注意:同一个类只会被JVM加载一次。
链接就是把二进制数据组装成可运行状态。
链接分为:校验、准备、解析3个步骤,校验是用来确认此二进制文件是否适合当前的JVM版本,准备就是为静态成员分配内存空间,并设置默认值。解析指的是转换常量池的代码引用为直接引用的过程,直到所有的符号引用都可被运行程序使用,(建立完整的对应关系),完成之后类型即可初始化,初始化之后类的对象就可以正常使用,直到一个对象不再使用之后,将被垃圾回收,释放空间。当没有任何引用指向Class对象时,将被卸载,结束类的声明周期。
工厂设计模式
将反射应用在工厂设计模式中
工厂设计模式在实际开发中使用的非常多,通过简单的工厂设计模式可以达到类的解耦目的,但是之前的工厂设计模式依然存在问题,那就是增加一个子类时,都需要修改工厂类,现在通过反射机制来修改工厂类让其在增加子类时可以不做任何修改,就达到功能补充。
使用反射完成工厂设计
创建一个水果接口
interface Fruit {
public void eat();
}
创建实现类苹果
public class Apple implements Fruit{
@Override
public void eat() {
System.out.println("...吃苹果");
}
}
创建实现类橘子
public class Orange implements Fruit{
@Override
public void eat() {
System.out.println("...吃橘子");
}
}
通过反射创建工厂类
class Factory{
public static Fruit getInstance(String className) throws Exception {
Fruit fruit=null;
fruit=(Fruit) Class.forName(className).newInstance();
return fruit;
}
}
动态传入类型,通过工厂调用
public class Demo{
public static void main(String[] args) throws Exception{
Fruit f=Factory.getInstance("myTest.Apple");
if(f!=null) {
f.eat();
}
}
}
结果:
...吃苹果
实例:结合属性文件的工厂模式
以上操作代码虽然可以通过反射取得接口实例,但是在操作时需要传入完整的包.类名称,而且用户也无法知道
一个接口有多少个可以使用的子类,所以此时可以通过属性文件的形式配置所要的子类信息
就是把所有的子类放到属性文件中,set的放到属性文件中,在工厂使用时get出来
总结要点:
1.Class类是反射机制操作的源头
2.Class类的对象有三种实现方式
(1)通过Object类中的getClass()方法
(2)通过“类.Class”形式
(3)通过“Class.forName()”方法,这种方式最常见
3.可以通过Class类中的newInstance()方法进行对象的实例化操作,但是要求类必须存在无参构造方法,如果类中没有无参的构造方法,则必须使用Constructor类完成对象的实例化操作。
4.可以通过反射取得一个类所继承的父类、实现的接口、类中的全部构造方法、全部普通方法及全部属性。
5.使用反射机制可以通过Method调用类中的方法,也可以直接操作类中的属性。
6.动态代理可以解决开发中代理类过多的问题,提供统一的代理实现功能。