反射
1.类加载器
2.获取class文件对象的方式(重点)
/*
获取class文件对象的方式(重点):
1.使用Object类中的方法getClass
Class<?> getClass() 返回此 Object 的运行时类。
2.java中会为每种数据类型都赋予一个class属性,这个class属性返回就是class文件对象
基本数据类型:int.class,double.class,char.class,boolean.class...
引用数据类型:int[].class,ArrayList<String>.class,String.class,Person.class...
3.可以使用Class类中的静态方法forName获取class文件对象
static Class<?> forName(String className) 返回与带有给定字符串名的类或接口相关联的 Class 对象。
参数:
String className:全类名(包名+类名),可以确定类的唯一性
com.itheima.demo01Reflect.Person
注意:
class文件对象是由类加载器创建的,我们无论使用那种方式获取的class文件对象都是唯一的
*/
public class Demo01Reflect {
public static void main(String[] args) throws ClassNotFoundException {
//1.使用Object类中的方法getClass,Person类默认继承了Object类,所以可以使用Object类中的方法
Person p = new Person();
Class c1 = p.getClass();
System.out.println(c1);//class com.itheima.demo01Reflect.Person
//2.java中会为每种数据类型都赋予一个class属性,这个class属性返回就是class文件对象
System.out.println(int.class);
System.out.println(double.class);
System.out.println(String.class);
Class c2 = Person.class;
System.out.println(c2);//class com.itheima.demo01Reflect.Person
//3.可以使用Class类中的静态方法forName获取class文件对象
Class c3 = Class.forName("com.zl.demo01Reflect.Person");
System.out.println(c3);
//class文件对象是由类加载器创建的,我们无论使用那种方式获取的class文件对象都是唯一的
System.out.println(c1==c2);//true 引用数据类型==比较的是对象的地址值
System.out.println(c1==c3);//true
System.out.println(c2==c3);//true
}
}
3.Class类常用方法
/*
Class类常用方法
String getSimpleName(); 获得类名字符串:类名
String getName(); 获得类全名:包名+类名
使用Class类中的forName方法,获取class文件对象,会执行类中的静态代码块(数据库:JDBC)
*/
public class Demo02ClassMethod {
public static void main(String[] args) throws ClassNotFoundException {
//获取Person类的class文件对象
Class clazz = Class.forName("com.zl.demo01Reflect.Person");
String simpleName = clazz.getSimpleName();
System.out.println(simpleName);//Person
String name = clazz.getName();
System.out.println(name);//com.zl.demo01Reflect.Person
}
}
4.反射概述
5.反射的准备工作
public class Person {
/*static {
System.out.println("静态代码块!");
}*/
private String name;
private int age;
public String sex;
public Person() {
System.out.println("Person类的空参数构造方法!");
}
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
System.out.println("Person类的满参数构造方法!");
}
private Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person类的私有构造方法!");
}
private void method(){
System.out.println("Person类的私有方法!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
6.使用反射技术获取类中的构造方法,并使用获取到的构造方法实例化对象
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/*
使用反射技术获取类中的构造方法,并使用获取到的构造方法实例化对象
实现步骤:
1.获取类的class文件对象
2.使用class文件对象中的方法getConstructor|getConstructors获取类中的(公共)构造方法
3.使用构造方法Constructor类中的方法newInstance实例化对象
*/
public class Demo03ReflectConstructor {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取类的class文件对象
Class clazz = Class.forName("com.zl.demo01Reflect.Person");
//2.使用class文件对象中的方法getConstructor|getConstructors获取类中的(公共)构造方法
/*
获取多个构造方法:
Constructor<?>[] getConstructors() 获取类的所有公共构造方法
Constructor<?>[] getDeclaredConstructors() 获取类声明的所有构造方法(包括公共的,受保护的,默认的,私有的)。
*/
Constructor[] cons = clazz.getConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
System.out.println("----------------------------");
Constructor[] declaredCons = clazz.getDeclaredConstructors();
for (Constructor con : declaredCons) {
System.out.println(con);
}
System.out.println("----------------------------");
/*
获取指定的构造方法:
Constructor<T> getConstructor(Class<?>... parameterTypes) 获取指定公共构造方法。
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定构造方法(包括公共的,受保护的,默认的,私有的)。
参数:
...:可变参数,调用方法是可变参数的方法,参数可以传递任意个
Class<?>... parameterTypes:传递构造方法参数的class文件对象
(String.class,int.class,double.class...)
注意:
类中没有指定的构造方法,会抛出NoSuchMethodException:没有这样的方法异常
*/
//public Person()
Constructor con1 = clazz.getConstructor();
System.out.println(con1);//public com.zl.demo01Reflect.Person()
//public Person(String name, int age, String sex)
Constructor con2 = clazz.getConstructor(String.class, int.class, String.class);
System.out.println(con2);//public com.zl.demo01Reflect.Person(java.lang.String,int,java.lang.String)
//private Person(String name, int age)
Constructor con3 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(con3);//private com.zl.demo01Reflect.Person(java.lang.String,int)
//3.使用构造方法Constructor类中的方法newInstance实例化对象
/*
java.lang.reflect.Constructor<T>类
T newInstance(Object... initargs) 实例化对象的方法(创建对象的方法)
参数:
Object... initargs:创建对象传递的实际参数 new Person("张三",18,"男")
返回值:
T:返回的就是创建好的对象,类型是Object
Object obj = new Person();
*/
//public Person()
Object obj1 = con1.newInstance();//此方法相当于new Person();
System.out.println(obj1);//com.zl.demo01Reflect.Person@4554617c Person{name='null', age=0, sex='null'}
//public Person(String name, int age, String sex)
Object obj2 = con2.newInstance("张三", 18, "男");//此方法相当于new Person("张三", 18, "男");
System.out.println(obj2);//Person{name='张三', age=18, sex='男'}
/*
private Person(String name, int age)
私有构造方法没有权限使用,要使用会抛出IllegalAccessException:非法访问异常
解决:
可以使用Constructor父类AccessibleObject中的方法解决
java.lang.reflect.AccessibleObject类
void setAccessible(boolean flag) 将此对象的 accessible 标志设置为指示的布尔值。
值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
值为 false 则指示反射的对象应该实施 Java 语言访问检查。
注意:
暴力反射不推荐,破坏了类的封装性(私有,不让外界使用)
*/
con3.setAccessible(true);//取消java语言访问检查==>暴力反射
Object obj3 = con3.newInstance("隔壁老王", 30);
System.out.println(obj3);//Person{name='隔壁老王', age=30, sex='null'}
}
}
7.使用反射技术获取构造方法并实例化对象的简化方式(重点)
import java.lang.reflect.Constructor;
/*
使用反射技术获取构造方法并实例化对象的简化方式(重点)
java.lang.Class类
T newInstance() 根空参数构造方法实例化对象返回
实现步骤:
1.获取类的class文件对象
2.使用class文件对象中的方法newInstance实例对象
注意
1.类中必须有空参数构造方法
2.空参数构造方法修饰符是public,不能是private
*/
public class Demo04ReflectConstructor {
public static void main(String[] args) throws Exception {
//1.获取类的class文件对象
Class clazz = Class.forName("com.zl.demo01Reflect.Person");
//2.使用class文件对象中的方法newInstance实例对象
//Constructor con = clazz.getConstructor();
//Object obj = con.newInstance();
//System.out.println(obj);
Object obj = clazz.newInstance();
System.out.println(obj);//Person{name='null', age=0, sex='null'}
Person p = (Person)obj;
p.setName("翠花");
System.out.println(p.getName());
}
}
8.使用反射技术获取类中的成员方法,并运行获取到成员方法(重点)
import java.lang.reflect.Method;
/*
使用反射技术获取类中的成员方法,并运行获取到成员方法
实现步骤:
1.获取类的class文件对象
2.使用class文件对象中的方法getMethod|getMethods获取类中(公共的)成员方法
3.使用成员方法Method类中的方法invoke,运行获取到的成员方法
*/
public class Demo05ReflectMethod {
public static void main(String[] args) throws Exception {
//1.获取类的class文件对象
Class clazz = Person.class;
//2.使用class文件对象中的方法getMethod|getMethods获取类中(公共的)成员方法
/*
获取多个成员方法:
Method[] getMethods() 获取本类和父类继承的,接口实现的所有的公共构造方法
Method[] getDeclaredMethods() 获取本类声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
Method类中的方法getName,获取方法名称
String getName() 以 String 形式返回此 Method 对象表示的方法名称。
*/
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
System.out.println("--------------------------------");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("--------------------------------");
/*
获取指定的成员方法:
Method getMethod(String name, Class<?>... parameterTypes) 获取指定公共成员方法。
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 获取指定已声明(公共、保护、默认(包)访问和私有)方法。
参数:
String name:方法的名称
Class<?>... parameterTypes:方法参数的class文件对象
注意:
获取指定的成员方法不存在,会抛出NoSuchMethodException:没有这样的方法异常
*/
//public String getName()
Method getNameMethod = clazz.getMethod("getName");
System.out.println(getNameMethod);//public java.lang.String com.zl.demo01Reflect.Person.getName()
//public void setName(String name)
Method setNameMethod = clazz.getMethod("setName", String.class);
System.out.println(setNameMethod);
//private void method()
Method privateMethod = clazz.getDeclaredMethod("method");
System.out.println(privateMethod);//private void com.zl.demo01Reflect.Person.method()
//3.使用成员方法Method类中的方法invoke,运行获取到的成员方法
/*
java.lang.reflect.Method类 extends AccessibleObject类
Object invoke(Object obj, Object... args) 运行指定的成员方法
参数:
Object obj:方法的运行需要对象的支持,运行哪个类的方法,就需要传递哪个类的对象
运行Person类的方法,需要传递Person对象(快速方式获取)
Object... args:运行方法传递的实际参数
返回值:
Object:方法的返回值
方法的返回值类型不是ovid,返回的就是方法的返回值
方法的返回值类型是void,返回null
*/
Object obj = clazz.newInstance();//new Person()
//public String getName()
Object v1 = getNameMethod.invoke(obj);//就相当于调用getName方法获取name的值
System.out.println("v1:"+v1);//v1:null name的默认值
//public void setName(String name)
Object v2 = setNameMethod.invoke(obj, "柳岩");//就相当于调用setName方法给name赋值
System.out.println("v2:"+v2);//v2:null 方法没有返回值
v1 = getNameMethod.invoke(obj);//就相当于调用getName方法获取name的值
System.out.println("v1:"+v1);//v1:柳岩
/*
private void method() 私有方法没有权限执行,会抛出非法访问异常:IllegalAccessException
使用暴力反射,取消java语言的访问权限检查
*/
privateMethod.setAccessible(true);
privateMethod.invoke(obj);//Person类的私有方法!
}
}
9.使用反射技术获取类中的成员变量(字段),并给成员变量赋值或者获取成员变量的值
import java.lang.reflect.Field;
/*
使用反射技术获取类中的成员变量(字段),并给成员变量赋值或者获取成员变量的值(了解)
实现步骤:
1.获取类的class文件对象
2.使用class文件对象中的方法getField|getFields获取类中(公共的)成员变量
3.使用成员变量Field类中的方法set给成员变量赋值,get获取成员变量的值
*/
public class Demo06ReflectField {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
//1.获取类的class文件对象
Class clazz = Class.forName("com.zl.demo01Reflect.Person");
//2.使用class文件对象中的方法getField|getFields获取类中(公共的)成员变量
/*
获取多个成员变量:
Field[] getFields() 获取所有可访问公共字段
Field[] getDeclaredFields() 获取所声明的所有字段(包含公共的,受保护的,默认的,私有的)
*/
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("----------------------------------");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}
System.out.println("----------------------------------");
/*
获取指定的的成员变量
Field getField(String name) 获取指定公共成员字段。
Field getDeclaredField(String name) 获取指定已声明字段(包含公共的,受保护的,默认的,私有的)
参数:
String name:成员变量名称
注意:
没有指定的成员变量,会抛出NoSuchFieldException:没有这样的字段异常
*/
//public String sex;
Field sexField = clazz.getField("sex");
System.out.println(sexField);//public java.lang.String com.zl.demo01Reflect.Person.sex
//private String name;
Field nameField = clazz.getDeclaredField("name");
System.out.println(nameField);//private java.lang.String com.zl.demo01Reflect.Person.name
//3.使用成员变量Field类中的方法set给成员变量赋值,get获取成员变量的值
/*
java.lang.reflect.Field类 extends AccessibleObject类
Object get(Object obj) 返回指定对象上此 Field 表示的字段的值。
参数:
Object obj:需要对象的支持,使用哪个类的字段,就传递哪个类的对象
返回值:
Object:成员变量的值
void set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
参数:
Object obj:需要对象的支持,使用哪个类的字段,就传递哪个类的对象
Object value:给字段赋实际使用值
*/
Object obj = clazz.newInstance();//使用空参数构造方法创建对象
//public String sex;
Object v1 = sexField.get(obj);
System.out.println("v1:"+v1);//v1:v1 sex的默认值
sexField.set(obj,"女");
v1 = sexField.get(obj);
System.out.println("v1:"+v1);//v1:女
/*
private String name;
私有的字段没有权限使用,需要使用暴力反射,取消java语言的权限检查
*/
nameField.setAccessible(true);
nameField.set(obj,"胡歌");
Object v2 = nameField.get(obj);
System.out.println("v2:"+v2);//v2:胡歌
}
}
10.使用反射技术获取实现类所实现的所有接口
/*
使用反射技术获取实现类所实现的所有接口
Class类中的方法:
Class<?>[] getInterfaces() 确定此对象所表示的类或接口实现的接口。
ClassLoader getClassLoader() 返回该类的类加载器。
*/
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException {
//获取接口实现类AandBImpl的class文件对象
Class clazz = Class.forName("com.zl.demo02Reflect.AandBImpl");
//使用反射技术获取实现类所实现的所有接口
Class[] interfaces = clazz.getInterfaces();
for (Class in : interfaces) {
/*
interface com.zl.demo02Reflect.A
interface com.zl.demo02Reflect.B
*/
System.out.println(in);
}
//根据class文件对象,获取到类加载器
ClassLoader classLoader = clazz.getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
}
}