Java反射学习笔记
感谢慕课网Cedar老师的视频!
https://www.imooc.com/learn/199
Java-reflect专题
Class类的使用
1.在面向对象的世界里,万事万物皆对象。
类是谁的对象呢??? 类是java.lang.Class类的实例对象
代码实例:
package com.cj.study.test1; public class ClassDemo1 { public static void main(String[] args) { //Foo的实例如何表示 Foo foo = new Foo(); //Foo这个类也是一个实例对象,Class类的实例对象,如何表示呢? //任何一个类都是Class的实例对象,这个实例对象有三种表示方式 //第一种表示方式--->实际在告诉我们任何一个类都有一个隐含的静态成员变量 Class c1 = Foo.class; //第二种表示方式--->已经知道该类的对象通过getClass方法 Class c2 = foo.getClass(); /* * 官网c1,c2表示了Foo类的类类型(class type) * 万事万物皆对象 * 类也是对象,是Class类的实例对象 * 这个对象我们称为该类的类类型 */ //不管c1 or c2都代表了Foo类的类类型,一个类只可能是Class类的一个实例对象 System.out.println(c1 == c2); //打印结果:true //第三种表达方式 Class c3 = null; try { c3 = Class.forName("com.cj.study.test1.Foo"); } catch (Exception e) { e.printStackTrace(); } System.out.println(c2 == c3); //打印结果:true //我们完全可以通过类的类类型创建类的实例对象-->通过c1 or c2 or c3创建Foo类的实例对象 try { Foo foo1 = (Foo)c3.newInstance(); //需要有无参构造器的方法 foo1.print(); //打印输出:foo } catch (Exception e) { e.printStackTrace(); } } } class Foo { void print(){ System.out.println("foo"); } }
Java类的加载机制
Class.forName("类的全称")
· 不仅表示了类的类类型,还代表了动态加载类
· 编译时刻加载类是静态加载类、运行时刻加载类是动态加载类
静态加载类示例:
Word.java
class Word { public void start(){ System.out.println("word...start..."); } }
Excel.java
class Excel { public void start(){ System.out.println("excel...start..."); } }
Office.java
class Office { public static void main(String[] arg){ if("word".equals(arg[0])){ Word word = new Word(); word.start(); } if("excel".equals(arg[0])){ Excel excel = new Excel(); excel.start(); } } }
通过终端窗口进行编译并执行:
终端输入:javac Office.java 进行编译会报错,找不到Word和Excel类,因为静态加载方式需要在编译时把类都进行加载
如果想正确的输出需要先编译Word和Excel类,然后再编译Office.java!
动态加载类示例:
接口OfficeAble.java
interface OfficeAble { public void start(); }
Word.java
class Word implements OfficeAble{ public void start(){ System.out.println("word...start..."); } }
Excel.java
class Excel implements OfficeAble{ public void start(){ System.out.println("excel...start..."); } }
Office.java
class Office { public static void main(String[] arg){ try{ Class c = Class.forName(arg[0]); OfficeAble oa = (OfficeAble)c.newInstance(); oa.start(); }catch(Exception e){ e.printStackTrace(); } } }
动态加载是在运行时进行加载,如果只编译OfficeAble,Word,Office,并且以Word作为入参进行输出是不会出错的,动态加载是在运行时需要什么就加载什么!
方法的反射
获取方法中常用信息
package com.cj.study.test1; import java.lang.reflect.Method; public class ClassDemo2 { public static void main(String[] args) { Class<String> c1 = String.class; System.out.println(c1.getName());//打印结果:java.lang.String System.out.println(c1.getSimpleName());//打印结果:String printClassMessage("str"); } /** * 打印类的信息,包括类的成员函数 * @param obj */ public static void printClassMessage(Object obj){ //要获取类的信息,首先要获取类的类类型 Class c = obj.getClass(); //获取类的名称 System.out.println("类的名称是:" + c.getName()); /** * Method类,方法对象 * 一个成员方法就是一个Method对象 * getMethods()方法获取的是所有public的函数,包括父类继承而来的 * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限 */ Method[] ms = c.getMethods(); Method[] dm = c.getDeclaredMethods(); for (Method m : ms) { //得到方法的返回值类型的类类型 Class<?> returnType = m.getReturnType(); System.out.println(returnType.getName() + " "); //得到方法的名称 System.out.print(m.getName() + "("); //获取参数类型--得到的是参数列表的类型的类类型 Class<?>[] parameterTypes = m.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.print(parameterType.getName() + ","); } System.out.println(")"); } } }
printClassMessage调用打印结果:
类的名称是:java.lang.String boolean equals(java.lang.Object,) java.lang.String toString() int hashCode() int compareTo(java.lang.Object,) int compareTo(java.lang.String,) int indexOf(java.lang.String,int,) int indexOf(int,) int indexOf(java.lang.String,) int indexOf(int,int,) java.lang.String valueOf(char,) java.lang.String valueOf(java.lang.Object,) java.lang.String valueOf(boolean,) java.lang.String valueOf([C,int,int,) java.lang.String valueOf([C,) java.lang.String valueOf(double,) java.lang.String valueOf(float,) java.lang.String valueOf(long,) java.lang.String valueOf(int,) int length() boolean isEmpty() char charAt(int,) int codePointAt(int,) int codePointBefore(int,) int codePointCount(int,int,) int offsetByCodePoints(int,int,) void getChars(int,int,[C,int,) [B getBytes() [B getBytes(java.lang.String,) void getBytes(int,int,[B,int,) [B getBytes(java.nio.charset.Charset,) boolean contentEquals(java.lang.StringBuffer,) boolean contentEquals(java.lang.CharSequence,) boolean equalsIgnoreCase(java.lang.String,) int compareToIgnoreCase(java.lang.String,) boolean regionMatches(int,java.lang.String,int,int,) boolean regionMatches(boolean,int,java.lang.String,int,int,) boolean startsWith(java.lang.String,) boolean startsWith(java.lang.String,int,) boolean endsWith(java.lang.String,) int lastIndexOf(int,int,) int lastIndexOf(java.lang.String,int,) int lastIndexOf(int,) int lastIndexOf(java.lang.String,) java.lang.String substring(int,) java.lang.String substring(int,int,) java.lang.CharSequence subSequence(int,int,) java.lang.String concat(java.lang.String,) java.lang.String replace(char,char,) java.lang.String replace(java.lang.CharSequence,java.lang.CharSequence,) boolean matches(java.lang.String,) boolean contains(java.lang.CharSequence,) java.lang.String replaceFirst(java.lang.String,java.lang.String,) java.lang.String replaceAll(java.lang.String,java.lang.String,) [Ljava.lang.String; split(java.lang.String,int,) [Ljava.lang.String; split(java.lang.String,) java.lang.String join(java.lang.CharSequence,[Ljava.lang.CharSequence;,) java.lang.String join(java.lang.CharSequence,java.lang.Iterable,) java.lang.String toLowerCase(java.util.Locale,) java.lang.String toLowerCase() java.lang.String toUpperCase() java.lang.String toUpperCase(java.util.Locale,) java.lang.String trim() [C toCharArray() java.lang.String format(java.util.Locale,java.lang.String,[Ljava.lang.Object;,) java.lang.String format(java.lang.String,[Ljava.lang.Object;,) java.lang.String copyValueOf([C,int,int,) java.lang.String copyValueOf([C,) java.lang.String intern() void wait(long,int,) void wait(long,) void wait() java.lang.Class getClass() void notify() void notifyAll() java.util.stream.IntStream chars() java.util.stream.IntStream codePoints()
成员变量的反射
package com.cj.study.test1; import java.lang.reflect.Field; public class ClassDemo3 { public static void main(String[] args) { // printFieldMessage("hello"); printFieldMessage(new Integer(1)); } public static void printFieldMessage(Object obj){ Class c = obj.getClass(); /** * 成员变量也是对象 * java.lang.reflect.Field * Field类封装了关于成员变量的操作 * getFields()方法获取的是所有的public的成员变量的信息,包括父类继承的 * getDeclaredFields()获取的是该类自己声明的成员变量的信息 */ // Field[] fs = c.getFields(); Field[] fs = c.getDeclaredFields(); for (Field f : fs) { Class<?> type = f.getType(); String typeName = type.getName(); //得到成员变量的名称 String fieldName = f.getName(); System.out.println(typeName + "," + fieldName); } } }
printFieldMessage调用打印结果:
int,MIN_VALUE int,MAX_VALUE java.lang.Class,TYPE [C,digits [C,DigitTens [C,DigitOnes [I,sizeTable int,value int,SIZE int,BYTES long,serialVersionUID
构造函数的反射
package com.cj.study.test1; import java.lang.reflect.Constructor; public class ClassDemo4 { public static void main(String[] args) { // printConMessage("hello"); printConMessage(new Integer(1)); } public static void printConMessage(Object obj){ Class c = obj.getClass(); /** * 构造函数也是对象 * java.lang.Constructor中封装了构造函数的信息 * getConstructors()获取所有本类声明的public构造函数 * getDeclaredConstructors()得到本类声明的所有构造函数 */ Constructor[] cs = c.getConstructors(); // Constructor[] cs = c.getDeclaredConstructors(); for (Constructor constructor : cs) { System.out.print(constructor.getName() + "("); Class[] parameterTypes = constructor.getParameterTypes(); for (Class parameterType : parameterTypes) { System.out.print(parameterType.getName() + ","); } System.out.println(")"); } } }
printConMessage调用打印结果:
java.lang.Integer(int,) java.lang.Integer(java.lang.String,)
通过类的类类型还可以获取很多关于类的信息,不一一列举了
方法反射的基本操作
package com.cj.study.test1; import java.lang.reflect.Method; public class MethodDemo1 { public static void main(String[] args) throws Exception { //要获取print(int,int)方法 //1.要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型 A a = new A(); Class c = a.getClass();
/** * 2.获取方法名称和参数列表来决定 * getMethod获取的是public的方法 * getDeclaredMethod获取自己生命的方法 */ // Method m = c.getMethod("print", int.class, int.class); Method m = c.getDeclaredMethod("print", new Class[]{int.class,int.class}); //下方这样的调用方法和a.print(10,20)效果是一样的 //方法如果没有返回值返回null,有返回值就会返回具体的值 // Object o = m.invoke(a, new Object[]{10, 20}); Object o = m.invoke(a,10,20); Method m1 = c.getMethod("print"); Object o1 = m1.invoke(a); Method m2 = c.getMethod("print", new Class[]{String.class, String.class}); Object o3 = m2.invoke(a, new Object[]{"HELLO", "world"}); } } class A { public void print(int a, int b){ System.out.println(a + b); }; public void print(String a, String b){ System.out.println(a.toLowerCase() + " " + b.toUpperCase()); }; public void print(){ System.out.println("啥也没有"); }; }
控制台打印结果:
30
啥也没有
hello WORLD
通过反射了解集合泛型的本质
package com.cj.study.test1; import java.lang.reflect.Method; import java.util.ArrayList; public class MethodDemo4 { public static void main(String[] args) { ArrayList list1 = new ArrayList(); ArrayList<String> list2 = new ArrayList<String>(); list2.add("hello"); Class c1 = list1.getClass(); Class c2 = list2.getClass(); System.out.println(c1 == c2); //打印输出true //反射的操作都是编译之后的操作 /** * c1 == c2结果返回true说明编译之后集合的泛型是去泛型化的 * Java中集合的泛型是防止错误输入的,只在编译阶段有效,绕过就无效了 * * 验证:我们可以操作方法的反射绕过编译 */ try { Method m = c2.getMethod("add",Object.class); m.invoke(list2,20); //绕过操作就绕过了泛型 System.out.println(list2.size()); //打印输出2 //不能使用加强for循环遍历,会报转换异常 // for (String s : list2) { // System.out.println(s); // } } catch (Exception e) { e.printStackTrace(); } } }