一丶反射的理解。
在正常情况下,我们可以通过一个封装好的类来进行一个对象的实例化操作。
反过来,我们通过实例化好的对象来【取得类的完整的信息】,这就是反射。
通过反射,我们可以取得反向的信息,取得一个完整对象的所属于【包.类】名称。
二丶反射的结果—Class类。
Class类是一切反射的根源,此类的定义如下:
pubilc final class Class<T> extends Object
implements Serializable,GenericDeclaration,Type,AnnotatedElement
此类是一个最终类,是不允许有子类的,而且有泛型,证明要指明泛型。
可以通过以下的三种方法进行实例化操作:
1、Object类中的getClass()方法。
package org.study.RebortChao;
public class ClassDemo{
public static void main(String[] args){
String str = "HELLO";
Class<?> cls = str.getClass();
System.out.println(cls.getName());
}
}
2、通过【.class】完成。
package org.study.RebortChao;
public class ClassDemo01{
public static void main(String[] args){
Class<?> cls = String.class;
System.out.println(cls.getName());
}
}
3、通过Class类内部的forName()方法完成。
重点内容
package org.study.RebortChao;
public class ClassDemo02{
public static void main(String[] args){
Class<?> cls = Class.forName("java.lang.String");
System.out.println(cls.getName());
}
}
三丶使用Class类进行对象的实例化。
Class的最大好处是通过【包.类名称】进行对象的实例化。
1、调用无参构造进行实例化。——这里的类构造器是没有参数的。
正常情况下,必须通过关键字new进行对象的实例化操作。
但是,
现在有了Class类之后,直接通过反射进行对象的实例化操作。
package org.study.RebortChao;
public class ClassObjectDemo01{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("类全名");
类名称 变量名称 = (类名称) cls.newInstance();
/*set类的一系列操作。*/
System.out.println(变量名称);
}
}
这里的【类全名】获取方法:【右击类名称】-->【copy qualified name】
另一种比较方便的形式是(无参构造的最常用形式):
无参构造的最常用形式。
package org.study.RebortChao;
public class ClassObjectDemo02{
public static void main(String[] args) throws Exception{
类名称 变量名称 = (类名称) cls.forName("类全名").newInstance();
/*set类的一系列操作。*/
System.out.println(变量名称);
}
}
以上的两种操作方法都是只适用于存在无参构造器的方法。
2、调用含参构造进行实例化。
这个时候必须按照如下步骤完成:
①、还是实例化Class类的对象。
②、通过Class类找到此类中的构造方法。
③、通过构造方法明确的给出需要的参数,并进行对象的实例化操作。
Class通过以下的方法取得一个类中的全部构造:
`java.lang.reflect.Constructor`
①、一个类中存多个构造方法,所以将返回一个Constructor的对象数组。
②、此方法接受的一个可变参数,在调用以上方法的时候,需要指明参数的顺序及个数。
范例:
通过Constructor进行对象的实例化操作。
package org.study.RebortChao;
import java.lang.reflect.Constructor;
public class ClassObjectDemo03{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("类全名");
Constructor<?>[] con=cls.getConstructor();
//得到全部构造。以数组的形式保存。
类名称 变量名称=(类名称) con[0].newInstance(对参数的操作);
System.out.println(变量名称);
}
}
明显的是比第一种的方法复杂,所以最好的建议是【类中保留无参构造方法】。
总结:对象实例化方法。
1、通过关键字new。耦合度加深,中间加入了工厂设计,来解决问题。
2、clone。对象的克隆。
3、通过Class类,进行反射加载实例化。(最方便,通过传入完整的【包。类】就可以。)
4、引用传递也是一种。
面向对象基础中有引用传递的信息
四丶全面的了解反射。
反射机制的最大好处就是可以通过一个Class类取得一个类中的完整信息。
完整信息包括:【继承的父类】、类中所有的【方法】和【属性】etc...
✎_取得类所在的包:
package org.study.RebortChao;
public class RefleDemo{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("类全名");
package pack = cls.getPackage();//取得包名
System.out.println(pack);
}
}
✎_取得类中的全部方法:
package org.study.RebortChao;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class RefleDemo01{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("类全名");
Method met[]= cls.getMethod(); //获取全部的方法
for(int x=0;x<met.length; x++){
int mod = met[x].getModifiers();//获取方法的修饰符
System.out.printin(Modifier.toString(mod)+"、");
/*toString()传入修饰符的数字,并转换为修饰符描述。*/
String ret=met[x].getReturnType().getName();//得到返回值的类型
System.out.println(ret+"、");
Class<?> param[]=met[x].getParameterTypes();//取得全部参数类型
for(int y=0;y<param.length;y++){
System.out.println(param[y].getName()+"arg-"+y);
if(y<param.length-1){
System.out.println("、");
}
}
System.out.println(")");
Class<?> exp[]=met[x].getExceptionTypes();//取得全部的异常
if(exp.length > 0){
System.out.println("throws ");
for(int y=0;y<exp.length;y++){
System.out.println(exp[y].getName());
}
if(y<exp.length-1){
System.out.println("、");
}
}
}
System.out.println(" ");
}
}
}
以上程序中用到许多常用的操作:
Method met[]=cls.getMethod();以对象数组的形式返回得到的全部方法。
met[x].getModifiers();得到全部的修饰符。
一般讲的修饰符是public、private之类的,它们可以按照一定的顺序相加,所以返回的是【整型】。
【整型的修饰符通过Modifier还原】Modifier.toString(mod)
met[x].getReturnType().getName();得到返回值类型。
met[x].getParameterTypes();得到全部的参数类型。
met[x].getExceptionTypes();得到全部的异常。
Modifier.toString(mod)传入修饰符的数字,并转换为修饰符描述。
✎_取得类中的全部属性:
package org.study.RebortChao;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class RefleDemo02{
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("类全名");
{
Field field[]=cls.getFields();
/*取得全部属性,这里的属性是继承来的属性。*/
for(int x=0; x<field.length; x++){
int mod=field[x].getModifiers();
System.out.println(Modifier.toString(mod)+" ");
//还原修饰符
System.out.println(
field[x].getType().getName()+" ");
System.out.println(field[x].getName()+" ");
}
}
{
Field field[]=cls.getDeclaredFields();
/*取得全部属性,是本类中的属性*/
for(int x=0; x<field.length; x++){
int mod=field[x].getModifiers();
System.out.println(Modifier.toString(mod)+" ");
//还原修饰符
System.out.println(
field[x].getType().getName()+" ");
/*取得属性的类型的名称*/
System.out.println(field[x].getName()+" ");
/*取得属性的名称*/
}
}
}
}
五丶通过反射操作类。
1、调用类中的方法。
正常的情况下,通过【对象.方法()】进行方法调用的。
那么,通过如下操作使用反射完成同样的操作:
getMethod()取得类中到的一个方法。
Object invoke()调用类中的方法,传入实例化对象,以及具体的参数内容。
调用类中【没有参数】的方法:
package org.study.RebortChao;
import java.lang.reflect.Method;
public class MethodInvokeDemo{
public static void main(String[] args) throws Exception{
Class<?> cls=Class.forName(类名称);
Method met=cls.getMethod("无参的方法");//调用无参的方法
met.invoke(cls.newInstance());//调用类中的方法
}
}
/*由于没有实例化对象,所以此时可以调用,都是通过Object完成的。*/
调用类中【有参数、有返回值】的方法
package org.study.RebortChao;
import java.lang.reflect.Method;
public class MethodInvokeDemo01{
public static void main(String[] args) throws Exception{
Class<?> cls=Class.forName("类名称");
Method met=cls.getMethod("有参有返回
值的方法",参数类型1.class,参数类型2.class,...);
/*调用有参有返回值的方法,还需要把传参数类型*/
Object obj=met.invoke(cls.newInstance()
,传参1,传参2,...);/*调用类中的方法*/
System.out.println(obj);
}
}
2、调用setter和getter
我们要求类中的所有属性都要封装,这样就可以使用反射机制进行方法的自动调用,只需要传入属性的名称就可以。
package org.study.RebortChao;
import java.lang.reflect.Method;
public class MethodInvokeDemo02{
public static void main(String[] args) throws Exception{
Class<?> cls=Class.forName("类名称");
Object obj=cls.newInstance();
setter(obj,"name","张三",String.class);
setter(obj,"age",20,,int.class);
getter(obj,"name");
getter(obj,"age");
}
public static void setter(Object inst,String attr,Object value,Class<?> valType) throws Exception{
Method met=inst.getClass().getMethod("set"+initCap(attr)+valType);
met.invoke(inst,value);
}
public static void getter(Object inst,String attr) throws Exception{
Method met=inst.getClass().getMethod("get"+initCap(attr));
Object re=met.invoke(inst);
System.out.println(re);
}
public static String initCap(String att){
StringBuffer buf = new StringBuffer();
buf.append(att.substring(0,1).toUpperCase()).append(att.substring(1));
return buf.toString();
}
}
/*开源框架中所采用的核心设计思想。这里只需要了解。*/
3、直接调用属性。
用到了java.lang.reflect.Field类
package org.study.RebortChao;
import java.lang.reflect.Field;
public class FieldObjectDemo{
public static void main(String[] args){
Class<?> cls = Class.forName("类全名");
Object obj = cls.newInstance();
Field name = cls.getDeclaredField("name");
Field age = cls.getDeclaredField("age");
name.setAccessible(true);//取消了private
age.setAccessible(true);//取消了private
name.set(obj,"张三");
age.set(obj,20);
System.out.println(name.get(obj));
System.out.println(age.get(obj));
}
}
/*一切都是以Object为操作的标准。*/
六丶在工厂设计中应用反射机制。
1、工厂设计。
90%的情况下,只要程序出现了接口,就必须通过工厂进行对象的【解耦合操作】。
package org.study.RebortChao;
interface IFruit{
public void eat();
}
class Apple implements IFruit{
pubnlic void eat(){
System.out.printin("Eatting Apple !");
}
}
class Orange implements IFruit{
pubnlic void eat(){
System.out.printin("Eatting Orange !");
}
}
class Factory{
public static IFruit getInstance(String className){
IFruit fruit = null ;
if("Apple".equal(className)){
fruit = new Apple();
}
if("Orange".equal(className)){
fruit = new orange();
}
return fruit;
}
}
public class Factory01{
public static void main(String[] args){
IFruit f = Factory.getInstance("Apple");
//这个的Apple是一个【类名称】。
f.eat();
}
}
/*基本上完成了一个工厂设计模式。*/
2、通过反射修改工厂。
依照之前的做法,每次扩充子类之后都要修改工厂。
【将反射机制应用在工厂之中】,则在子类扩充的时候就没有必要去修改工厂了。
package org.study.RebortChao;
interface IFruit{
public void eat();
}
class Apple implements IFruit{
pubnlic void eat(){
System.out.printin("Eatting Apple !");
}
}
class Orange implements IFruit{
pubnlic void eat(){
System.out.printin("Eatting Orange !");
}
}
class Factory{
public static IFruit getInstance(String className){
IFruit fruit = null ;
try{
fruit=(IFruit) Class.forName(className).newInstance();
}catch(InstantiationException e){
e.printStackTrace();
}catch(IllegalAccessException e){
e.printStackTrace();
}catch(ClassNotFoundException e){
e.printStackTrace();
}
return fruit;
}
}
public class Factory02{
public static void main(String[] args){
IFruit f = Factory.getInstance("org.study.RebortChao.Apple");
//这里需要传一个完整的【包.类名称】。
f.eat();
}
}
/*如果程序突然修改了这个类所在的包,则程序就非常麻烦了。
此时可以使用属性文件完成。*/
3、通过属性,进行子类的配置。
package org.study.RebortChao;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;
interface IFruit{
public void eat();
}
class Apple implements IFruit{
pubnlic void eat(){
System.out.printin("Eatting Apple !");
}
}
class Orange implements IFruit{
pubnlic void eat(){
System.out.printin("Eatting Orange !");
}
}
class PropertiesOperate{ //属性操作
private Properties pro = null;
private PropertiesOperate(){
this.pro=new Properties();
File f=new File("存放的磁盘位 置"+File.separator+"fruit.xml");
if(f.exists()){
try{
this.pro.loadFromXML(new FileInputStream(f));
}catch(InstantiationException e){
e.printStackTrace();
}catch(IllegalAccessException e){
e.printStackTrace();
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}else{
this.pro.setProperty("fruit","org.study.RebortChao.Apple");
try{
this.pro.storeToXml(new FileOutputStream(f),"fruit Info");
}catch(FileNotFoundException e){
e.printStrackTrace();
}catch(IOException e){
e.printStrackTrace();
}
}
}
public Properties getPro(){
return this.pro;
}
}
class Factory{
public static IFruit getInstance(String className){
IFruit fruit = null ;
try{
fruit=(IFruit) Class.forName(className).newInstance();
}catch(InstantiationException e){
e.printStackTrace();
}catch(IllegalAccessException e){
e.printStackTrace();
}catch(ClassNotFoundException e){
e.printStackTrace();
}
return fruit;
}
}
public class Factory03{
public static void main(String[] args){
IFruit f = Factory.getInstance(new PropertiesOperate().getPro().getProperty("fruit"));
f.eat();
}
}
/*现在的程序可以通过配置文件进行控制,实现了配置文件和程序的相互分离的代码*/