黑马程序员——反射

------- android培训java培训、期待与您交流! ----------

反射,是1.2的新特性

Class类代表Java类,它的各个实例对象对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。

一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型就是Class。Java中的所有类,同属于同一个Class类。

Class类型的变量代表内存中的一段字节码,如:

内存中加载了多少个字节码,就有多少个Class对象/实例;

一旦用到某个类,该类的class文件就会被加载到内存,内存也就有了该字节码。

一道面试题:Class.forName()的作用:返回字节码,返回的方式有两种:一、该类字节码已经被加载到JVM里面了,直接返回;二、javaVM中还没有这个字节码,用类加载器去加载,把加载进来的类缓存在虚拟机里了,以后再要得到这份字节码就不需要加载了。

 

得到字节码的方式有三种:

1.       类名.class  如:System.class

2.       对象.getClass()如:new Date().getClass() 该对象应该是除了Class之外的其他类的对象。

3.       Class.getName(“类的完整名字(含包名)”)例如:Class.getName(“java.util.Date”)

4.       以上的第三种最常用,因为可以将参数中的类名定义为一个变量,等待文件传递具体值。

九个预定义的Class实例对象:八个基本类型和void,他们对应的字节码。如int.class ==Integer.TYPE;

本类型的class(字节码)文件,和对应的包装类型的TYPE字段是相等的。 isArray()判断一个Class对象是不是数组类。

 

反射就是把Java类中的各种成分映射成相应的java类。

一个Java类用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,如某个类中的所有方法都可以用Method这个类来表示,而每一个方法就是Method类的一个实例对象。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。

一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象,就可以实现好多Java类不能实现的功能。

 

 

 

构造方法的反射

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

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

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

得到某一个构造方法:

例子:     Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

    //获得方法时要用到类型

创建实例对象:

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

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

    //调用获得的方法时要用到上面相同类型的实例对象

Class.newInstance()方法:

例子:String obj =(String)Class.forName("java.lang.String").newInstance();

该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。

该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。(比较消耗资源,只有当获取该类构造方法比较麻烦的时候,才用此方法)

当需要用默认的空构造方法创建某个java类的实例时,就可以用此方法,省去了中间的先获得构造方法在创建对象的繁琐流程。

 

 

成员变量的反射

Field类代表某个类中的一个成员变量

得到的Field对象是对应到类上面的成员变量,而不是对应到对象上的成员变量。字段fieldX 代表的是x的定义,而不是具体的x变量。

示例代码:

public classReflectPoint {

    private int x;

    public int y;

   

    public ReflectPoint(int x, int y) {

        super();

        this.x = x;

        this.y = y;

    }

}

    ReflectPoint point =new ReflectPoint(1,7);

    Field y =Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");

    System.out.println(y.get(point));

    //Field x =Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");

    Field x =Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");

    x.setAccessible(true);

    System.out.println(x.get(point));

 

将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。

class Xxx

{

    Stringname="abc";

    Stringemail="abd";

    int x = 5;

}

func(Object obj)

{

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

for(Field field : fields)

{

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

    {

        field.setAccesible(true);

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

        field.set(obj,original.replaceAll("b","a");

    }

}

}

 

用构造函数创建一个类的对象,想要获取一个类的某个成员变量(字段)的在某个具体对象中的值。

步骤:

1.       Field f =类名.class.getField(“参数名”); 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。getField(“参数名”),但是看不见私有参数,该方法只能传入非私有的参数。

2.       f.get(具体对象); 返回指定对象上此 Field 表示的字段的值。但看不到私有字段。

 

 

1.       Field f =类名.class.getDeclaredField(“参数名”);只要是类中声明的变量(字段),不论是否私有,都可以传入。这就是暴力反射。

2.       f.setAccessible(true);将字段设为可见的。

3.       f.get(具体对象); 如果字段是私有的,此处是无法获取的;只有在2中将字段设为可见的才可以。

 

成员变量反射的其他方法:

F是一个Field对象,则

f.getType(); 获取字段的类型。返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。

f.set(对象,该对象的字段新设值);

Fields[] fs =类名.class.getFields(); 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。

 

在此建议:分别总结Class/Field的常用方法。

 

成员方法的反射

Method类代表某个类中的一个成员方法

常用方法:

getMethod(方法名, 参数列表.class)
          返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

invoke(对象,参数列表)执行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对象对应的是一个静态方法!

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

Jdk1.5:publicObject invoke(Object obj,Object... args)

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

 

对接收数组参数的成员方法进行反射

 

注意:用反射调用main(String[] args)方法的时候,考虑到1.5对1.4版本的兼容,会按1.4的语法解析参数,将 .invoke(null,String类型数组) 中的数组中的每个元素解析成参数,解决办法两种:

a、给数组再打包一层数组;

b、用(Object)强制类型转换,告诉编译器这是一个对象,不要当做多个对象形成的数组。

如:

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

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

 

数组与Object的关系及其反射类型

所有元素类型,维数都想同的数组都对应一个类。

Arrays.asList();注意该方法,对int[] (int 类型一位数组的不同)。

1.       该方法,可以将数组变成字符串以方便直接将数组打印出来

2.       但对于一位整型数组int[],结果却是个特例,会打印出hashcode;

3.       原因,1.4版本的该方法传递的参数是Object[] ,也就是要求数组中的元素都是一个对象(Object或其子类);而int[]中的元素都是整型数据,不符合参数标准,所有智能按照1.5版本方法来解析。

4.       1.5方法中,传递的参数是元素列表,所以就把int[]当做一个元素来处理了,当然打印出来的是hashcode.

 

数组的反射应用

可以赢用数组的反射解决以下问题:创建一打印方法,如果要打印的值是数组,就打印出每个元素,如果不是数组就直接打印。

我们只能获得一个数组中某个元素的具体类型,无法获得数组中说有元素的类型。方法:

a[0].getClass().getName();

Array类的应用:方法……主要记住下面两个:

static Object  get(数组对象, 下标)
          返回指定数组对象中索引组件的值。

static int getLength(数组对象)
          以 int 形式返回指定数组对象的长度

反射的作用:实现框架功能

 

采用配置文件加反射的方式创建ArrayList和HashSet的实例:

public static void main(String[] args) throwsException{

Properties props = new Properties();

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

props.load(ips);

Ips.close();

 

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

Class clazz = Class.forName(className);

 

Collection collection = (Collection)clazz.newInstance();

ReflectPoint pt1 = new ReflectPoint(3,3);

ReflectPoint pt2 = new ReflectPoint(5,5);

ReflectPoint pt3 = new ReflectPoint(3,3);

collection.add(pt1);

collection.add(pt2);

collection.add(pt3);

collection.add(pt1);

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

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
黑马程序员的tb_brand是指在JavaWeb基础教程中创建的一个表。这个表是用来存储品牌信息的,具体的表结构和数据类型需要和JavaBean类中的成员变量保持一致。\[1\]在这个教程中,使用了Maven来构建项目,并且使用了MyBatis作为持久层框架,通过配置pom.xml文件来引入相关依赖。\[2\] Maven是一个用于管理和构建Java项目的工具,它提供了一套标准化的项目结构、构建流程和依赖管理机制。\[3\] #### 引用[.reference_title] - *1* [【JAVAWEB开发】黑马程序员java web案例资料(含Element的删除与修改)](https://blog.csdn.net/aasd23/article/details/126940147)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [黑马程序员-MyBatis 框架-最全入门笔记、阿伟看了都得说真大、真细、真全!!!](https://blog.csdn.net/qq_57383364/article/details/128103058)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [JavaWeb——黑马程序员课程笔记](https://blog.csdn.net/King_ZACC/article/details/128573804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值