Reflection是Java被视为动态语言的关键
需求:使用反射创建一个类的对象
public class demo1 {
public static void main(String[] args) throws Exception {
//正常手段new对象
User user1 = new User(001, "Kitty", 15);
User user2 = new User(001, "Kitty", 15);
System.out.println("----------------------------");
Class class1 = Class.forName("反射.User"); ————————获取类的模板
User user = (User) class1.newInstance(); ————————获取类的对象
user.setAge(20);
user.setId(002);
user.setName("Tony");
System.out.println(user);
}
}
class User{
private int id;
private String name;
private int age;
public User(){}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "id:"+id+" name:"+name+" age:"+age;
}
}
对象照镜子后可以得到的信息——某个类的属性、方法和构造器、某个类到底实现了哪些接口
对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象
注意:
eg: Class class1 = Class.forName("反射.User"); ————————获取类的模板
——包名+类名
eg: User user = (User) class1.newInstance(); ————————获取类的对象
———类名调用方法
eg:Class clazz = Person.class;
————类名直接调用eg:Class clazz = person.getClass();
————new出来的实例对象调用getclass方法eg:Class clazz = Class.forName("demo01.Student");
————forname方法练习获取class类
public class demo2 {
public static void main(String[] args) throws Exception {
//获得class对象的方法1——用new出来的对象实例获取class模板
Person person = new Student();
Class class1 = person.getClass();
//获得class对象的方法2
Class class2 = Class.forName("反射.Person");
//获得class对象的方法3——类名直接调用class
Class class3 = Student.class;
//获取父类的类型
Class superclass = class1.getSuperclass();
//获取Class对象——正对包装类,内置基本类型 ,只对包装类型有效
Class type = Integer.TYPE;
System.out.println(type);//——————输出:int
// 打印
System.out.println(person);
System.out.println(class1);
System.out.println(class2);
System.out.println(class3);
System.out.println(superclass);
}
}
...————————此处省略类的描述
练习:各种类型的class对象
import java.lang.annotation.ElementType;
public class demo3 {
public static void main(String[] args) {
Class c1 = Object.class; // Object类
Class<Comparable> c2 = Comparable.class;// 接口
Class<String> c3 = String.class; // 基本类型
Class<String[]> c4 = String[].class; // 数组
Class<ElementType> c5 = ElementType.class; // 枚举类型
Class<Override> c6 = Override.class; // 注解
Class c7 = int[][].class; // 基本类型
Class<Void> c8 = void.class; // void
Class<Class> c9 = Class.class; // 反射对象本身
System.out.println(c1);——————class java.lang.Object
System.out.println(c2);——————interface java.lang.Comparable
System.out.println(c3);——————class java.lang.String
System.out.println(c4);——————class [Ljava.lang.String;
System.out.println(c5);——————class java.lang.annotation.ElementType
System.out.println(c6);——————interface java.lang.Override
System.out.println(c7);——————class [[I
System.out.println(c8);——————void
System.out.println(c9);——————class java.lang.Class
System.out.println("======================");
// 数组中 和长度无关 类型相同就是一个class
int[] arr = new int[10];
int[] arr2 = new int[100];
Class<? extends int[]> c10 = arr.getClass();
Class<? extends int[]> c11 = arr2.getClass();
System.out.println(c10);——————class [I
System.out.println(c11);——————class [I
}
}
类构造器clinit()方法:由编译期自动收集类中所有类变量的赋值动作和静态 代码块中的语句合并产生的
(类构造器是构造类信息的,不是构造该类对象的构造器)。
eg: static {
System.out.println("静态代码块");
m = 300;
}
static int m = 100;——————————m = 100
练习:深刻练习内存初始化
public class demo4 {
public static void main(String[] args) {
A a = new A();
System.out.println(a.m);
* 1. 加载——加载到内存 会产生一个类对应的class对象
* 2. 连接——为static变量m分配内存 m=0
* 3. 初始化——调用clinit()方法 最后m = 100;
* clinit()
* System.out.println("静态代码块");
m = 300;
m = 100;
* }
}
}
class A{
static { // 1.先执行静态代码块
System.out.println("静态代码块");
m = 300;
}
static int m = 100;
public A(){ // 2.后执行构造方法
System.out.println("构造方法");
}
}
主动引用————一定导致类的初始化
eg: ------------主动引用:调用父类的静态变量 ——导致两者初始化
Son son = new Son();
System.out.println( new Son().f);
eg: --------调用子类的静态变量——导致两者初始化
System.out.println(Son.s);
--------调用子类的变量——导致两者初始化
System.out.println(new Son().a);
eg: --------反射引用:——导致两者初始化
Class.forName("反射.Son");
类的被动引用————不会发生类的初始化
eg: --------子类调用父类的静态变量——导致父类被初始化 子类不会初始化
System.out.println(Son.f);
eg: --------被动引用:创建自定义类数组——不会导致两者初始化
Son[] sons = new Son[10];
eg: --------子类调用常量 ——不会导致两者初始化
System.out.println(Son.ss);
分类:系统提供的和java开发人员编写的
系统提供的类加载器有:引导类加载器 扩展类加载器 系统类加载器
用来加载 Java 的核心库,是用原生代码来实现的,并不继承自java.lang.ClassLoader。 无法直接获取
用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
它据 Java 应用的类路径来加载 Java 类 Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
基本上所有的类加载器都是 java.lang.ClassLoader类的一个实例
每个加载器都有自己的加载缓存 当一个类被加载之后会放进缓存中 等到下次加载时只需拿出之前加载好的类
练习获取类加载器
public class demo6 {
public static void main(String[] args) throws ClassNotFoundException {
//获得系统的类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);——————sun.misc.Launcher$AppClassLoader@18b4aac2
// 获得系统加载器的父类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);——————sun.misc.Launcher$ExtClassLoader@1b6d3586
// 获得父类加载器的父类加载器
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);——————null
//获取当前的类加载器
ClassLoader classLoader = Class.forName("反射.demo6").getClassLoader();
System.out.println(classLoader);——————sun.misc.Launcher$AppClassLoader@18b4aac2
//获取JDK内置类的加载器——顶层加载器加载
ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader1);——————null
//获得系统类加载器可以加载的路径
String property = System.getProperty("java.class.path");
System.out.println(property);
}
}
需要参数 因为方法重载之后 仅仅靠方法名无法判断
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class demo7 {
public static void main(String[] args) throws Exception {
// 获取类的信息——模板
Class aclass = Class.forName("反射.User");
// 获得类名
System.out.println(aclass.getName());// 获得全类名:包名+类名
System.out.println(aclass.getSimpleName());//获得类名
System.out.println("============================");
//获得字段(成员变量)
Field[] fields = aclass.getFields();//获得public的变量
for (Field field : fields) {
System.out.println(field);
}
Field[] declaredFields = aclass.getDeclaredFields();//获得全部变量 包括private
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("============================");
//获得指定字段
Field id = aclass.getDeclaredField("id");
System.out.println(id);
System.out.println("============================");
//获得方法
Method[] methods = aclass.getMethods();// 获得public的方法
for (Method method : methods) {
System.out.println("公有:"+method);
}
Method[] declaredMethods = aclass.getDeclaredMethods();// 获得全部方法 包括私有
for (Method declaredMethod : declaredMethods) {
System.out.println("全部:"+declaredMethod);
}
System.out.println("============================");
//获得指定方法
Method getName = aclass.getMethod("getName");
Method setName = aclass.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
System.out.println("============================");
//获得构造器
Constructor[] constructors = aclass.getConstructors();//获得public的构造器
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
Constructor[] declaredConstructors = aclass.getDeclaredConstructors();//获得全部的构造器 包括私有
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
System.out.println("============================");
//获得指定的构造器
Constructor constructor = aclass.getConstructor(null);
Constructor constructor1 = aclass.getConstructor(int.class, String.class, int.class);
System.out.println(constructor);
System.out.println(constructor1);
}
}
反射创建对象的方法
练习:使用反射创建对象 调用方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class demo8 {
public static void main(String[] args) throws Exception {
Class aclass = Class.forName("反射.User");
------创建对象方法一——通过new默认为无参对象
User user1 = (User) aclass.newInstance();
System.out.println(user1);
System.out.println("==========================");
------创建对象方法二——通过指定构造器创建对象
Constructor declaredConstructor = aclass.getDeclaredConstructor(int.class, String.class, int.class);
User user2 = (User) declaredConstructor.newInstance(1, "张三", 20);
System.out.println(user2);
System.out.println("==========================");
/*调用方法传参*/
//1. 创建一个对象
User user3 = (User) aclass.newInstance();
// 2. 获得要使用的方法
Method setName = aclass.getDeclaredMethod("setName", String.class);
//3. 使用invoke( ) 执行方法
setName.invoke(user3,"李四");
System.out.println(user3.getName());
System.out.println("==========================");
/*获得字段*/
//1.创建一个对象
User user4 = (User) aclass.newInstance();
//2. 获得要使用的字段(成员变量)
Field age = aclass.getDeclaredField("age");
//3.解决办法:调用setAccessible(true)方法 则可以访问私有
age.setAccessible(true);
age.set(user4,21);
System.out.println(user4.getAge());
}
}
测试:是否关闭检查测试性能
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class demo9 {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
//测试性能
test1();
test2();
test3();
}
public static void test1(){
User user = new User();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long end = System.currentTimeMillis();
System.out.println("普通调用:"+(end-start)+"毫秒");
}
public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class aClass = user.getClass();
Method getName = aClass.getDeclaredMethod("getName");
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long end = System.currentTimeMillis();
System.out.println("反射调用:"+(end-start)+"毫秒");
}
public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class aClass = user.getClass();
Method getName = aClass.getDeclaredMethod("getName");
getName.setAccessible(true);//关闭检查
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long end = System.currentTimeMillis();
System.out.println("反射关闭检查调用:"+(end-start)+"毫秒");
}
}——————————输出:普通调用:3毫秒 电脑有些快哦哈哈哈
反射调用:2172毫秒
反射关闭检查调用:1052毫秒
练习:反射获取泛型类型
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class demo10 {
public static void main(String[] args) throws Exception {
//反射获取泛型信息
Method method = demo10.class.getMethod("test1", Map.class, List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();//其返回的是参数的参数化的类型,里面的带有实际的参数类型
for (Type genericParameterType : genericParameterTypes) {
System.out.println("原始参数:"+genericParameterType);
if(genericParameterType instanceof ParameterizedType){ // 如果这个参数的类型是泛型
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("附加参数:"+actualTypeArgument);
}
}
}
// 反射获取返回值泛型信息
Method method1 = demo10.class.getMethod("test2");
Type genericReturnType = method1.getGenericReturnType();
if(genericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
System.out.println("返回值:"+actualTypeArguments);
}
}
public void test1(Map<String,User> map,List<User> list){
System.out.println("1111");
}
public Map<Integer,User> test2(){
System.out.println("2222");
return null;
}
}
练习:反射获取注解信息
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class demo11 {
public static void main(String[] args) throws Exception {
Class aClass = Class.forName("反射.Student2");
//获得类的注解信息
Annotation[] annotations = aClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
// 获得类的注解的名字
lei lei = (反射.lei) aClass.getAnnotation(lei.class);
System.out.println(lei.value());
//获得类中字段的注解信息
Field name = aClass.getDeclaredField("name");
ziduan ziduan = (ziduan)name.getAnnotation(ziduan.class);
System.out.println(ziduan.name());
System.out.println(ziduan.type());
System.out.println(ziduan.length());
}
}
@lei("db_Student")
class Student2{
@ziduan(name = "db_id",type = "int",length = 10)
private int id;
@ziduan(name = "db_name",type = "String",length = 5)
private String name;
@ziduan(name = "db_age",type = "int",length = 5)
private int age;
public Student2() { }
public Student2(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
//定义类的注解
@Target(ElementType.TYPE) // 定义注解起作用的范围
@Retention(RetentionPolicy.RUNTIME) // 定义注解起作用的时间
@interface lei{
String value();
}
// 定义字段的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface ziduan{
String name();
String type();
int length();
}