黑马程序员-java高新之反射

--------------------- android培训java培训、java学习型技术博客、期待与您交流! -------------------

反射

概述:反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是FieldMethodContructorPackage等等

应用:

当程序使用的类不确定时,可以通过提供配置文件,让使用者将具体的类存储到配置文件中。然后该程序通过反射技术,对指定的类进行内容的获取。

好处:反射技术大大提高了程序的扩展性

反射的基石Class

Java程序中的各个Java类,它们是否属于同一类事物,是不是可以用一个类来描述这类事物呢?这个类的名字就是Class。每个java类都是Class的一个实例对象,它们的内容不同,但是,它们的特征相同,譬如,都有方法,有字段,有父类,有包。

Class的三种创建方式

Class c=对象.getClass()

局限性:必须要先创建对象,才能调用getClass方法

Class c1=类名.class

局限性:必须知道类名

String str="类名"

Class c2=Class.forName(str)

扩展性最强,只要将类名传入即可。

九个预定义Class实例对象

byte.Class

short.Class

int.Class

long.Class

double.Class

float.Class

char.Class

boolean.Class

void.Class

常用方法

static Class forName(String className)

返回与给定字符串名的类或接口的相关联的Class对象。

Class getClass()

返回的是Object运行时的类,即返回Class对象即字节码对象

Constructor getConstructor()返回Constructor对象

,它反映此Class对象所表示的类的指定公共构造方法。

Field getField(String name)返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段。

Field[] getFields()

返回包含某些Field对象的数组,表示所代表类中的成员字段。Method getMethod(String name,Class… parameterTypes)

返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法。

Method[] getMehtods()

返回一个包含某些Method对象的数组,是所代表的的类中的公共成员方法。String getName()

String形式返回此Class对象所表示的实体名称。

String getSuperclass()

返回此Class所表示的类的超类的名称定的Class对象是否是一个基本类型。

T newInstance()

创建此Class对象所表示的类的一个新实例。

 

代码演示

class ReflectDemo

{

       public static void main(String[] args)throws Exception

       {

              String str="abcd";

       Class cls1=str.getClass();

       Class cls2=String.Class;

       Class cls3=Class.forName("java.lang.String");

       System.out.println(cls1==cls2);//打印结果为ture

System.out.println(cls1==cls3);// 打印结果为ture

 

 

System.out.println(cls1.isPrimitve());//打印结果为false

System.out.println(int.Class.isPrimitive());//打印结果为ture

System.out.println(int[] Class.isPrimitve());//打印结果为false

System.out.println(int[] Class.isArray());//打印结果为ture

//只要是源程序中出现的类型,都有各自的Class实例对象,例如int[] void等

System.out.println(int.Class =Integer.Class);// 打印结果为false

System.out.println(int.Class =Integer.TYPE);// 打印结果为ture

 

}

}

注意:Integer.TYPE表示Integer中封装的基本数据对应的Class类,其他基本数据包装类中也有封装对应的基本数据Class类。

Constructor

概述:代表某个类中的一个构造方法,用于反射构造方法。

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

Constructor[] constructor=Class.forName("java.lang.String").getConstructors();

得到某个类中一个构造方法,通过指定构造方法的参数

Constructor cons=String.Class.get9Constyuctors(StringBuffer.Class);

反射构造实例对象

String str=(String)Cons.newInstance(StringBuffer("abc"))

当要构造的实例对象是默认的无参构造方法时,可以直接用Class.newInstanced来创建

String str1=(String)Class.forName("java.lang.String").newInstance();

注意:

通过放射构造对象时传入的参数必须与获得Constructor构造方法时传入的参数相同

Field

概述代表某个类中的一个成员变量,Field对应的是类上面的成员变量,不是对象上的成员变量,代表的是成员的定义,不是具体的变量。

要获取具体对象上的变量值可以通过Fieldget方法将对象作为参数传入,即可获得该对象上所对应变量的值。

代码演示:

class FiledDemo

{

       private int x;

       pulic  int y;

       public str1="basketball"

       public str2="ball"

       public str3="bounb"

       FiledDemo(int x,int y)

{

       this.x=x;

       this.y=y;

}

}

class Demo

{

       public static void main(String[] args)

{

       FieldDemo fd=new FieldDemo(3,6);

       //当成员变量非私有时

Field fieldy=fd.getClass().getField("y");

       int num=fieldy.get(fd);

       System.out.println(num);

       //当成员变量私有时

       //获取变量定义

Field fieldx=fd.getClass().getDeclaredField("x");

       //取消java语言访问检查

fieldx.setAccessible(true);

       int num1=fieldx.get(fd);

System.out.println(num);

      

}

}

小练习-将原对象变量中的b该为a

import java.lang.reflect.*;

public class FieldDemo

{

       public static void main(String[] args)throws Exception

       {

              Point pt =new Point();

              Field [] fields = pt.getClass().getFields();

              for(Field field: fields)

              {

                     if(field.getType()==String.class)

                     {

                            String oldvalue =(String)field.get(pt);

                            String newvalue=oldvalue.replace("b","a");

                            field.set(pt,newvalue);

                     }

              }

       System.out.println(pt.toString());

 

       }

}     

class Point

{

       public String str1="basketball";

       public String str2="ball";

       public String str3="bounb";

       public String toString ()

       {

              return str1+"::"+str2+"::"+str3;

       }

}

}

Method

概述:代表某个类中的一个成员方法,用于反射成员方法

得到类中的某一个方法,通过ClassgetMethod方法传入指定的方法和该方法中所定义的参数的Class

Method charAt=Class.forName("java.lang.String").getMethod("charAt",int.class);

通过反射调用方法,需要将对应的对象和方法定义的参数传入

charAt.invoke()

特殊情况,当invoke中的第一参数为null时证明该方法对应的是一个静态方法。

小练习-通过反射调用main方法

class MianDemo

{

       public static void main(String[] args)

{

       for(String arg:args)

{

       System.out.println(arg);

}

}

}

class RunMain

{

       public static void main(String[] args)

{

       //定义一个字符串等于传入的第一个字符串

String startmain=args[0];

//通过传入的字符串获取main方法

Method mianmethod=Class.forName("startmain"). getMethod("main",String[].class);

//运行main方法,将传入的数据打包成一个数组传入

Mainmethod.invoke(null,Object[]{String[]{"adavc","kfh"}})
}

}

注意:运行时要将类名MianDemo传入或自定义一个类名运行。

数组的反射

概述:具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。

代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class

基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。

代码演示:

class ArrayDemo

{

       public static void main(String[] args)

       {

       int [] a1=new int[3];

       int [] a2=new int[4];

       int [][] a3=new int[3][2];

       String [] a4=new String [3];

       //打印结果为true说明同一类型同一维度的数组属于同一类型

       System.out.println(a1.getClass==a2.getClass);

//打印结果为false说明同一类型不同一维度的数组不属于同一类型

System.out.println(a1.getClass==a3.getClass);

//打印结果为false说明不同一类型同一维度的数组不属于同一类型

System.out.println(a1.getClass==a4.getClass);

}

}

小练习-打印数组中的元素

class ArrayDemo1

{

       public static void main(String[] args)

       {

              String [] strs=new String{"abc""abb""abd"};

              String str1="str1";

              printObject(strs);

              printObject(str1);

}

private static void printObject(Object obj)

{

       Class clazz=obj.getClass();

       if(clazz.isArray())

{

       int len=Arrays.getlength(obj);

       for(int x=0;x<len;x++)

{

       Systrm.out.println(Array.get(obj,x));

}

}

else

{

       System.out.println(obj);

}

}

}

hashCode详解:

1哈希算法的由来:若在一个集合中查找是否含有某个对象,通常是一个个的去比较,找到后还要进行equals的比较,对象特别多时,效率很低。有这么一种HashCode算法,有一个集合,把这个集合分成若干个区域,每个存进来的对象,可以算出一个hashCode值,根据算出来的值,就放到相应的区域中去。当要查找某一个对象,只要算出这个对象的hashCode值,看属于第几个区域,然后到相应的区域中去寻找,看是否有与此对象相等的对象。这样查找的性能就提高了。2要想HashCode方法有价值的话,前提是对象存入的是hash算法这种类型的集合当中才有价值。如果不存入是hashCode算法的集合中,则不用复写此方法。

3如果没有复写hashCode方法,对象的hashCode值是按照内存地址进行计算的。这样即使两个对象的内容是想等的,但是存入集合中的内存地址值不同,导致hashCode值也不同,被存入的区域也不同。所以两个内容相等的对象,就可以存入集合中。如果对象存入的不是根据hash算法的集合中,就不需要复写hashCode方法。

4当一个对象存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则对象修改后的哈希值与最初存储进HashSet集合中的哈希值就不同了。在这种情况下,调用contains方法或者remove方法来寻找或者删除这个对象的引用,就会找不到这个对象。从而导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。(程序中某一些对象不再被使用,以为被删掉了,但是没有,还一直在占用内存中,当这样的对象慢慢增加时,就会造成内存泄露。)

反射的应用示例

框架概念:

我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。

实现框架功能

import java.io.InputStream;

import java.util.Collection;

import java.util.Properties;

class OutlineDemo

{

public static void main(String[] args) throws Exception

{

InputStream ips = new FileInputStream("config.properties");

Properties prop=new Properties();

Prop.load(ips);

Ips.close();

String className=prop.getProperty("className");

Collection coll=( Collection)Class.forName(className);

FiledDemo fd1=new FiledDemo(1,3);

FiledDemo fd2=new FiledDemo(2,3);

FiledDemo fd3=new FiledDemo(2,3);

coll.add(fd1);

coll.add(fd2);

coll.add(fd3);

coll.add(fd4);

System.out.println(coll.size());

}

}

--------------------- android培训java培训、java学习型技术博客、期待与您交流! -------------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值