黑马程序员_Java基础加强之反射

来源:互联网 发布:f999b隔墙听淘宝有卖吗 编辑:程序博客网 时间:2024/05/17 23:44
------- android培训java培训、期待与您交流! ----------

反射

反射的基石 Class类,java是面向对象的,任何一个对象都属于某个类。运行xx.java文件会产生一些扩展名为??.class的文件。这些??.class文件是Class类的实例对象。

xx.class文件是xx类的字节码文件。这些文件是二进制编码,用于jvm加载调用。

什么是字节码,当jvm用到xx类是,首先jvm会把xx.class类,加载进内存。每一个java程序至少有一个字节码文件。

获取Class对象的几种方法:

TYPE.class;    用类名直接获取class文件,Class cls1 = Integer.class;

Var.getClass();  用实例变量名获取class文件, Class cls2 = new String().getClass();

Class.forName(String ClassName); 通过文件名来获取class文件, Class cls3 = Class.forName("Object.lang.String");注意异常。

九个预定义的Class实例对象

有九种预定义的 Class 对象,表示八个基本类型和 void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即 booleanbytecharshortintlongfloat 和 double

如何判断是否是基本类型用isPrimitive()来判断。

数组类型不是基本数据类型,System.out.println(int[].class.isPrimitive())打印出false

获取class的基本信息

反射就是把java中的各种成分映射成相应的java类。一个类的组成部分:成员变量、方法、构造方法、包、注解等信息。这些信息可以通过getField(String name),,getFields(),getMthod(Stringname,Class<?>...parameterTypes),getConstructor(Class<?>... parameterTypes),getConstructors()等等来获取各种类的信息。具体可以查阅API文档,不再赘述。

构造方法的反射应用

怎么获取类的构造函数,可以获取被private修饰的构造方法,并且创建对象。举例说明:

public class Test {

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

//得到String的所有构造方法

Constructor[] con = String.class.getConstructors();

//获取 String(StringBuffer buffer)构造方法

Constructor sb = String.class.getConstructor(StringBuffer.class);

//获取String(char[] value, int offset, int count) 构造方法

Constructor cii = String.class.getConstructor(char[].class,int.class,int.class);

//获取实例对象 

String  str1 = (String) sb.newInstance( new StringBuffer("abcde"));

System.out.println(str1);

str1 = (String) cii.newInstance("abcde".toCharArray(),0,"abcde".length());

System.out.println(str1);

//该方法返回的实例是空惨构造方法返回实例对象

str1 = String.class.newInstance();

System.out.println(str1);

}

}

可以通过使用泛型的方法去掉强制转换,加粗字段部分语句改成如下:

Constructor<String> cii = String.class.getConstructor(char[].class,int.class,int.class);

String  str1 = sb.newInstance( new StringBuffer("abcde"));

颠覆我们的思维的时刻来临了。单利设计模式,在一般情况下只创建一个对象。但是通过反射我们可以调用类中被private修饰的构造函数,使其创建多个实例。如下代码所示:

class Single {

private static Single instance;

private Single(){}

public static Single getInstance(){

if(instance==null)

instance = new Single();

return instance;

}

}

public class Test {

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

//获取被private修饰要使用getDeclaredConstructor()

Constructor con = Single.class.getDeclaredConstructor(null);

//设置访问的权限

con.setAccessible(true);

System.out.println(con.newInstance(null));

System.out.println(con.newInstance(null));

System.out.println(con.newInstance(null));

}

}

成员变量的反射应用

反射可以获取类的所有Field,Field可以被任何修饰符修饰。举例说明:

public class Point {

public int x ;

private int y;

public int getX() {

return x;

}

public void setX(int x) {

this.x = x;

}

public int getY() {

return y;

}

public void setY(int y) {

this.y = y;

}

Point(){}

public Point(int x, int y) {

super();

this.x = x;

this.y = y;

}

}

public class Test {

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

Point p = new Point(4,2);

Field  fieldX = p.getClass().getField("x");

System.out.println("p原始的x值 = "+fieldX.get(p));

fieldX.set(p, 5);

System.out.println("p修改后的x值 = "+p.getX());

Field  fieldY = p.getClass().getDeclaredField("y");

fieldY.setAccessible(true);

System.out.println("p原始的y值 = "+fieldY.get(p));

fieldY.set(p, 6);

System.out.println("p原始的y值 = "+p.getY());

}

}

高级应用:

要求定一个Reflect,定义Stringintchar成员变量若干个,把String类型的字母a替换成bint类型全部替换成0char类型替换成@

class Refect{

public String str1 = "aaaaaa";

public String str2 = "ababab";

public int  a = 345;

public int b = 246;

public char c = 'A';

public char d = 'B';

public String getStr1() {

return str1;

}

public void setStr1(String str1) {

this.str1 = str1;

}

@Override

public String toString() {

return "Refect [a=" + a + ", b=" + b + ", c=" + c + ", d=" + d", str1=" + str1 + ", str2=" + str2 + "]";

}

}

public class Test {

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

Refect r = new Refect();

r.toString();

System.out.println(r.getStr1());

change(r);

System.out.println(r.getStr1());

r.toString();

}

private static void change(Object o) throws Exception {

// TODO Auto-generated method stub

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

for(Field tmp:fields){

if(tmp.getType()==int.class){

tmp.set(o, 0);

}else if(tmp.getType()==String.class){

String str = (String) tmp.get(o);

System.out.println(str);

tmp.set(o, str.replace('a''b'));

}else if(tmp.getType()==char.class){

tmp.set(o, '@');

}

}

}

}

运行结果:

aaaaaa

aaaaaa

ababab

bbbbbb

成员方法的反射应用:

public class Test {

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

String str =  "abc";

//获取charAt方法 

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

//执行charAt方法

System.out.println(methodCharAt.invoke(str, 0));

//获取hashCode方法

Method methodHashCode = String.class.getMethod("hashCode"null);

//执行hansCode方法

System.out.println(methodHashCode.invoke(str, null));

System.out.println(str.hashCode());

}

}

如果调用类的静态方法,invoke的第一参数为null

接受数组类型的举例:

public class Test {

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

Method methodMain = thod.class.getMethod("main", String[].class);

String[] a = {"itcast","itheima","lsh","Yes"};

methodMain.invoke(new thod(),(Object)a);

methodMain.invoke(new thod(), new Object[]{ new String[]{"itcast","itheima","lsh","Yes"}});

}

}

class thod{

public void main(String[] args){

for(String s:args){

System.out.println(s);

}

}

}

数组与Object的关系: 

基本数据类型的一位数组只能转换成一个Object对象,不能转换成Object数组对象。

能够转换成Object数组的对象必须是泛型对象的数组,就是引用类型的数组才能转换成Object数组对象。

Java 1.5之前不支持泛型,所有的对象直接强制转换成Object对象,java1.5之后支持泛型,可以把泛型数组转换成Object数组,为了兼容java1.5之前版本,导致基本数据类型的数组不能转换成Object 数组。举例说明:

public class Test {

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

int[] a = { 1, 3, 3, 3 };

char[] b = { '2''a''b' };

int[][] c = new int[3][4];

String[] str = { "a""b""c" };

//正确 int数组可以强制转换成Object对象

Object A = a;

// 下面一句话错误 int数组不能转换成Object数组

// Object[] A1 = a;

// 下面这句话错误 和上面的错误一致

// Object[] B = b;

//这句话正确 二维数组 可以理解成一个一维数组,每个数组元素是一个一维数组 

Object[] C = c;

//String 不是基本数据类型

Object[] Str = str;

}

}

数组的反射应用:

数组的应用主要是改,查操作。用isArray()判断是否是数组类型的量。

用反射来操作数组要使用Array,数组工具。

public class Test {

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

int[] a = { 1, 3, 3, 3 };

char[] b = { '2''a''b' };

String[] str = { "a""b""c" };

print(a);

print(b);

print(str);

}

public static void print(Object obj){

//isArray() 判断是否为数组类型

if(obj.getClass().isArray()){

//Array.getLength(obj) 获取数组的长度

for(int i=0;i<Array.getLength(obj);i++){

//Array.get(obj,i) 获取索引为i的元素值

System.out.println(Array.get(obj, i));

//可以更改数组元素的值必须保证value的类型和数组元素的类型一致

//Array.set(obj, i, value);

}

}else{

System.out.println(obj);

}

}

}

如何获取数组类型中元素的类型,可以通过下面的方法来获取Array.get(obj,i).getClass().getName()

------- android培训java培训、期待与您交流! ----------
原创粉丝点击