一、什么是反射?
请结合注解学习
1.定义
将类的各个组成部分封装为其他对象(Field,Constructor,Method),就是反射机制
2. 比如将class文件中的成员变量封装为第二阶段Class类中的Field类
二、反射有什么用?
- 运行的时候操作这些对象,
比如:你使用idea时候的class. 然后自动弹出的可用的提示方法
- 降低程序的耦合性。
三、如何获取Class对象的3种方式,
1. 三种方式
-
Class.forName(“全类名”) : 阶段1可以使用,将class文件,加载进内存并返回Class对象
多用于配置文件,读取文件,加载类 -
Student.class : 阶段2 可用,类的的属性class **
多用于传参** -
student.getClass() : 阶段3可用,对象实例的方法
多用于对象获取字节码文件
2. 代码示例
package Java学习.Java高级.注解和反射.反射.获取Class类的方法;
/**
* 1. Class.forName("全类名") : 阶段1可以使用,**将class文件,加载进内存并返回Class对象**
* 多用于**配置文件,读取文件,加载类**
*
*
* 2. Student.class : 阶段2 可用,**类的的属性class **
* 多用于**传参**
*
* 3. student.getClass() : 阶段3可用,**对象实例的方法**
* 多用于**对象**获取字节码文件
*/
public class Demo01黑马 {
public static void main(String[] args) throws ClassNotFoundException {
//1.
System.out.println("----1. Class.forName(\"全类名\")------");
System.out.println(Class.forName("Java学习.Java高级.注解和反射.反射.获取Class类的方法.Student01"));
//2.
System.out.println("--------2. Student.class---------");
System.out.println(Student01.class);
//3.
System.out.println("-----3. student.getClass()-----");
System.out.println(new Student01().getClass());
System.out.println("-------123是否相等----------");
System.out.println(new Student01().getClass().hashCode());
System.out.println(Student01.class.hashCode());
System.out.println(Class.forName("Java学习.Java高级.注解和反射.反射.获取Class类的方法.Student01").hashCode());
System.out.println("HashCode的值相等,地址值相等,");
System.out.println("结论: 同一个class字节码文件的在程序的运行中,只会被加载一次" +
"\n无论通过哪一种方式获取的class对象都是同一个.");
}
}
class Student01{
}
Run:
----1. Class.forName(“全类名”)------
class Java学习.Java高级.注解和反射.反射.获取Class类的方法.Student01
--------2. Student.class---------
class Java学习.Java高级.注解和反射.反射.获取Class类的方法.Student01
-----3. student.getClass()-----
class Java学习.Java高级.注解和反射.反射.获取Class类的方法.Student01
-------123是否相等----------
1915910607
1915910607
1915910607
HashCode的值相等,地址值相等,
结论: 同一个class字节码文件的在程序的运行中,只会被加载一次
无论通过哪一种方式获取的class对象都是同一个.
Process finished with exit code 0
四、获取的反射对象有什么用?通过Class 获取该类的Field,Constructor和Method对象,并且可以使用对应部分的方法(例如fiead.get())
1. Field
(1)知识点
* 一、获取成员变量Field
* 1. getField("publicField") (public权限)1个字段publicField
* 2. getFields() (public权限)全部字段们
*
* 3. getDeclaredField("privateField") (所有权限)的1个字段privateField
* 4. getDeclaredFields() (所有权限)的字段们
* 二、使用field
* 1.get(): .get(person02)
* 2.set(): .set(person02,"设置的值")
* 3.暴力反射:获取非public字段后需要暴力反射才能使用privateField的方法(比如get())
* privateField1.setAccessible(true);
(2) 代码
package Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.获取字段Field021;
import Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02;
import java.lang.reflect.Field;
/**
* 一、获取成员变量Field
* 1. getField("publicField") (public权限)1个字段publicField
* 2. getFields() (public权限)全部字段们
* <p>
* 3. getDeclaredField("privateField") (所有权限)的1个字段privateField
* 4. getDeclaredFields() (所有权限)的字段们
* 二、使用field
* 1.get(): .get(person02)
* 2.set(): .set(person02,"设置的值")
* 3.暴力反射:获取非public字段后需要暴力反射才能使用privateField的方法(比如get())
* privateField1.setAccessible(true);
* <p>
* --------------------------------------------------------------------------
* 一、获取构造方法Constructor
* 1. getConstructor(String.class) (public权限)1个String参数的Constructor
* 2.3.4.同理
* 二、使用constructor
* 1.newInstance(): 新建Person的实例 ,newInstance(String "name",int age)
* <p>
* -----------------------------------------------
* 一、获取成员方法Method
* 1. getMethod("方法名eat",String.class) public权限的字段
* String.class方法的参数的类型String
* 2.3.4同上
* 二、Method的使用
* 1.invoke(): 调用方法 invoke("蛇皮怪"),蛇皮怪就是方法的参数。
* <p>
* -----------------------------------------------
* 一、获取类名getName
* 1. getName()
*/
public class Demo02 {
public static void main(String[] args) throws Exception {
Person02 person02 = new Person02();
Class<? extends Person02> class1 = person02.getClass();
/**
* * 一、获取成员变量Field
* * 1. getField(String name) public权限的字段
* * 2. getFields() 全部public权限字段们
* *
* * 3. getDeclaredField(String name) 获取所有权限的(public --private)的字段
* * 4. getDeclaredFields() 获取所有权限的(public --private)的字段们
* 拓展
* 5.获取class1对象下字段privateField的值 privateField.get(class1)
* 6.设置值: privateField.set(class1,"设置的值")
* 7.暴力反射获取
* privateField1.setAccessible(true);
*/
Field publicField = class1.getField("publicField");
System.out.println("-----------一、.---------");
System.out.println("1.getField(\"publicField\");-------");
System.out.println(publicField);
Object[] fields;
fields = class1.getFields();
System.out.println("2.getFields()-------");
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i]);
}
System.out.println("结论:只能获取public类型的field");
System.out.println("4.getDeclaredFields()--------");
fields = class1.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i]);
}
/**
* * 拓展
* * 5.获取class1对象下字段privateField的值 privateField.get(class1)
* * 6.设置值: privateField.set(class1,"设置的值")
* * 7.暴力反射获取
* privateField1.setAccessible(true);
*/
System.out.println("5.获取class1对象下字段privateField的值 privateField.get(person02)-------\n" +
"6.设置值: privateField.set(person02,\"设置的值\")-------");
Field privateField = class1.getField("publicField");
System.out.println("privateField.get(person02): " + privateField.get(person02));
privateField.set(person02, "set的值");
System.out.println("privateField.set(person02,\"set的值\"): " + privateField.get(person02));
System.out.println("暴力反射privateField1.setAccessible(true);----------");
Field privateField1 = class1.getDeclaredField("privateField");
//暴力反射前访问私有报错java.lang.IllegalAccessException
//System.out.println(privateField1.get(person02));
privateField1.setAccessible(true);
System.out.println("暴力反射就能获取私有Field: " + privateField1.get(person02));
}
}
Run:
-----------一、.---------
1.getField(“publicField”);-------
public java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.publicField
2.getFields()-------
public java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.publicField
结论:只能获取public类型的field
4.getDeclaredFields()--------
private java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.privateField
java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.defaltField
protected java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.protectField
public java.lang.String Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02.publicField
5.获取class1对象下字段privateField的值 privateField.get(person02)-------
6.设置值: privateField.set(person02,“设置的值”)-------
privateField.get(person02): null
privateField.set(person02,“set的值”): set的值
暴力反射privateField1.setAccessible(true);----------
暴力反射就能获取私有Field: null
Process finished with exit code 0
2, Constructor
(1)知识点
* 一、获取构造方法Constructor
* 1. getConstructor(String.class) (public权限)1个String参数的Constructor
* 2.3.4.同理
* 二、使用constructor
* 1.newInstance(): 新建Person的实例 ,newInstance(String "name",int age)
(2)code
package Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.获取构造方法Method022;
import Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02;
import java.lang.reflect.Constructor;
public class Demo022 {
public static void main(String[] args) throws Exception {
/**
* 一、获取构造方法Constructor
* 1. getConstructor(String.class) (public权限)1个String参数的Constructor
* 2.3.4.同理
* 二、使用constructor
* 1.newInstance(): 新建Person的实例 ,newInstance(String "name",int age)
*/
Person02 person02 = new Person02();
Class<? extends Person02> aClass = person02.getClass();
Constructor<? extends Person02> constructor = aClass.getConstructor();//获取无参构造
Constructor<? extends Person02> constructor1 = aClass.getConstructor(String.class);//获取一个参数的构造
System.out.println("无参构造: " + constructor);
System.out.println("1参构造: " + constructor1);
System.out.println("-------二、获取构造的作用,newInstance()新建person对象实例------------");
Person02 person021 = constructor1.newInstance("参数1");
System.out.println(person021);
}
}
Run:
无参构造: public Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02()
1参构造: public Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02(java.lang.String)
-------二、获取构造的作用,newInstance()新建person对象实例------------
Person02{privateField=‘参数1’, defaltField=‘null’, protectField=‘null’, publicField=‘null’}
Process finished with exit code 0
3.Method
(1)知识点
* 一、获取成员方法Method
* 1. getMethod("方法名eat",String.class) public权限的字段
* String.class方法的参数的类型String
* 2.3.4同上
* 二、Method的使用
* 1.invoke(): 调用方法 invoke("蛇皮怪"),蛇皮怪就是方法的参数。
(2)code
package Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.获取成员方法们Method023;
import Java学习.Java高级.注解和反射.反射.heima.使用Class对象02.Person02;
import java.lang.reflect.Method;
/**
* * 一、获取成员方法Method
* * 1. getMethod("方法名eat",String.class) public权限的字段
* * String.class方法的参数的类型String
* * 2.3.4同上
* * 二、Method的使用
* * 1.invoke(): 调用方法 invoke("蛇皮怪"),蛇皮怪就是方法的参数。
*
* 1.使用class获取Method
* 2.使用Method
* (1)使用method调用方法
* (2)使用method获取方法名称
*/
public class Demo_023 {
public static void main(String[] args) throws Exception {
//1.使用class获取Method
Person02 person02 = new Person02();
Class<? extends Person02> aClass = person02.getClass();
Method eatMethod = aClass.getMethod("eat", String.class);
//2.使用method调用方法invoke()
eatMethod.invoke(person02, "个蛇皮");
System.out.println(eatMethod.getName());
}
}
Run:
eat…个蛇皮
eat
Process finished with exit code 0
五、案例练习.
1. 需求:
- 写一个框架,不能改变类的任何的代码的情况下,创建类的对象,并且执行其中的任意代码
2. 实现原理:
- 配置文件
- 反射
3. 实现步骤
- 需要将创建对象的全类名和需要执行的文件定义在配置文件中
className=Java学习.Java高级.注解和反射.反射.heima.反射项目.Person
methodName=eat
- 在程序中加载读取配置文件
//2.在程序中**加载读取配置文件**----------
//2.1创建Properties对象
Properties properties = new Properties();
//2.2加载load()方法,加载配置文件,储存key value 的值在properties中
//2.2.1 :load() 需要传递参数InputStream
String configuration = "D:\\Program Files\\JetBrains\\test1\\Lab\\src\\Java学习\\Java高级\\注解和" +
"反射\\反射\\heima\\反射项目\\configuration.properties";
FileInputStream fileInputStream = new FileInputStream(configuration);
properties.load(fileInputStream);
//2.3 获取配置文件的数据:
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
- 使用反射技术加载类进内存
Class.forName("全类名")
- 创建Person对象
//4.创建Person对象------
//4.1因为Class类的创建Person对象方法newInstance()已经弃用
//我们先创建获得构造函数类Constructor在创建Person对象
//获得构造函数类Constructor 无参
Constructor<?> constructor = aClass.getConstructor();
//4.2 newInstance()创建Person对象
Object person = constructor.newInstance();
- **5.用aClass获取getMethod对象,然后再使用新建的person对象invoke(person)执行方法 **
//5.用aClass获取getMethod对象,然后再使用新建的person对象invoke(person)执行方法---------------
Method method = aClass.getMethod(methodName);
method.invoke(person);
4. 代码:
1.配置文件 configuration.properties
className=Java学习.Java高级.注解和反射.反射.heima.反射项目.Person
methodName=eat
2.Person 类:Person.java
package Java学习.Java高级.注解和反射.反射.heima.反射项目;
public class Person {
private String privateField;
String defaltField;
protected String protectField;
public String publicField;
public void eat(){
System.out.println("eat....");
}
public void eat(String food){
System.out.println("eat..."+food);
}
public Person() {
this.privateField = privateField;
}
public Person(String privateField) {
this.privateField = privateField;
}
@Override
public String toString() {
return "Person02{" +
"privateField='" + privateField + '\'' +
", defaltField='" + defaltField + '\'' +
", protectField='" + protectField + '\'' +
", publicField='" + publicField + '\'' +
'}';
}
public Person(String privateField, String defaltField, String protectField, String publicField) {
this.privateField = privateField;
this.defaltField = defaltField;
this.protectField = protectField;
this.publicField = publicField;
}
public String getPrivateField() {
return privateField;
}
public void setPrivateField(String privateField) {
this.privateField = privateField;
}
public String getDefaltField() {
return defaltField;
}
public void setDefaltField(String defaltField) {
this.defaltField = defaltField;
}
public String getProtectField() {
return protectField;
}
public void setProtectField(String protectField) {
this.protectField = protectField;
}
public String getPublicField() {
return publicField;
}
public void setPublicField(String publicField) {
this.publicField = publicField;
}
}
Demo_01.java
package Java学习.Java高级.注解和反射.反射.heima.反射项目;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 一、Properties类是Map的子类,性质类
* 1. Properties 对象可以把以properties结尾的文件
* 用load方法读取到内存里面形成一个集合
*
*/
public class Demo_01 {
public static void main(String[] args) throws Exception {
//2.在程序中**加载读取配置文件**----------
//2.1创建Properties对象
Properties properties = new Properties();
//2.2加载load()方法,加载配置文件,储存key value 的值在properties中
//2.2.1 :load() 需要传递参数InputStream
String configuration = "D:\\Program Files\\JetBrains\\test1\\Lab\\src\\Java学习\\Java高级\\注解和" +
"反射\\反射\\heima\\反射项目\\configuration.properties";
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(configuration),"GBK");
// 解码出错,properties是GBK格式
properties.load(inputStreamReader);
//2.3 获取配置文件的数据:
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
System.out.println(className);
//3. 使用**反射**技术加载类**进内存**-----------
Class aClass = Class.forName(className);
//4.创建Person对象------
//4.1因为Class类的创建Person对象方法newInstance()已经弃用
//我们先创建获得构造函数类Constructor在创建Person对象
//获得构造函数类Constructor 无参
Constructor<?> constructor = aClass.getConstructor();
//4.2 newInstance()创建Person对象
Object person = constructor.newInstance();
//5.用aClass获取getMethod对象,然后再使用新建的person对象invoke(person)执行方法---------------
Method method = aClass.getMethod(methodName);
method.invoke(person);
}
}
Run:
Java学习.Java高级.注解和反射.反射.heima.反射项目.Person
eat…
Process finished with exit code 0