黑马程序员————JAVA之反射

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

 

一、反射的基础-Class类:
java程序中使用到的各个java类,他们是属于同一类事物,所以java就用Class类表示这类事物
Class类无构造方法(或被私有)
比如:
Person p1=new Person();//当源程序使用到Person类的时候,先要从硬盘上将Person类的二进制代码(字节码)加载到内存中来,//然后才可以用这些字节码复制出各个对象
Class c=Date.class//字节码1;
 
1、获取字节码的3种方式
p1.getClass();//类的实例对象
Class c=Person.class;//类名.class
Class.forName("java.lang.String")//Class类的静态方法:
得到String的字节码:
内存中有String的字节码,直接返回
内存中无String的字节码,使用类加载器加载,然后返回
 
2、八种基本数据类型和void也有对应的Class实例对象
九个预定义的实例对象
boolean  isPrimitive() 
判定指定的 Class 对象是否表示一个基本类型。 
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.isArray());//true
总之:只要是在源程序中出现的类型,都有各自的class实例对象,例如:int[],void
3、Class类中的常见方法:
 
类中常见方法
1)获取:有Declared的获取是获取类里面不可见或不可见的成员!!!
**** static Class<?> forName(String className) :
返回与带有给定字符串名的类或接口相关联的 Class 对象。
 
* Constructor<?>[] getConstructors() :
获取某一个类中的所有可见的构造方法,返回一个包含某些 Constructor 对象的数组。
 Constructor<T> getConstructor(Class<?>... parameterTypes) :获取类中符合某一参数类型的构造方法
 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。 
 
* Field[]  getFields() 
 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
 Field  getField(String name) :获取类里面可见的成员变量
         返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。 
 注:获取的是类上名字为name的变量,不是类实例上的变量
*** Field  getDeclaredField(String name) :获取成员
* Method getMethod(String name, Class<?>... parameterTypes) :
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。 //name表示获取的方法名字,后面的参数组为原方法的参数类型.class
 Method[] getMethods() :
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口
包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。 
String getName() :
          以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。 
Package getPackage() :获取此类的包。 
 
 
2)判断
*** T newInstance() :创建此 Class 对象所表示的类的一个新实例。  
//提供便利使用,内部封装了Constructor,内部先得到默认的构造方法,然后使用他创建实例对象 
* boolean isPrimitive() :基本类型判断(int、char、float等)
          判定指定的 Class 对象是否表示一个基本类型。
 boolean isInterface() :判定指定的 Class 对象是否表示一个接口类型。  
* boolean isArray() :判定此 Class 对象是否表示一个数组类。 
 boolean isInstance(Object obj) :判定指定的 Object 是否与此 Class 所表示的对象赋值兼容。
 boolean isEnum() :当且仅当该类声明为源代码中的枚举时返回 true。  
<U> Class<? extends U> asSubclass(Class<U> clazz) :
          强制转换该 Class 对象,以表示指定的 class 对象所表示的类的一个子类。 
 
 
二、反射:就是把  java类的各个成分 映射成  相应的java类!
 
比较占用缓存,反射会导致程序性能下降
那么为什么要用反射:反射是为了框架服务的,在程序编写过程中,有的方法或者需要运行的程序(类)我不知道是什么样的,但我需要用到这个类或方法,就使用反射
比如:给毛胚房(框架)安装一个门(未知的样式,未知的锁等),怎么把锁装上去,门才是这个对象,装锁的方法存储在门里!,但是我建筑毛胚房的时候是不知道未来要装什么门!,所以就需要用反射,将门的名称传入,获取门的安装锁的方法,实现锁的安装!
java类中各种成分信息包装成对应的类:例如
Field类:反射类中的成员变量java.lang.reflect
Method:方法java.lang.reflect
Constructor<T>:构造方法java.lang.reflect
Package:包
Modifier:提供了 static 方法和常量,对类和成员访问修饰符进行解码。java.lang.reflect
1、Constructor类:代表某个类中的一个构造方法
常用方法
 String getName() :以字符串形式返回此构造方法的名称。 
**** T newInstance(Object... initargs):initargs是该T类构造方法的参数;和原构造方法的参数需一致! 否则异常
  使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。 
/*
练习:获取一个String类的构造方法,并使用他创建对象
*/
public staitc void main(String[] args)
{
Constructor<String> c=String.class.getConstructor(StringBuffer.class);
//获取String类中参数类型为StringBuffer的构造方法
String s=c.newInstance(new StringBuffer("abc"));//使用获取到的构造方法构造参数类型为StringBuffer的String实例对象
System.out.println(s);
}
 
 
2、Field类:类中的成员变量类!
常见方法:
获取:
 Object get(Object obj) :返回指定对象上此 Field 表示的字段的值。
 boolean getBoolean(Object obj) 
          获取一个静态或实例 boolean 字段的值。 
 · byte getByte(Object obj) 
          获取一个静态或实例 byte 字段的值。 
  char getChar(Object obj) 
          获取 char 类型或另一个通过扩展转换可以转换为 char 类型的基本类型的静态或实例字段的值。 
 int getInt(Object obj) 
          获取 int 类型或另一个通过扩展转换可以转换为 int 类型的基本类型的静态或实例字段的值。 
 String getName() :返回此 Field 对象表示的字段的名称。
 ** Class getType() 
          返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。

 修改:
******setAccessible(true):暴力反射,一般用于获取到的字段是私有的时候,将字段设置可见
(此方法属于AccessibleObject类)
 ** void set(Object obj, Object value) 
          将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 
  void setBoolean(Object obj, boolean z) 
          将字段的值设置为指定对象上的一个 boolean 值。 
 void setChar(Object obj, char c) 
         将字段的值设置为指定对象上的一个 char 值。 
 void setInt(Object obj, int i) 
          将字段的值设置为指定对象上的一个 int 值。 
 
/*

练习:

获取ReflectPoint类中的两个字段(private,public),并打印

*/

public class ReflectPoint {

private int x;

public int y;



public ReflectPoint(int x, int y) {

super();

this.x = x;

this.y = y;

}

public static void main(String[] args) {

ReflectPoint pt1=new ReflectPoint(3,5);

Field fy=pt1.getClass().getField("y");//这里的fy取出的是ReflectPoint这个类上的可见变量y,不是其对象pt1上的变量y

System.out.println(fy.get(pt1));//获取pt1中fy代表的变量的值




Field fx=pt1.getClass().getDeclaredField("x");//获取不可见的变量

fx.setAccessible(true);//若不将私有的x设置可见,则抛出异常java.lang.NoSuchFieldException

//一般在取出的时候我们不知道是否可见,所以常用这个方法

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

}




}

*/

/**

 *将任意一个对象中所有String类型的成员变量所对应的的字符串内同中的“b”修改成“a”

 *获取所有成员变量,getDeclaredField();

 *for循环,设置可见,修改

 */

public class ReflectString {

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

{

ReflectPoint pt1=new ReflectPoint();//此类在另外的文件中

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

for (Field fp:fields) {

//if(fp.getType().equals(String.class))都是字节码所以直接用==

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

String str=(String)fp.get(pt1);

str=str.replaceAll("b", "a");

fp.set(pt1,str);

}

}

System.out.println(pt1);

}

}

3、Method类:类中方法的封装类
 Object invoke(Object obj, Object... args):对带有指定参数args的指定对象obj调用由此 Method 对象表示的底层方法。 
obj表示要调用这个方法的对象,args为此对象方法的参数实例(即obj.Method(args);)
当obj参数为null时,也就是代表这个方法是静态方法,可以不使用对象即可调用,当然加上对象的参数也没问题

3.1反射一般的成员函数
/*
获取String类中的charAt方法,并调用他获取字符串的某一索引字符
String s="abc";
Method m=String.class.getMethod("charAt", int.class);
System.out.println(m.invoke(s, 1));//自动装箱
System.out.println(m.invoke(s, new Object[]{2}));//1.4以前的写法!
*/
 
 
3.2反射接收数组的成员函数
/*
调用另外一个类中的主函数,但并不知道它的名字(也就是被调用的类的名字需通过本类的主函数参数给传递进去)
*/
class Demo{
public static void main(String[] args)
String startName=args[0];
String[] s=new String[]{"111","222","333"};
Method m=Class.forName(startName).getMethod("main", String[].class);
//m.invoke(null, s);//这会报异常,因为mian函数在接收参数的时候:接收到数组会将数组进行拆包,也就是将数组中的元素都一个个拆分出来传递进去
m.invoke(null, new Object[]{s});//增加一层包装
m.invoke(null, (Object)s);//将s向上提升为一个Object参数,这样虚拟机就会认为这是一个变量,就不会拆了!
}
}
class TestArguments{
public static void main(String[] args)
{
for(String arg:args)
System.out.println(arg);
}
}
2.4、数组的反射:Array类java.lang.reflect
常用方法
static Object get(Object array, int index): 返回指定数组对象中索引组件的值。
对数组的反射:当数组的类型以及维度都一样时,反射的类型才相同
int[] a1=new int[]{1,2,3};

int[] a2=new int[4];

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

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

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

//System.out.println(a1.getClass() == a3.getClass());高级编译器不让通过了,也就是这两句话返回的是false!

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

System.out.println(a1.getClass().getSuperclass().getName());//打印父类的名字:Object

Object ob1 =a1;//数组是一个类,是Object的子类,所以这是可以的

Object[] ob2 =a3;//同上

//Object[] ob3 =a1;//错误的表达:Object类型的数组里装 int !基本数据类型和Object类是不同的

Object[] ob4 =a4;

static <T> List<T>  asList(T... a) : 返回一个受指定数组支持的固定大小的列表。 

System.out.println(Arrays.asList(a1));//[[I@37f2ae62],

因为asList这个方法接收的是一个属于Object范畴下的一个可变参数,就如同Object[] ob3 =a1一样(可以推想,1.4以前这里应该编译不过了)
正因为是可变参数,所以a1传进去是 Object ob1 =a1,打印的就是a1的地址值了
System.out.println(Arrays.asList(a4));//[a, b, c]

 

 

黑马程序员的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、付费专栏及课程。

余额充值