黑马程序员---Java基础---反射

时间:2023-02-19 17:04:51

-----------android培训java培训、java学习型技术博客、期待与您交流!------------ 


一、获取Class对象的三种方式:

1.调用Object类的getClass():任何类都会继承此方法;

2.任何的数据类型(包括基本类型)都有一个:静态的class属性:

Student.class;

int.class

3.调用Class类的静态方法forName(String 全名限定的类名):(常用)

通过这个Class对象,可以获取Student类内部的成员属性、构造方法、成员方法的一些信息,并能够调用它们;

package cn.hebei.sjz_反射;

/*
* 获取Class对象的三种方式:
*/
public class Demo {
public static void main(String[] args) throws Exception {
Student stu = new Student();

Class stuClass1 = stu.getClass();

Class stuClass2 = Student.class;

Class stuClass3 = Class.forName("cn.itcast.demo01_获取Class对象的三种方式.Student");

System.out.println(stuClass1 == stuClass2);
System.out.println(stuClass1 == stuClass3);

Student stu2 = new Student();
Class stuClass4 = stu2.getClass();
System.out.println(stuClass1 == stuClass4);
}
}


二、通过Class对象获取构造方法并调用
Class类:

批量的:

Constructor[] getConstructors() :获取所有的"公有构造方法"

Constructor[] getDeclaredConstructors() :获取全部(包括私有)的构造方法;

获取某个构造方法

Constructor getConstructor(Class ... parameterTypes) :获取指定的"公有构造方法";

Constructor getDeclaredConstructor(Class ... parameterTypes) :获取指定的构造方法(包括私有的);

调用某个构造方法:

Constructor的 Object newInstance(Object... initargs) :调用指定构造方法,并实例化此类的对象;

暴力访问:如果私有成员,需要设置暴力访问;

Constructor的setAccessible(true):不进行权限检查;

package cn.hebei.sjz_通过Class对象获取构造方法并调用;

import java.lang.reflect.Constructor;

public class Demo {
public static void main(String[] args) throws Exception {
//1.获取Student的Class对象
Class stuClass = Class.forName("cn.itcast.demo02_通过Class对象获取构造方法并调用.Student");
System.out.println("************获取所有的\"公有构造方法\"*******************");
Constructor[] conArray = stuClass.getConstructors();
for(Constructor c : conArray){
System.out.println(c);
}

System.out.println("************获取所有的构造方法(包括私有的)***************");
conArray = stuClass.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}

System.out.println("************获取\"公有构造方法\"***********************");
Constructor con = stuClass.getConstructor(String.class);//获取的是"具有String类型形参的"公有构造方法
//Constructor con = stuClass.getConstructor(String.class,int.class);
Object obj = con.newInstance("刘德华");//调用此构造方法,并传递实参:相当于:Object obj = new Student("刘德华");

System.out.println("************获取\"私有构造方法\"并调用*******************");
con = stuClass.getDeclaredConstructor();
//设置暴力访问
con.setAccessible(true);

obj = con.newInstance();

}
}


三、通过Class对象获取成员属性并调用
Class类的方法:

批量的:

Field[] getFields():获取所有"公有属性";

Field[] getDeclaredFields() :获取所有成员属性(包括私有):

获取单个成员属性

Field getField(String name) :获取指定的"公有属性";

Field getDeclaredField(String name) :获取指定的属性,包括私有的;

为成员属性赋值:(注意:1.一定要先实例化此类对象;2.访问私有属性前,要设置暴力访问)

Field的 void set(Object obj, Object value) 

package cn.hebei.sjz_通过Class对象获取成员属性;

import java.lang.reflect.Field;

public class Demo {
public static void main(String[] args) throws Exception {
// 1.获取Student的Class对象
Class stuClass = Class.forName("cn.itcast.demo03_通过Class对象获取成员属性并调用.Student");
System.out.println("********************获取所有\"公有属性\"************************");
Field[] fieldArray = stuClass.getFields();
for (Field f : fieldArray) {
System.out.println(f);
}
System.out.println("********************获取所有属性(包括私有的)************************");
fieldArray = stuClass.getDeclaredFields();
for (Field f : fieldArray) {
System.out.println(f);
}

// 创建一个Student对象
Object obj = stuClass.getConstructor().newInstance();
System.out.println("*********************获取公有属性,并调用*********************************");
Field f = stuClass.getField("name");
System.out.println("赋值前打印:" + obj);
f.set(obj, "刘德华");
System.out.println("赋值后打印:" + obj);

System.out.println("*********************获取私有属性,并赋值*********************************");
f = stuClass.getDeclaredField("score");
// 暴力访问
f.setAccessible(true);

f.set(obj, 88.5);
System.out.println(obj);
}
}


四、通过Class对象获取成员方法并调用
Class类的方法:

批量的:

Method[] getMethods():获取所有"公有方法"(包括继承的)

Method[] getDeclaredMethods() :获取所有成员方法(包括私有):

获取单个成员方法

Method getMethod(String name, Class... parameterTypes) :获取指定的"公有方法";

Method getDeclaredMethod(String name, Class... parameterTypes) :获取指定的方法,包括私有的;

调用方法:(注意:1.要先创建此类的对象;2.调用私有方法前,要先设置暴力访问)

Method:

Object invoke(Object obj, Object... args) :调用Method所代表的方法:

返回值:此Method对象调用所代表的方法,所获取的返回值;

形参:obj:方法所属对象;

args:Method所代表的那个方法的实参列表;

package cn.hebei.sjz_通过Class对象获取成员方法并调用;

import java.lang.reflect.Method;

public class Demo {
public static void main(String[] args) throws Exception {
//1.获取Class对象
Class stuClass = Class.forName("cn.itcast.demo04_通过Class对象获取成员方法并调用.Student");
System.out.println("*************获取所有\"公有方法\"*******************");
Method[] methodArray = stuClass.getMethods();
for(Method m : methodArray){
System.out.println(m);
}
System.out.println("**************获取所有的方法(包括私有的)***************");
methodArray = stuClass.getDeclaredMethods();
for(Method m : methodArray){
System.out.println(m);
}

//创建Student对象
Object obj = stuClass.getConstructor().newInstance();

System.out.println("**************获取公有的,带参的show1()方法,并调用******");
Method m = stuClass.getMethod("show1", String.class,int.class);
Object result = m.invoke(obj, "刘德华",20);//调用show1()方法
System.out.println("调用的返回值:" + result);

System.out.println("***************获取私有的,无参的、无返回值的show4()方法,并调用****************");
m = stuClass.getDeclaredMethod("show4");
m.setAccessible(true);
m.invoke(obj);


}
}


五、练习

练习1

package cn.hebei.sjz_通过反射运行配置文件内容;

import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
/*
* 通过反射运行配置文件内容
*/
public class Demo {
public static void main(String[] args) throws Exception {
//1.获取Student的Class对象
//Class stuClass = Class.forName("cn.hebei.sjz_通过反射运行配置文件内容.Student");
String classPath = getValue("className");
Class stuClass = Class.forName(classPath);

//2.实例化一个Student对象
Object obj = stuClass.getConstructor().newInstance();
//3.调用方法
//Method m = stuClass.getMethod("show");
Method m = stuClass.getMethod(getValue("methodName"));
m.invoke(obj);
}

//一个方法,获取配置文件中的某个键对应的值
public static String getValue(String key) throws IOException{
Properties pro = new Properties();
FileReader in = new FileReader("properties.ini");
pro.load(in);
in.close();

return pro.getProperty(key);
}
}


练习2:

package cn.hebei.sjz_通过反射越过泛型检查;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/*
*
* 通过反射越过泛型检查:
*
* 1.定义一个具有String泛型的集合,要求成功向集合中添加一个int数据;
*/
public class Demo {
public static void main(String[] args) throws Exception, SecurityException {
List<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb");
//strList.add(10);

//通过反射
Class listClass = strList.getClass();
//获取add方法
Method addMethod = listClass.getMethod("add", Object.class);
//调用add方法
addMethod.invoke(strList, 10);

//遍历集合
for(Object o : strList){
System.out.println(o);
}

}
}


练习3:

package cn.hebei.sjz_通用方法;

import java.lang.reflect.Field;

/*
* 通用方法
*/
public class Demo {
public static void main(String[] args) throws SecurityException, Exception {
Cat c = new Cat();
setValue(c, "name", "波斯猫");
c.show();
}

// 通过反射写一个通用的设置某个对象的某个属性为指定的值
public static void setValue(Object target, String fieldName, Object value)
throws Exception, SecurityException {
// 1.获取Class对象
Class aClass = target.getClass();
// 2.获取字段
Field f = aClass.getDeclaredField(fieldName);
// 3.暴力访问
f.setAccessible(true);
// 4.设置
f.set(target, value);
}
}


六、代理模式

代理类的目的:是为所代理的类的某些方法,增加一些额外的操作;

Java中实现动态代理:

步骤:

1.自定义类,实现InvocationHandler接口;

重写invoke()方法:需要代理的方法,都要经过此方法,

我们可以在此方法中做我们想要做的事情;

2.动态生成代理对象:

Proxy类静态方法:newProxyInstance()

注意:Java的动态代理机制是基于"接口"的,也就是所有需要被代理的类都必须实现某个接口,以达到它们作为共同类型的目的;