--------------------- android培训、java培训、java学习型技术博客、期待与您交流! -------------------
反射
概述:反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等
应用:
当程序使用的类不确定时,可以通过提供配置文件,让使用者将具体的类存储到配置文件中。然后该程序通过反射技术,对指定的类进行内容的获取。
好处:反射技术大大提高了程序的扩展性
反射的基石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对应的是类上面的成员变量,不是对象上的成员变量,代表的是成员的定义,不是具体的变量。
要获取具体对象上的变量值可以通过Field的get方法将对象作为参数传入,即可获得该对象上所对应变量的值。
代码演示:
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类
概述:代表某个类中的一个成员方法,用于反射成员方法
得到类中的某一个方法,通过Class的getMethod方法传入指定的方法和该方法中所定义的参数的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学习型技术博客、期待与您交流! -------------------