闪灵电影下载:基础加强第五天-- Java 反射

来源:百度文库 编辑:九乡新闻网 时间:2024/04/28 01:18:13
 

基础加强第五天

2011-03-10 18:04 11人阅读 评论(0) 收藏 举报

java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。java程

序中的各个java类,它们是否属于同一类,是不是可以用一个类来描述这类事物呢?这个类的名字就是Class。
java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class。
Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,Class类代表Java类,它的实例对象分别对象各个类在内存中的字节码,例如,Person类的字节码,

ArrayList类的字节码,等等。
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可

分别用一个个的对象来表示,这些对象显然具有相同的类型。
 public static void main(String[] args) throws Exception {
  String str="abc";
  Class cla1=str.getClass();
  Class cla2=String.class;
  Class cla3=Class.forName("java.lang.String");
  System.out.println(cla1==cla2);
  System.out.println(cla2==cla3);
  System.out.println(cla1.isPrimitive());
  System.out.println(int.class==Integer.class);
  System.out.println(int.class==Integer.TYPE);
 }
预定义Class实例对象:
Int.class==Integer.TYPE
boolean.class=Boolean.TYPE
byte.class=Byte.TYPE
char.class=Character.TYPE
short.class=Short.TYPE
long.class=Long.TYPE
float.class=Float.TYPE
double.class=Double.TYPE
void.class=Vlid.TYPE
数组类型的Class实例对象
Class.isArray()
只要是在原程序中出现的类型,都有各自的Class实例对象,例如:int[],void...

 

反射
反射就是把java类中的各种成分映射成相应的java类。例如,一个java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个

个的java类来表示。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是

Field、Method、Contructor、Package等等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,

  /*new String(new StringBuffer("abc"));*/
  Constructor constructor1=String.class.getConstructor(StringBuffer.class);
  String str2=(String)constructor1.newInstance(new StringBuffer("abc"));
  System.out.println(str2.charAt(0));
Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
例:Constructor[] constructors=Class.forName("java.lang.String").getConstructors();
得到某一个构造方法:
例:Constructor constructor=Class.forName("java.lang.String").getConstructor(String.class);
创建实例对象:
通常方式:String str=new String(new StringBuffer("abc"));
反射方式:String str=(String)constructor.newInstance(new StringBuffer("abc"));
Class.newInstance()方法:String obj=(String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码用到了缓存机制来保存默认构造方法的实例对象。

Field类代表某个类中的一个成员变量
public class ReflectPoint { 
 private int x;
 public int y;
 public ReflectPoint(int x, int y) {
  super();
  this.x = x;
  this.y = y;
 }
}

  ReflectPoint  pt1=new ReflectPoint(3,5);
  Field fieldy=pt1.getClass().getField("y");
  System.out.println(fieldy.get(pt1));
  Field fieldx=pt1.getClass().getDeclaredField("x");
  fieldx.setAccessible(true);
  System.out.println(fieldx.get(pt1));
得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段

fieldx代表是的x的定义,而不是具体的x变量,上例还可看出,变量x是私有的,y是公有的,所有在获取对象的时候x要比y麻烦点。

将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改成“a”。
import java.lang.reflect.Field;

public class ReflectTest {

 /**
  * @param args
  * @throws Exception 
  */
 public static void main(String[] args) throws Exception {
  
  ReflectPoint  pt1=new ReflectPoint(3,5);
  
  changeStringValue(pt1);
  System.out.println(pt1);
 }

 private static void changeStringValue(Object obj) throws Exception {
  Field[] fields=obj.getClass().getFields();
  for(Field field : fields){
   if(field.getType()==String.class){
    String oldValue=(String)field.get(obj);
    String newValue=oldValue.replace("b", "a");
    field.set(obj, newValue);
   }
  }
 }

}
public class ReflectPoint { 

 public String str1="ball";
 public String str2="basktball";
 public String str3="yello";
 
 public String toString(){
  return str1+"_"+str2+"-"+str3;
 }
}

Method类
Method类代表某个类中的一个成员方法
得到类中的某一个方法:
例:Method charAt=Class.forName("java.lang.String").getMethod("charAt",int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str,1));
如果传递给Method对象的invoke()方法的一个参数为null,说明该Method对象对应的是一个静态方法。
例:
  Method methodCharAt=String.class.getMethod("charAt", int.class);
  System.out.println(methodCharAt.invoke(str2, 1));
  System.out.println(methodCharAt.invoke(str2, new Object[]{0}));

jdk1.4和jdk1.5的invoke方法的区别:
jdk1.4:public Object invoke(Object obj,Object[] args),按jdk1.4的语法,需要讲一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被
jdk1.5:public Object invoke(Object obj,Object...args)

启动java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),普通方法调用mian方法:
  TestArguments.main(new String[]{"111","222","333"});

通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?有以下几种方法:
  String StaringClassName=args[0];
  Method mainMethod=Class.forName(StaringClassName).getMethod("main", String[].class);
  mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
  mainMethod.invoke(null, (Object)new String[]{"111","222","333"});

数组与Object的关系及反射类型
数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,即可以当做Object类型使用,又可以当做Object[]类型使用。
Arrays.asList()方法处理int[]和String[]时的差异。
例:
  int[] a1=new int[]{1,2,3};
  int[] a2=new int[4];
  int[][] a3=new int[1][2];
  String[] a4=new String[]{"a","b","c"};
  System.out.println(a1.getClass()==a2.getClass());
  //System.out.println(a1.getClass()==a3.getClass());
  //System.out.println(a1.getClass()==a4.getClass());
  System.out.println(a1.getClass().getName());
  System.out.println(a4.getClass().getSuperclass().getName());
  System.out.println(a1.getClass().getSuperclass().getName());
  
  Object obj1=a1;
  Object obj2=a4;
  //Object[] obj3=a1;
  Object[] obj4=a3;
  Object[] obj5=a4;
  
  System.out.println(a1);
  System.out.println(a4);
  System.out.println(Arrays.asList(a1));
  System.out.println(Arrays.asList(a4));
输出结果为:
true
[I
java.lang.Object
java.lang.Object
[I@14318bb
[Ljava.lang.String;@ca0b6
[[I@14318bb]
[a, b, c]

Array工具类用于完成对数组的反射操作:
 public static void main(String[] args){
  String[] a4=new String[]{"a","b","c"};
  printObject(a4);
  
  printObject("abc");
 }
 private static void printObject(Object obj){
  Class clazz=obj.getClass();
  if(clazz.isArray()){
   int len=Array.getLength(obj);
   for(int i=0;i    System.out.println(Array.get(obj, i));
   }
  }else{
   System.out.println(obj);
  }
 }
打印结果:
a
b
c
abc

怎样得到数组中的元素类型?
Object[] a=new ObetClass().getName();
a[1].getClass().getName();

ArrayList(),HashSet(),HashCode()三个方法的区别用下面实例说明:
public class ReflectPoint { 
 private int x;
 public int y;
 
 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + x;
  result = prime * result + y;
  return result;
 }
 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  ReflectPoint other = (ReflectPoint) obj;
  if (x != other.x)
   return false;
  if (y != other.y)
   return false;
  return true;
 }
 public ReflectPoint(int x, int y) {
  super();
  this.x = x;
  this.y = y;
 }
}
public class ReflectTest1 {

 /**
  * @param args
  */
 public static void main(String[] args) {
  //Collection collections=new ArrayList();
  Collection collections=new HashSet();
  ReflectPoint pt1=new ReflectPoint(3, 3);
  ReflectPoint pt2=new ReflectPoint(4, 5);
  ReflectPoint pt3=new ReflectPoint(3, 3);
  collections.add(pt1);
  collections.add(pt2);
  collections.add(pt3);
  collections.add(pt1);
  
  System.out.println(collections.size());
  
 }

}
用ArrayList()打印数字为4,用HashSet()打印数字为3,用HashCode()打印数字为2


当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,

在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集区