二十一、反射

一、反射机制

1.反射机制的作用

通过java语言中的反射机制可以操作字节码文化。

2.反射机制的相关类在哪个包下?

java.lang.reflect.*;

3.反射机制相关的重要的类有哪些?

java.lang.Class:代表整个字节码,代表一个类型
java.lang.reflect.Method:代表字节码中的方法字节码,代表类中的方法
java.lang.reflect.Constructor:代码字节码中的构造方法字节码,代表类中的构造方法
java.lang.reflect.Field:代码字节码中的属性字节码,代表类中的成员变量(静态变量)

4.获取到一个类的字节码的三种方式:

第一种:通过Class这个类中的静态方法forName;

Class c = Class.froName("类名");

Class.froName():
(1)静态方法
(2)方法的参数是一个字符串
(3)字符串需要的是一个完整类名
(4)完整类名必须带有包名,java.lang包也不能省略

第二种:java中任何一个对象都有一个方法:getClass()

Class c = 对象.getClass();

第三种:java中任何一种类型,包括基本数据类型,它都有.class属性

Class c = 任何类型.class;
5.使用反射机制获取实例化对象
//不使用反射机制,创建对象
User user = new User();
System.out.println(user);

//使用反射机制创建对象

//通过反射机制,获取Class,通过Class来实例化对象
Class c = Class.forName("com.heimao.java.bean.User");//c表示user类型
//newInstance() 这个方法会调用User这个类的无参数构造方法,完成对象的创建。
//重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的
Object obj = c.newInstance();
System.out.println(obj);

使用反射机制获取实例化对象的优点:可以在不改变java源代码的基础上,可以做到不同对象的实例化,非常灵活(符合OCP开闭原则)

6.Class.forName()

如果你只希望一个类的静态代码块执行,其它代码一律不执行,可以使用:
Class.forName(“完整类名”);
这个方法的执行会导致类加载,类加载时,静态代码块执行。

7.获取类路径下文件的绝对路径

使用的前提是必须在类路径下

/*
Thread.currentThread()  当前线程对象
getContextClassLoader()  是线程对象的方法,可以获取到当前线程的类加载器对象
getResource() 这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源
*/
String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
8.以流的形式返回
//获取一个文件的绝对路径,把绝对路径传进去以流的形式返回
/*String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
FileReader reader = newFileReader(path); */

可以省略为

//直接以流的形式返回。
InputStream reader = Thread.currentThread().getContextClassLoader().getResource("");
9.资源绑定器

java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容。
使用这种方式,属性配置文件xxx.properties必须放在类路径下

//资源绑定器,只能绑定xxx.properties文件,并且这个文件必须在类路径下,文件扩展名也必须是properties
//并且在写路径的时候,路径后面的扩展名不能写
ResourceBundle bundle = ResourceBundle.getBundle("classinfo");
String className = bundle.getString("key");
System.out.println(className);
10.通过反射机制访问对象属性

给属性赋值set;
获取属性的值get

(1)先创建一个学生类,里面有四个属性
先不使用反射机制,访问一个对象的属性

Student s = new Student();
//给属性赋值
s.no = 110;
//读属性值
System.out.println(s.no);

使用反射机制,访问一个对象的属性

Class studentClass = Class.froName("com.heimao.java.bean.Student");
Object obj =  studentClass.newInstance(); //此时obj就是Student对象(底层调用无参构造方法)

//获取属性(根据属性的名称来获取Field)
Field noFiled = studentClass.getDeclaredField("no");

//给obj对象的属性赋值
/*
需要三要素:
要素1:obj对象
要素2:属性
要素:220
反射机制虽然会让代码变复杂,但是会更灵活
*/
noFiled.set(obj,220);

//读取属性的值
System.out.println(noFiled.get(obj));

注意:反射机制有个缺点是如果想要获取私有属性,给私有属性赋值必须要执行noFiled.setAccessible(true); 打破封装

11.通过反射机制调用一个对象的方法

先创建一个UserService类
不使用反射机制,怎么调用方法

UserService userService = new UserService();
boolean loginSuccess = userService.login("admin", "123");
System.out.println(loginSuccess ? "登录成功" : "登录失败");

使用反射机制,调用方法

Class userServiceClass = Class.forName("com.heimao.java.service.UserService");
//创建对象
Object obj = userServiceClass.newInstance();
//获取Method
Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class,String.class);
//反射机制最重要的一个方法
Object retValue = loginMethod.invoke(obj,"admin", "123");
12.使用反射调用构造方法

先创建一个VIP类,里面有编号和姓名两个属性。
不使用反射机制创建对象

Vip v1 = new Vip();
Vip v2 = new Vip(111,"zhangsna")

使用反射机制创建对象

Class c = Class.forName("com.heimao.java.bean.Vip");
//调用无参构造方法
Object obj = c.newInstance();

//调用有参构造方法
//先获取这个有参数构造方法
Constructor con = c.getDeclaredConstructor(int.class, String.class);
//然后调用构造方法new对象
Object newobj = con.newInstance(110,"zhangsan");
System.out.println(newObj);

//获取无参数构造方法
Constructor con2 = c.getDeclaredConstructor();
Object newObj2 = con2.newInstance();
System.out.println(newObj2);
13.怎么获取一个类的父类和实现的接口?

获取父类:使用.getSuperclass()方法
获取接口:使用.getInterfaces()方法

扩展

1.类加载器

(1)什么是类加载器?
专门负责加载器的命令/工具
ClassLoader

(2)JDK中自带了3个类加载器
启动类加载器
扩展类加载器
应用类加载器

(3)类加载器执行过程
首先通过“启动类加载器”加载
(注意:启动类加载器专门加载jre\lib\rt.jar,rt.jar中都是JDK最核心的类库)

如果通过“启动类加载器”加载不到的时候
才会通过“扩展类加载器”加载。
(注意:扩展类加载器专门加载jre\lib\ext*.jar)

如果通过“扩展类加载器”加载不到的时候
才会通过“应用类加载器”加载
(注意:应用类加载器专门加载classpath中的jar包(class文件))

(4)java中为了保证类加载的安全,使用了双亲委派机制。
优先从启动类加载器中加载,这个称为“父”,“父”无法加载到,再从扩展类加载器中加载,这个称为“母”。双亲委派,如果都加载不到,才会考虑从应用类加载器中加载。直到加载到为止。

2.通过反射机制,反编译一个类的属性Field

先创建一个学生类,里面有四个属性

//*
* 通过反射机制,反编译一个类的属性Field
*/
//创建这个是为了拼接字符串
StringBuilder s = new StringBuilder();
ClassstudentClass = Class.froName("com.heimao.java.bean.Student");
//s.append("public class Student  {");
//s.append("public class "+ studentClass.getSimpleName() + " {"); //动态获取类名
s.append(Modifier.toString(studentClass.getModifiers()) class "+ studentClass.getSimpleName() + " {");//动态获取修饰符,并且转换为字符串

Field[] fields = stduentClass.getDeclaredFields();
for(Field field : fields){
	s.append("\t");
	s.append(Modifier.toString(field.getModifiers())); //输出四个属性的修饰符
	s.append(" ");
	s.append(field.getType().getSimpleName());
	s.append(" ");
	s.append(field.getName());
	s.append(";\n");	
}

s.append("}");
3.可变长参数

int… args
语法:类型… (注意:一定是3个点)

(1)可变长度参数要求的参数个数是:0~N个。
(2)可变长度参数在形式参数中只能出现一个,并且必须在最后一个位置上
(3)可变长度参数可以当做一个数组来看待,也可以传一个数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值