Cat:
package com.hspedu;/*** @author 韩顺平* @version 1.0*/
public class Cat {private String name = "招财猫";public int age = 10; //public的public Cat() {} //无参构造器public Cat(String name) {this.name = name;}public void hi() { //常用方法//System.out.println("hi " + name);}public void cry() { //常用方法System.out.println(name + " 喵喵叫..");}}
re.properties
classfullpath=com.hspedu.Cat
method=cry
测试类
package com.hspedu.reflection.question;import com.hspedu.Cat;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;/*** 反射问题的引入*/
@SuppressWarnings({"all"})
public class ReflectionQuestion {public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {//根据配置文件 re.properties 指定信息, 创建Cat对象并调用方法hi//回忆//传统的方式 new 对象 -》 调用方法
// Cat cat = new Cat();
// cat.hi(); ===> cat.cry() 修改源码.//我们尝试做一做 -> 明白反射//1. 使用Properties 类, 可以读写配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\re.properties"));String classfullpath = properties.get("classfullpath").toString();//"com.hspedu.Cat"String methodName = properties.get("method").toString();//"hi"System.out.println("classfullpath=" + classfullpath);System.out.println("method=" + methodName);//2. 创建对象 , 传统的方法,行不通 =》 反射机制//new classfullpath();//3. 使用反射机制解决//(1) 加载类, 返回Class类型的对象clsClass cls = Class.forName(classfullpath);//(2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例Object o = cls.newInstance();System.out.println("o的运行类型=" + o.getClass()); //运行类型//(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象// 即:在反射中,可以把方法视为对象(万物皆对象)Method method1 = cls.getMethod(methodName);//(4) 通过method1 调用方法: 即通过方法对象来实现调用方法System.out.println("=============================");method1.invoke(o); //传统方法 对象.方法() , 反射机制 方法.invoke(对象)}
}
package com.hspedu.reflection;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;public class Reflection01 {public static void main(String[] args) throws Exception {//1. 使用Properties 类, 可以读写配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\re.properties"));String classfullpath = properties.get("classfullpath").toString();//"com.hspedu.Cat"String methodName = properties.get("method").toString();//"hi"//2. 使用反射机制解决//(1) 加载类, 返回Class类型的对象clsClass cls = Class.forName(classfullpath);//(2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例Object o = cls.newInstance();System.out.println("o的运行类型=" + o.getClass()); //运行类型//(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象// 即:在反射中,可以把方法视为对象(万物皆对象)Method method1 = cls.getMethod(methodName);//(4) 通过method1 调用方法: 即通过方法对象来实现调用方法System.out.println("=============================");method1.invoke(o); //传统方法 对象.方法() , 反射机制 方法.invoke(对象)//java.lang.reflect.Field: 代表类的成员变量, Field对象表示某个类的成员变量//得到name字段//getField不能得到私有的属性Field nameField = cls.getField("age"); //System.out.println(nameField.get(o)); // 传统写法 对象.成员变量 , 反射 : 成员变量对象.get(对象)//java.lang.reflect.Constructor: 代表类的构造方法, Constructor对象表示构造器Constructor constructor = cls.getConstructor(); //()中可以指定构造器参数类型, 返回无参构造器System.out.println(constructor);//Cat()Constructor constructor2 = cls.getConstructor(String.class); //这里老师传入的 String.class 就是String类的Class对象System.out.println(constructor2);//Cat(String name)}
}
速度测试
package com.hspedu.reflection;import com.hspedu.Cat;import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;/*** 测试反射调用的性能,和优化方案*/
public class Reflection02 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//Field//Method//Constructorm1();m2();m3();}//传统方法来调用hipublic static void m1() {Cat cat = new Cat();long start = System.currentTimeMillis();for (int i = 0; i < 90; i++) {cat.hi();}long end = System.currentTimeMillis();System.out.println("m1() 耗时=" + (end - start));}//反射机制调用方法hipublic static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {Class cls = Class.forName("com.hspedu.Cat");Object o = cls.newInstance();Method hi = cls.getMethod("hi");long start = System.currentTimeMillis();for (int i = 0; i < 900000000; i++) {hi.invoke(o);//反射调用方法}long end = System.currentTimeMillis();System.out.println("m2() 耗时=" + (end - start));}//反射调用优化 + 关闭访问检查public static void m3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {Class cls = Class.forName("com.hspedu.Cat");Object o = cls.newInstance();Method hi = cls.getMethod("hi");hi.setAccessible(true);//在反射调用方法时,取消访问检查long start = System.currentTimeMillis();for (int i = 0; i < 900000000; i++) {hi.invoke(o);//反射调用方法}long end = System.currentTimeMillis();System.out.println("m3() 耗时=" + (end - start));}
}
package com.hspedu.reflection.class_;import com.hspedu.Cat;
import java.util.ArrayList;/*** 对Class类特点的梳理*/
public class Class01 {public static void main(String[] args) throws ClassNotFoundException {//看看Class类图//1. Class也是类,因此也继承Object类//Class//2. Class类对象不是new出来的,而是系统创建的//(1) 传统new对象/* ClassLoader类public Class> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}*///Cat cat = new Cat();//(2) 反射方式, 刚才老师没有debug到 ClassLoader类的 loadClass, 原因是,我没有注销Cat cat = new Cat();/*ClassLoader类, 仍然是通过 ClassLoader类加载Cat类的 Class对象public Class> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}*/Class cls1 = Class.forName("com.hspedu.Cat");//3. 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次Class cls2 = Class.forName("com.hspedu.Cat");System.out.println(cls1.hashCode());System.out.println(cls2.hashCode());Class cls3 = Class.forName("com.hspedu.Dog");System.out.println(cls3.hashCode());}
}
package com.hspedu.reflection.class_;import com.hspedu.Car;import java.lang.reflect.Field;/*** 演示Class类的常用方法*/
public class Class02 {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {String classAllPath = "com.hspedu.Car";//1 . 获取到Car类 对应的 Class对象//> 表示不确定的Java类型Class> cls = Class.forName(classAllPath);//2. 输出clsSystem.out.println(cls); //显示cls对象, 是哪个类的Class对象 com.hspedu.CarSystem.out.println(cls.getClass());//输出cls运行类型 java.lang.Class//3. 得到包名System.out.println(cls.getPackage().getName());//包名//4. 得到全类名System.out.println(cls.getName());//5. 通过cls创建对象实例Car car = (Car) cls.newInstance();System.out.println(car);//car.toString()//6. 通过反射获取属性 brandField brand = cls.getField("brand");System.out.println(brand.get(car));//宝马//7. 通过反射给属性赋值brand.set(car, "奔驰");System.out.println(brand.get(car));//奔驰//8 我希望大家可以得到所有的属性(字段)System.out.println("=======所有的字段属性====");Field[] fields = cls.getFields();for (Field f : fields) {System.out.println(f.getName());//名称}}
}
package com.hspedu.reflection.class_;import com.hspedu.Car;/*** 演示得到Class对象的各种方式(6)*/
public class GetClass_ {public static void main(String[] args) throws ClassNotFoundException {//1. Class.forNameString classAllPath = "com.hspedu.Car"; //通过读取配置文件获取Class> cls1 = Class.forName(classAllPath);System.out.println(cls1);//2. 类名.class , 应用场景: 用于参数传递Class cls2 = Car.class;System.out.println(cls2);//3. 对象.getClass(), 应用场景,有对象实例Car car = new Car();Class cls3 = car.getClass();System.out.println(cls3);//4. 通过类加载器【4种(后期介绍)】来获取到类的Class对象//(1)先得到类加载器 carClassLoader classLoader = car.getClass().getClassLoader();//(2)通过类加载器得到Class对象Class cls4 = classLoader.loadClass(classAllPath);System.out.println(cls4);//cls1 , cls2 , cls3 , cls4 其实是同一个对象System.out.println(cls1.hashCode());System.out.println(cls2.hashCode());System.out.println(cls3.hashCode());System.out.println(cls4.hashCode());//5. 基本数据(int, char,boolean,float,double,byte,long,short) 按如下方式得到Class类对象Class integerClass = int.class;Class characterClass = char.class;Class booleanClass = boolean.class;System.out.println(integerClass);//int//6. 基本数据类型对应的包装类,可以通过 .TYPE 得到Class类对象Class type1 = Integer.TYPE;Class type2 = Character.TYPE; //其它包装类BOOLEAN, DOUBLE, LONG,BYTE等待System.out.println(type1);System.out.println(integerClass.hashCode());//和下面一样System.out.println(type1.hashCode());//和上面一样}
}
package com.hspedu.reflection.class_;import java.io.Serializable;/*** 演示哪些类型有Class对象*/
public class AllTypeClass {public static void main(String[] args) {Class cls1 = String.class;//外部类Class cls2 = Serializable.class;//接口Class cls3 = Integer[].class;//数组Class cls4 = float[][].class;//二维数组Class cls5 = Deprecated.class;//注解//枚举Class cls6 = Thread.State.class;Class cls7 = long.class;//基本数据类型Class cls8 = void.class;//void数据类型Class cls9 = Class.class;//Class本质也是一个类System.out.println(cls1);System.out.println(cls2);System.out.println(cls3);System.out.println(cls4);System.out.println(cls5);System.out.println(cls6);System.out.println(cls7);System.out.println(cls8);System.out.println(cls9);}
}
验证过程:
底层调用了一个SecurityManager的类作验证
打开任意一个字节码文件,JVM会验证该文件是否以魔数开头
案例说明:
package com.hspedu.reflection.classload_;/*** 我们说明一个类加载的链接阶段-准备*/
public class ClassLoad02 {public static void main(String[] args) {}
}
class A {//属性-成员变量-字段//分析类加载的链接阶段-准备 属性是如何处理//1. n1 是实例属性, 不是静态变量,因此在准备阶段,是不会分配内存//2. n2 是静态变量,分配内存 n2 是默认初始化 0 ,而不是20//3. n3 是static final 是常量, 他和静态变量不一样, 因为一旦赋值就不变 n3 = 30public int n1 = 10;public static int n2 = 20;public static final int n3 = 30;
}