欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaSE的反射机制

程序员文章站 2022-12-20 18:14:15
文章目录1.注意点2.获取class的三种方式2.1Class.forName()2.2对象.getClass()2.3任何类型.class3.通过反射实例化对象4.路径问题类加载器传送门1.注意点反射机制的作用:操作字节码文件(class文件)反射机制的相关类在java.lang.reflect.*下反射机制相关的重要类(1)java.lang.Class:代表整个字节码,代表一个类型(2)java.lang.reflect.Method:代表字节码中的方法字节码(3)java.lang....



1.注意点

  • 反射机制的作用:操作字节码文件(class文件),让代码具有通用性,可变化的内容写到配置文件中,同时源代码不需要改动,可以实现穿件不同的对象,调用不同的方法
  • 反射机制的相关类在java.lang.reflect.*下
  • 反射机制相关的重要类
    (1)java.lang.Class:代表整个字节码,代表一个类型
    (2)java.lang.reflect.Method:代表字节码中的方法字节码
    (3)java.lang.reflect.Constructor:代表字节码中的构造方法字节码
    (4)java.lang.reflect.Field:代表字节码中的属性字节码

2.Class类

2.1获取class的三种方式

2.1.1Class.forName()

Class c = Class.forName(“完整类名带包名”);
静态方法,参数为字符串,完整类名带包名

try { Class c1 = Class.forName("java.util.Date"); Class c2 = Class.forName("java.lang.String"); String s1 = "abc"; Class x = s1.getClass(); System.out.println(x==c2);//ture ==判断的是对象的内存地址 } catch (ClassNotFoundException e) { e.printStackTrace(); } 

如果只希望一个类的静态代码块执行,其他代码一律不执行,可以使用Class.forName(“完整类名”);
这个方法的执行会导致类加载,类加载时,静态代码块执行

public class ReflectTest04 { public static void main(String[] args) { try { Class.forName("com.pjpowernode.javase.reflect.Person"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } class Person { static {System.out.println("HelloWorld");} } 

2.1.2对象.getClass()

String s1 = "abc";//x代表Sting.class字节码,代表String类型 Class x = s1.getClass(); 

JavaSE的反射机制

2.1.3任何类型.class

Class y = String.class;//y代表String类型 Class z = Date.class;//z代表Date类型 System.out.println(y == c2);//true 

2.2通过反射实例化对象

通过Class的newInstance()方法来实例化对象。内部实际上调用了无参构造方法,必须保证无参构造方法存在

public class ReflectTest02 { public static void main(String[] args) { Class c = null; try { c = Class.forName("com.pjpowernode.javase.reflect.User"); Object obj = c.newInstance(); System.out.println(obj); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } } class User{} 

放射机制的灵活性:不改变java源代码的基础之上,通过修改配置文件,可以做到不同对象的实例化,符合OCP原则(对扩张开放,对修改关闭)。学会了房设计值有利于理解破鞋高级框架底层的源代码

public class ReflectTest03 { public static void main(String[] args) throws Exception { //IO流读取配置文件 FileReader reader = new FileReader("chapter25/classinfo.properties"); //穿件属性对象的Map Properties pro = new Properties(); pro.load(reader);//加载 reader.close();//关闭流 String className = pro.getProperty("className"); Class c = Class.forName(className);//通过反射机制实例化对象 Object obj = c.getName(); System.out.println(obj); } } 

3.Filed类

3.1获取Filed

Field为属性/成员

public class FiledTest01 { public static void main(String[] args) throws Exception { Class studentClass = Class.forName("com.pjpowernode.javase.filed.Student"); String className = studentClass.getName(); System.out.println(className);//完整类名 String simpleName = studentClass.getSimpleName(); System.out.println(simpleName);//简类名 //获取类中所有的public消失的Field Field[] files = studentClass.getFields(); System.out.println(files.length);//1 Field f = files[0];//取出这个Field String fieldName = f.getName(); System.out.println(fieldName);//no System.out.println("=========="); //获取所有的Field Field[] fs = studentClass.getDeclaredFields(); for (Field field : fs) { //获取属性的名字 System.out.println(field.getName()); //获取Field的属性的类型 Class fieldType = field.getType(); String fName = fieldType.getName(); System.out.println(fName); //获取属性的修饰符列表 int i = field.getModifiers(); //返回的修饰符是一个数字,每个数字代表一种修饰符 String modifierString = Modifier.toString(i); System.out.println(modifierString); System.out.println("=========="); } } } class Student { private String name; protected int age; boolean sex; public int no; } 

3.2反编译Filed

了解

public class Animal { //5个Filed private String name; protected int age; boolean sex; public int no; public static final double MATH_PI = 3.14; } public class ReflectTest05 { public static void main(String[] args) throws Exception { //反编译一个类的属性Filed StringBuilder s = new StringBuilder(); Class animalClass = Class.forName("com.pjpowernode.javase.reflect.Animal"); s.append(Modifier.toString(animalClass.getModifiers()) + " class " + animalClass.getSimpleName() + "{\n"); Field[] fields = animalClass.getDeclaredFields(); for (Field field : fields) { s.append("\t"); s.append(Modifier.toString(field.getModifiers())); s.append(" "); s.append(field.getType().getSimpleName()); s.append(" "); s.append(field.getName()); s.append(";\n"); } s.append("}"); System.out.println(s); } } 

3.3通过反射机制访问对象属性

重点

public class ReflectTest06 { public static void main(String[] args) throws Exception { //不通过反射机制访问对象的属性 Animal animal = new Animal(); animal.no = 100; System.out.println(animal.no); Class animalClass = Class.forName("com.pjpowernode.javase.reflect.Animal"); Object obj = animalClass.newInstance(); //获取no属性 Field noField = animalClass.getDeclaredField("no"); //给obj对象(Animal对象)的no赋值,三要素:obj对象,no属性,值 noField.set(obj, 222); //读取属性值,两要素:获取obj对象,no属性 System.out.println(noField.get(obj)); //可以访问对象的私有属性 Field nameField = animalClass.getDeclaredField("name"); nameField.setAccessible(true); nameField.set(obj, "Kitty"); System.out.println(nameField.get(obj)); } } 

4.Method类

4.1可变长度参数

  • 可变长度参数要求的参数个数为:0~N个
  • 可变长度参数在参数列表中必须在最后一个位置上,并且可变长度参数只能有一个
  • 可变长度参数可以当做一个数组来看待
    语法:类型…
package com.pjpowernode.javase.reflect.Method; public class MethodTest01 { public static void main(String[] args) { m(1,2,3); int[] arr ={4,5,6}; m(arr); m(new int[]{7,8,9}); } public static void m(int...args){ for (int i = 0; i <args.length; i++) { System.out.println(args[i]); } } public static void m2(int a,String...args){} } 

4.2反射Method

了解

public class MethodTest02 { public static void main(String[] args) throws Exception { Class userServiceClass = Class.forName("com.pjpowernode.javase.reflect.Method.UserService"); Method[] methods = userServiceClass.getDeclaredMethods(); for (Method method : methods) { //获取修饰符列表 System.out.println(Modifier.toString(method.getModifiers())); //获取方法的返回值类型 System.out.println(method.getReturnType().getSimpleName()); //获取方法名 System.out.println(method.getName()); //获取方法的修饰符列表 Class[] parameterTypes = method.getParameterTypes(); for (Class parameterType : parameterTypes) { System.out.println(parameterType.getSimpleName()); } } } } 

4.3反编译Method

与Field的反编译类似,了解

public class MethodTest03 { public static void main(String[] args) throws Exception { StringBuilder s = new StringBuilder(); Class userServiceClass = Class.forName("com.pjpowernode.javase.reflect.Method.UserService"); s.append(Modifier.toString(userServiceClass.getModifiers()) + " class " + userServiceClass.getSimpleName() + "{\n"); Method[] methods = userServiceClass.getDeclaredMethods(); for (Method method : methods) { s.append("\t"); s.append(Modifier.toString(method.getModifiers())); s.append(" "); s.append(method.getReturnType().getSimpleName()); s.append(" "); s.append(method.getName()); s.append("("); Class[] parameterTypes = method.getParameterTypes(); for (Class parameterType : parameterTypes) { s.append(parameterType.getSimpleName()); s.append(","); } s.deletCharAt(s.length()-1); s.append("){}\n"); } s.append("}"); System.out.println(s); } } 

4.4通过反射机制调用方法

重点

public class UserService { public boolean login(String name,String password){ if("admin".equals(name)&&"123".equals(password)){ return true; } return false; } } 
public class MethodTest04 { public static void main(String[] args) throws Exception{ //不使用反射机制 UserService userService = new UserService(); boolean loginSuccess=userService.login("admin","123"); System.out.println(loginSuccess); Class userServiceClass = Class.forName("com.pjpowernode.javase.reflect.Method.UserService"); //创建对象 Object obj =userServiceClass.newInstance(); //获取Method Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class); //调用方法,四要素:对象,方法名,实参列表,返回值 Object reValue = loginMethod.invoke(obj,"admin","123"); System.out.println(reValue); } } 

5.Constructor类

5.1反编译构造方法

了解

public class Vip { int no; String name; int age; public Vip() {} public Vip(int no, String name, int age) { this.no = no; this.name = name; this.age = age; } } 
public class ConstructorTest01 { public static void main(String[] args) throws Exception{ StringBuilder s =new StringBuilder(); Class vipClass = Class.forName("com.pjpowernode.javase.reflect.Constructor.Vip"); s.append(Modifier.toString(vipClass.getModifiers())+" class "+vipClass.getSimpleName()+"{\n"); Constructor[] constructors = vipClass.getDeclaredConstructors(); for (Constructor constructor:constructors){ s.append("\t"); s.append(Modifier.toString(constructor.getModifiers())); s.append(" "); s.append(vipClass.getSimpleName()); s.append(" "); s.append("("); Class[] parameterTypes = constructor.getParameterTypes(); for(Class parameterType:parameterTypes){ s.append(parameterType.getSimpleName()); s.append(","); } if(parameterTypes.length>0){ s.deleteCharAt(s.length()-1); } s.append("){}\n"); } System.out.println(s); } } 

5.2通过反射机制构造方法

比5.1重要一些,但都不是重点

public class ConstructorTest02 { public static void main(String[] args) throws Exception{ //不适用反射创建对象 Vip vip1 = new Vip(); Vip vip2 = new Vip(001,"zhangsan",34); //使用反射机制创建对象 Class c =Class.forName("com.pjpowernode.javase.reflect.Constructor.Vip"); //调用无参构造方法 Object obj =c.newInstance();//JDK1.8任然可以使用 System.out.println(obj); //调用有参构造方法 //第一步:获取这个有参数的构造方法 Constructor con = c.getDeclaredConstructor(int.class,String.class,int.class); //第二步:调用构造方法new对象 Object newObj = con.newInstance(002,"lisi",36); System.out.println(newObj); } } 

6.获取父类与接口

重点

public class ReflectTest07 { public static void main(String[] args) throws Exception { Class stringClass = Class.forName("java.lang.String"); //获取父类 Class superClass = stringClass.getSuperclass(); System.out.println(superClass.getName()); //获取实现了的接口 Class[] interfaces = stringClass.getInterfaces(); for (Class in : interfaces) { System.out.println(in.getName()); } } } 

路径问题

FileReader reader = new FileReader(“charper25/classinfor2.properties”);
IDEA中默认的当前路径是project的根,离开了IDEA,可能当前路径就不是了
通用的编写模式:这个文件必须在类路径下,src是类的根路径

//获取当前线程对象的类加器对象getContextClassLoader() //从类加载的根路径下加载资源jgetResource() String path = Thread.currentThread().getContextClassLoader() .getResource("classinfo.properties").getPath(); System.out.println(path); 
//String path = Thread.currentThread().getContextClassLoader() .getResource("classinfo.properties").getPath(); //FileReader reader = new FileReader(path); //直接以流的形式返回 InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("classinfo.properties"); Properties pro =new Properties(); pro.load(stream); stream.close(); String className = pro.getProperty("className"); System.out.println(className); 

java.uitl下提供了一个资源绑定器,便于获取配置文件的内容,使用以下方法时XXX.properties必须放到类路径下,路径扩展名不写

ResourceBundle bundle = ResourceBundle.getBundle("classinfo"); String className = bundle.getString("className"); System.out.println(className); 

类加载器

ClassLoader 类加载器是负责加载类的工具/命令
JDK中自带了三的类加载器

  • 启动类加载器:rt.jar
  • 扩展类加载器:ext/*.jar
  • 应用类加载器:classpath
    代码在执行之前,会将所有需要的类全部加载到JVM中。首先通过类加载器加载JDK·中最核心的类库;在启动类加载器找不到的时候,通过扩展类加载器加载;如果扩展类加载器没有加载到,通过应用类加载器加载
    java中未来保证类加载的安全,使用了双亲委派机制:
    优先从父(启动类加载器)中加载,如果无法加载到,从母(扩展类加载器)中加载。如果都加载不到,才会考虑从应用类加载器中加载

本文地址:https://blog.csdn.net/RTyinying/article/details/108018673

相关标签: JavaSE进阶 java