Java笔记7 Java基础加强<1>反射

时间:2022-01-17 15:57:58


17_张孝祥_Java基础加强_透彻分析反射的基础_Class类

l  如何得到各个字节码对应的实例对象(Claass类型)

Ø  类名.class,例如System.class

Ø  对象.getClass,例如:new Data().getClass();

Ø  Class forName(“类名”),例如:ClassforName(“java utile Date”);

l  九个预定义Class实例对象:

Ø  8种基本数据类型(booleanbytecharshortintlongfloatdouble)和void。

Ø  基本数据类型.class == 基本数据包装类.TYPE。例如,int.class == Integer.TYPE;

l  数组类型的Class实例对象。

Ø  Class isArray()

²  总之,只要在源程序中出现类型,都有各自的Class实例对象,例如int[],void。

代码演示:

String str1 = "abc";

Class cls1 = str1.getClass();

Class cls2 = String.class;

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

System.out.println(cls1 ==cls2);//true

System.out.println(cls1 ==cls3);//true

      

System.out.println(cls1.isPrimitive());//false

System.out.println(int.class.isPrimitive());//true

System.out.println(int.class == Integer.class);//false

System.out.println(int.class == Integer.TYPE);//true

System.out.println(int[].class.isPrimitive());//false

System.out.println(int[].class.isArray());//true

 

 

18_张孝祥_Java基础加强_理解反射的概念

l  反射就是把Java类中的各种成分映射成相应的java类。一个类中的组成部分:成员变量,方法,构造方法,包等等。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。

 

 

19_张孝祥_Java基础加强_构造方法的反射应用

l  Constructor类代表某个类中的一个构造方法

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

Ø  例子:Constructor [] constructors=Class.forName("java.lang.String").getConstructors();

l  得到某一个构造方法:

Ø  例子:Constructor constructor =

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

l  创建实例对象:

Ø  通常方式:String str = new String(newStringBuffer("abc"));

Ø  反射方式: String str = (String)constructor.newInstance(newStringBuffer("abc"));

代码演示:

package day25reflect;

 

public class Person {

    private int num;

    private Stringname;

    public Person(String name){

       this.name = name;

    }

    public Person(String name,int num){

       this.name = name;

       this.num = num;

    }

}

 

package day25reflect;

 

import java.lang.reflect.Constructor;

 

public class ReflectTest {

 

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

       Class<Person> cls = (Class<Person>)Class.forName("day25reflect.Person");//注意包名省略会报错

       Constructor<Person> constructor1 =(Constructor<Person>)cls.getConstructor(String.class,int.class);

       Person p1 = constructor1.newInstance("李某某",24);

       System.out.println(p1);

       Constructor<Person> constructor2 =(Constructor<Person>)cls.getConstructor(String.class);

       Person p2 = constructor2.newInstance("李某某");

       System.out.println(p2);

      

       Constructor constructor3 =

              Class.forName("java.lang.String").getConstructor(StringBuffer.class);

       String str = (String)constructor3.newInstance(new StringBuffer("abc"));

       System.out.println(str);

      

       Constructor constructor4 =

              Class.forName("java.lang.String").getConstructor(char[].class);

       String str2 = (String)constructor4.newInstance(newchar[]{'a','b','c'});

       System.out.println(str2);

    }

}

打印结果:

day25reflect.Person@c17164

day25reflect.Person@1fb8ee3

abc

abc

//通过newInstance方法返回的结果都是指定类型的实例对象。

 

 

20_张孝祥_Java基础加强_成员变量的反射

/*ReflectPoint.java*/

import java.util.Date;

 

public class ReflectPoint {

    private Datebirthday =new Date();

   

    private int x;

    public int y;

    public Stringstr1 ="ball";

    public Stringstr2 ="basketball";

    public Stringstr3 ="itcast";

   

    public ReflectPoint(int x,int y) {

       super();

       this.x = x;

       this.y = 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;

       final ReflectPoint other = (ReflectPoint) obj;

       if (x != other.x)

           return false;

       if (y != other.y)

           return false;

       return true;

    }

 

    @Override

    public String toString(){

       returnstr1 +":" +str2 +":" +str3;

    }

/*成员变量的setget方法省略*/ 

}

 

l  成员变量的反射示例

ReflectPoint pt1 = newReflectPoint(3,5);

Field fieldY =pt1.getClass().getField("y");

//fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上,要用它去取某个对//象上对应的值

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

Field fieldX =pt1.getClass().getDeclaredField("x");//受保护或私有成员变//量须调用此方法。

fieldX.setAccessible(true);

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

 

 

21_张孝祥_Java基础加强_成员变量反射的综合案例

l  改变字段的函数:

private static void changeStringValue(Object obj)throws Exception {

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

       for(Field field : fields){

           //if(field.getType().equals(String.class)){

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

              String oldValue = (String)field.get(obj);

              String newValue = oldValue.replace('b','a');//将字段变量//的字符b换成a。

              field.set(obj, newValue);

           }

       }  

    }

}

 

 

22_张孝祥_Java基础加强_成员方法的反射

l  成员方法放射举例:

String str1 = “abc”;

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

System.out.println(methodCharAt.invoke(str1,1));//b

System.out.println(methodCharAt.invoke(str1,new Object[]{2}));//c

      

l  jdk1.4和jdk1.5的invoke方法的区别:

Ø  Jdk1.5:public Objectinvoke(Object obj,Object... args)

Ø  Jdk1.4:public Objectinvoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。

 

 

23_张孝祥_Java基础加强_对接收数组参数的成员方法进行反射

l  问题:

启动Java程序的main方法的参数是一个字符串数组,即public static voidmain(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mainMethod.invoke(null,newString[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不把它当作jdk1.5的语法解释,因此会出现参数类型不对的问题。

l  解决办法:

Ø  mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});

Ø  mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了。

代码演示:

//TestArguments.main(newString[]{"111","222","333"});

String startingClassName = args[0];

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

//mainMethod.invoke(null, newObject[]{new String[]{"111","222","333"}});

mainMethod.invoke(null, (Object)newString[]{"111","222","333"});

 

 

24_张孝祥_Java基础加强_数组与Object的关系及其反射类型

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

int [] a2 = new int[4];

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

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

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

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

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

System.out.println(a1.getClass().getName());

System.out.println(a1.getClass().getSuperclass().getName());

System.out.println(a4.getClass().getSuperclass().getName());

 

Object aObj1 = a1;

Object aObj2 = a4;

//Object[] aObj3 = a1;

Object[] aObj4 = a3;

Object[] aObj5 = a4;

      

System.out.println(a1);

System.out.println(a4);

System.out.println(Arrays.asList(a1));

System.out.println(Arrays.asList(a4));

}

 

 

25_张孝祥_Java基础加强_数组的反射应用

l  数组的反射

Ø  具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。

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

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

Ø  Arrays.asList()方法处理int[]和String[]时的差异。

Ø  Array工具类用于完成对数组的反射操作。

代码演示:

 

printObject(a4); 

printObject("xyz");

 

private static void printObject(Object obj) {

       Class 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);

       }  

    }

 

 

26_张孝祥_Java基础加强_ArrayList_HashSet的比较及Hashcode分析

代码演示:

/*首先,在Reflect类中重写hashCode和equals方法*/

 

/*下面为测试类中主函数的测试代码*/

Collection collections= newHashSet();

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);   

      

pt1.y = 7;   

collections.remove(pt1);

System.out.println(collections.size());//2

 

 

28_张孝祥_Java基础加强_用类加载器的方式管理资源和配置文件

/*getRealPath();//金山词霸/内部

       一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的。*/

      

       //获取相对路径,开发中不这么做。<配置1>

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

      

       /*获取当前工作目录下的文件(类加载器可以加载classpath目录文件,同样一

        般文件放到classpath目录中也能加载,注意,Eclipsesrc源文件目录中java

        文件编译后会以.class文件存到classpath目录中,其他文件会原封不动地存到

        classpath目录中),开发中常用到.<配置2>*/

       //InputStream ips =ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");

      

       //相对于当前包下面的文件.<配置3>

       //InputStream ips =ReflectTest2.class.getResourceAsStream("resources/config.properties");

      

       //路径"/"开头,表示是从根目录开始。<配置4>

       InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");

 

       Properties props = new Properties();

       props.load(ips);

       ips.close();

       StringclassName = props.getProperty("className");