黑马程序员--------------学习JAVA反射(Reflection)

------- android培训java培训、期待与您交流! ----------

一:什么是反射。

反射的概念:主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。

java中的反射:是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说自审,并能直接操作程序的内部属性和方法

总结:简而言之Java的反射能在程序运行的时候,获取正在运行类中的属性和方法。并且还能访问、检测和修改他们的能力。

二:反射的基础Class类。

Java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class.

如何得到Class的对象呢?有三种方法可以的获取:
    1调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。例如:
     MyObject x;
     Class c1 = x.getClass();
    2使用Class类的中静态forName()方法获得与字符串对应的Class对象。例如: 
     Class c2=Class.forName("MyObject"),Employee必须是接口或者类的名字。
    3获取Class类型对象的第三个方法非常简单。如果T是一个Java类型,那么T.class代表了匹配的类对象。例如
     Class cl1 = Manager.class;
     Class cl2 = int.class;
     Class cl3 = Double[].class;
    注意:Class对象实际上描述的只是类型,而这类型未必是类或者接口。例如上面的int.class是一个Class类型的对象。由于历史原因,数组类型的getName方法会返回奇怪的名字。

Class类的常用方法
    1getName() 
     一个Class对象描述了一个特定类的属性,Class类中最常用的方法getName以  String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void 名称。

    2newInstance()
     Class还有一个有用的方法可以为类创建一个实例,这个方法叫做newInstance() 例如:
     x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调 用默认构造器(无参数构造器)初始化新建对象。

    3getClassLoader() 
     返回该类的类加载器。

Class的一些使用技巧
    1forNamenewInstance结合起来使用,可以根据存储在字符串中的类名创建对象。例
     Object obj = Class.forName(s).newInstance();

    2、虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类 对象。例如:
     if(e.getClass() == Employee.class)...

 

三:什么是字节码        

字节码是一种中间码,它比机械码更抽象。它经常被看作是包含一个执行程序的二进制文件,更像一个对象模型。在java中,字节码CPU构架(JVM)的具有可移植性的机械语言。

 

四:写java反射类一般的两步骤:

第一步:获取类的字节码;获取方法有四种:

第一种:运用getClass()  注:每个class 都有此函数

第二种:运用Class.getSuperclass() 通过子类求出父类的字节码

第三种:运用Class.forName()(最常被使用)。通过用Class类中的方法

第四种:运用primitive wrapper classesTYPE 语法,这个有局限性只能用于 九个预定义的对象:八个基本数据对象 +  void

举例:

String str1 = "abc";

第一种:Class cls1 = str1.getClass(); 或者Class cls2 = String.class;

第二种:Class c2 = cls1.getSuperclass();

第三种:Class cls3 = Class.forName("java.lang.String");

第四种:Class c1 = Boolean.TYPE;

 

第二步:使用javaapi,常用的操作类有。

Field类:简单的理解可以把它看成一个封装反射类的属性的类。

//构造一个含构造方法的变量

public class ReflectPoint {
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}


得到某个类中的某个public成员变量:

例:Field  filedY = pt1. getClass.getField(“y”);

打印某个类中的某个public成员变量:

System.out.println(fieldY.get(pt1));

得到某个类中的某个private成员变量:

Field  filedX = pt1. getClass.getDeclaredfield(“x”);

打印某个类中的某个private成员变量:

fieldX.setAccessible(true);

System.out.println(fieldx.get(pt1));

Constructor类:Constructor类则封装了反射类的构造方法。

   得到某个类所有的构造方法:

         例:Constructor[] constructor = Class.forName(“java lang String”).getCoustructor();

得到某一个的构造方法:

         例:Constructor constructor = 

Class.forName(“java lang String”).getCoustructor(StringBuffer.class);

创建实例对象。

通常方式:

String str = new String(new StringBuffer(“abc”));

反射方式:

String str = (String)constructor.newInstance(new StringBuffer(“abc”));

Method类:它是用来封装反射类方法的一个类。

//方法与对象时没有关系的。参数(方法的名字,参数类型)

String Str1 = "abc";

获取某个对象的方法。

Method methodCharAt = String.class.getMethod("charAt"int.class);

调用某个对象方法中的方法。

//invoke意思是调用,方法对象中的方法。(对象名,传入的参数)

System.out.println(methodCharAt.invoke(Str1, 1));

//如果invoke(null, 1)第一个参数为null,则这个方法是静态方法。

五:数组与Object之间注意事项。 

1.数组是基础类型(int,byte,short,long, char, double,float ,boolean )的数组就不能存入Object数组内;

例:int[] a1 = new int[]{1,2,3};

Object[] obj = a1;//是错误的。

原因:Object[]内部要装的是Object类型的元素,而int[] a1内装的是int类型的数组(基本类型),所以错误。

2.数组不是基本类型时,数组存入Object数组时要拆包。

例:

int[] a1 = new int[]{1,2,3};

String[] a4 = new String[]{"a","b","c"};

sop(Arrays.asList(a1));//打印的是[[I@3d4b7453]

sop(Arrays.asList(a4));//打印的是[a, b, c]
原因:jdk1.4中的asList接收的是Object的数组,因为是int类型,所以和Object[]数组对不上, 所以跳到jdk1.5版本中T... a可变参数的Object,但这Object当做是一个参数,

五:数组的反射

1.创建数组打印的类,所以要获取字节码,数组长度。

public static void printObject(Object obj){
Class<? extends Object> clazz = obj.getClass();
if(clazz.isArray()){//假如是数组
 int len =Array.getLength(obj);
 for(int i = 0 ; i < len; i++){
 System.out.println(Array.get(obj, i));
 }
}else{
System.out.println(obj);
}
}

2.就是对数组就会拆包,对不是数组就打印。

printObject(a4);
printObject("xcv");
printObject(a1);

打印结果:

a

b

c

xcv

1

2

3

 

六:反射实现框架功能:

框架(Framework:

是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用

方面而后者是从目的方面给出的定义。

框架与工具的区别:

工具被用户的类调用,而框架则是调用用户提供的类。

框架解决的核心问题:

1.框架要顾及以后写的类。

2.框架不能new实例对象,而是要用反射类获取。

框架举例:

package fanshe2;
//用反射做框架
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Properties;
public class ReflectTest3 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
InputStream ips = ReflectTest3.class.getClassLoader().getResourceAsStream("config2.properties");
Properties props = new Properties();
props.load(ips);
ips.close();//要马上关闭资源,因为这样系统资源会泄露。
 
String className = props.getProperty("className");
Collection collections = (Collection)Class.forName(className).newInstance();
ReflectPoint pt1= new ReflectPoint(3,3); 
ReflectPoint pt2= new ReflectPoint(5,5); 
ReflectPoint pt3= new ReflectPoint(3,3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);
System.out.println(collections.size());
}
}

在反射中配置文件的设置方法://配置文件名叫config.properties

//配置文件方式一:-------------------------------------------------------------------------------------------

//config2.properties为相对路径,相对于当前工作目录

//InputStream ips = new FileInputStream("config2.properties");

//绝对路径例:("d:\\config2.properties");

//真正实际用途是配置出来的。就是用完整的路径,但完整的不是硬编码,而是运算出来的。getReal.path();

//配置文件方式二:用类加载器----------------------------------------------------------------------------

//InputStream ips = ReflectTest3.class.getClassLoader().getResourceAsStream("config2.properties");

//如果("config2.properties")这样写,则去classPath的根目录下逐个找"config2.properties"该文件。

//如果("fanshe2/config2.properties")

//类加载器方法的缺点只能读取文件,不能写文件。方式一还能写文件用OutputStream.

//配置文件方式三:用类方法:-------------------------------------------------------------------------------

InputStream ips = ReflectTest3.class.getResourceAsStream("config2.properties");

//如果配置文件不再自己的包内,则直接写成:

//InputStream ips = ReflectTest3.class.getResourceAsStream("fanshe22/config2.properties");

//如果所在的包名加入了/,则要完整的包名因为他是绝对路径了。

//InputStream ips = ReflectTest3.class.getResourceAsStream("完整的包路径/所在的包名/config2.properties");

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值