1、页首请关注 思维导航大纲

2、大牛文章学习:

序号 博主 主要内容
1  sinat_38259539 总结的较全面的反射内容
2    

3、自己的理解:

3.1.本文大纲

3.2.正文

1、获取class类的方法 

反射首先是要获取class类,获取class类有以下几种方法:

[参考博文:https://blog.csdn.net/beiyoujiayu/article/details/50451875] (感谢原文博主内容)内容如下,并对其中a、b、c 三点进行了验证:

#a&b. 内容验证:

public class Test {

   public static  void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
System.out.println("111111");
Class clazz = A.class;
System.out.println("222222");
A a = (A)clazz.newInstance();
System.out.println("333333"); System.out.println("\n111111");
Class clazz1 =Class.forName("$reflect.B");
System.out.println("222222");
B b = (B)clazz1.newInstance();
System.out.println("333333");
} } class A{
// 静态代码块
static{
System.out.println("hello A~");
}
// 非静态代码块
{
System.out.println("world A~");
}
}
class B{
static{
System.out.println("hello B~");
}
{
System.out.println("world A~");
}
}

运行结果,大家仔细看看,这个结果的输出也是惊艳到我了,竟然不一样(底层实现细节还不清楚,哪位大牛看到是否能指教一下):

#c. 内容,这个博文写的不对,应该说class.forName 是动态加载,其他的是静态加载,

参考博文[java动态加载类和静态加载类: https://blog.csdn.net/su20145104009/article/details/52935472]

还有这篇文章:https://www.cnblogs.com/yangwenbin/p/4344294.html

以及这篇文章:https://blog.csdn.net/zyw23zyw23/article/details/70244825

核心差别是:两者的出现的时期不同:

动态加载(运行时加载): Class.forName()在运行时加载;

静态加载(编译时加载): Class.class和getClass()是在编译器加载

2、反射的过程,构造器、字段、方法 的反射

class获取到以后,我们就可以为所欲为啦~~~~~~~

测试类:

class Human {
public String publicField;
protected String protectedField;
private String privateField;
}
class Person extends Human{ public String sex;
private Integer age;
public double high; // 注意该字段没有get set 方法 private Person() {
} public Person(Integer age, String sex) {
this.age = age;
this.sex = sex;
} private void privateMethod() {
System.out.println("执行私有方法");
}
protected void protectedMethod() {
System.out.println("执行protected方法");
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} @Override
public String toString() {
return "Person{" + "sex='" + sex + '\'' + ", age=" + age + '}';
}
}

2.构造器的反射:

主要有以下几个方法,带 Declare的表示获取申明的所有构造器:

具体代码:

    Class clazz = Class.forName("$reflect.Person");
    System.out.println("获取公共构造器:");
    Constructor[] cons = clazz.getConstructors();
    for (Constructor con : cons) {
    System.out.println(con);
    }
    System.out.println("获取定义的所有构造器:");
    cons = clazz.getDeclaredConstructors();
    for (Constructor con : cons) {
    System.out.println(con);
    }
输出:
获取公共构造器:
public $reflect.Person(java.lang.Integer,java.lang.String)
获取定义的所有构造器:
private $reflect.Person()
public $reflect.Person(java.lang.Integer,java.lang.String)

获取对象:

        Class clazz = Class.forName("$reflect.Person");

        System.out.println("测试1:获取对象[获取私有构造器报错]");
try {
Constructor con = clazz.getConstructor();
con.newInstance();
} catch (Exception e) {
e.printStackTrace();
}

测试1:获取对象[获取私有构造器报错]
java.lang.NoSuchMethodException: $reflect.Person.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getConstructor(Class.java:1825)
at $reflect.Test2.main(Test2.java:27)

        System.out.println("测试2:获取对象[私有构造器直接获取对象报错]");
try {
Constructor con = clazz.getDeclaredConstructor();
Object obj = con.newInstance(); //私有构造器获取对象直接报错
System.out.println(obj);
} catch (Exception e) {
e.printStackTrace();
}

测试2:获取对象[私有构造器直接获取对象报错]
java.lang.IllegalAccessException: Class $reflect.Test2 can not access a member of class $reflect.Person with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Constructor.newInstance(Constructor.java:413)
at $reflect.Test2.main(Test2.java:29)

        System.out.println("测试3:获取对象[成功]");
try {
Constructor con = clazz.getDeclaredConstructor();
       // 设置为可读
con.setAccessible(true);
Object obj = con.newInstance();
System.out.println(obj);
} catch (Exception e) {
e.printStackTrace();
}
测试3:获取对象[成功]

2.2.字段的反射:

方法:

代码:

    System.out.println("获取公共字段:");
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}

获取公共字段:

public java.lang.String $reflect.Person.sex

public double $reflect.Person.high

public java.lang.String $reflect.Human.publicField

    System.out.println("获取定义的所有字段:");
fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}

获取定义的所有字段:
public java.lang.String $reflect.Person.sex

public double $reflect.Person.high

private java.lang.Integer $reflect.Person.age

设置对象字段:

try {
Constructor con = clazz.getDeclaredConstructor();
con.setAccessible(true);
Object obj = con.newInstance();
System.out.println(obj);
Field field = clazz.getField("sex");
field.set(obj, "男");
System.out.println(obj);
//field = clazz.getField("age"); java.lang.NoSuchFieldException: age
//field.set(obj, 28);
     field = clazz.getDeclaredField("age");
field.setAccessible(true);
field.set(obj, 28);
System.out.println(obj);
} catch (Exception e) {
e.printStackTrace();
}

Person{sex='null', age=null}
Person{sex='男', age=null}
Person{sex='男', age=28}

总结1:没有get/set方法发字段也可以通过字段反射设置值:

    try {
Class clazz = Class.forName("$reflect.Person");
Object obj = new Person(28, "男");
System.out.println(obj); Field f = clazz.getField("high");
f.set(obj, 17);
System.out.println(f.get(obj));
System.out.println(obj);
}
catch (Exception e){
e.printStackTrace();
}

Person{sex='男', age=28, high=0.0}
17.0
Person{sex='男', age=28, high=17.0}

2.3.方法的反射:

方法:

获取方法:

  System.out.println("获取公共方法:");
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}

获取公共方法:
public java.lang.String $reflect.Person.toString()
public java.lang.Integer $reflect.Person.getAge()
public void $reflect.Person.setAge(java.lang.Integer)
public java.lang.String $reflect.Person.getSex()
public void $reflect.Person.setSex(java.lang.String)
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

    System.out.println("获取定义的所有方法:");
methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}

获取定义的所有方法:
public java.lang.String $reflect.Person.toString()
private void $reflect.Person.privateMethod()
protected void $reflect.Person.protectedMethod()
public java.lang.Integer $reflect.Person.getAge()
public void $reflect.Person.setAge(java.lang.Integer)
public java.lang.String $reflect.Person.getSex()
public void $reflect.Person.setSex(java.lang.String)

执行方法:

    try {
Constructor con = clazz.getConstructor(Integer.class, String.class);
Person person = (Person)con.newInstance(10,"男");
System.out.println(person); // Person{sex='男', age=10} Method method = clazz.getMethod("getAge");
System.out.println(method.invoke(person)); // method = clazz.getMethod("setAge", Integer.class);
method.invoke(person, 18);
System.out.println(person.getAge()); //
} catch (NoSuchMethodException e) {
e.printStackTrace();
}

注意点1:观察以上输出,我们可以发现: 

  1、get Methods/Fields 能获取自身及父类的公开public修饰的方法和字段。

  2、getDeclared Methods/Fields 能自身所以修饰词的字段和方法,不能获取父类相关字段或方法。

即:通过本class的反射,不能获取父类 private/protected/default 的相关字段和方法。

      不过可以通过 clazz.getSuperClass()方法获取父类class后进行相关反射操作。

3、内省

定义:可以理解为是轻量级的反射,主要的作用是针对bean对象字段的操作

代码:

public class IntroSpectorTest {

    public static  void main(String[] args) throws Exception {
Object obj = new Person1("男",18); BeanInfo person = Introspector.getBeanInfo(Person1.class) ;
PropertyDescriptor[] pds = person.getPropertyDescriptors() ;
for (PropertyDescriptor pd : pds) {
System.out.println("\nname: "+pd.getName());
System.out.println(pd.getReadMethod());
System.out.println(pd.getWriteMethod());
System.out.println(pd.getPropertyType());
System.out.println(pd.getDisplayName());
System.out.println("Get方法invoke: "+pd.getReadMethod().invoke(obj));
}
}
} class Human1 { public Human1(){} // 父类 public 内省可以获取
public Map getMap(){
return null;
}

name: map
public java.util.Map $reflect.Human1.getMap()
null
interface java.util.Map
map
Get方法invoke: null

}
class Person1 extends Human1{ public String sex;
private Integer age;
public double high; // 内省无get、set 方法 public Person1(String sex, Integer age) {
this.sex = sex;
this.age = age;
} public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}

name: age
public java.lang.Integer $reflect.Person1.getAge()
public void $reflect.Person1.setAge(java.lang.Integer)
class java.lang.Integer
age
Get方法invoke: 18

// 没有字段也可以获取, 没有set方法
public Integer getAge1() {
return 11;
}

name: age1
public java.lang.Integer $reflect.Person1.getAge1()
null
class java.lang.Integer
age1
Get方法invoke: 11

// private 不行
private Integer getAge2() {
return 11;
}
// protected 不行
protected Integer getAge3() {
return 11;
}
// 不以get开头不行
public Integer age4() {
return 11;
}
// get大小写敏感,不行
public Integer gETAge41() {
return 11;
} // 光有set不行,必须有get
public void setAge5() {} public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}

name: sex
public java.lang.String $reflect.Person1.getSex()
public void $reflect.Person1.setSex(java.lang.String)
class java.lang.String
sex
Get方法invoke: 男

}

总结2:观察以上输出,我们可以发现: 

  1、内省是根据get方法获取字段,而非通过字段获取。

  2、对于没有get/set方法发字段,内省无法进行值的设置和获取,此时需要依赖字段反射,这也是为什么上面我说到:内省是轻量级的反射。

总结2-1源码分析,内省方法构建逻辑主要在这个方法中:

构建细节(看源码可以发现:static方法会过滤、is开头也可以是内省方法 等更多的逻辑细节):

4、修饰词:

5、class类原理(源码分析)、jvm加载类机制,反射源码分析

4、举一反三

5、总结领悟

Java基础1-反射篇的更多相关文章

  1. 黑马程序员:Java基础总结----反射

    黑马程序员:Java基础总结 反射   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...

  2. Java基础2-容器篇

    java基础2-容器篇 1.页首请关注 思维导航大纲 1.常用容器的类型层次结构 2.理解容器的常用思维大纲 a.空间 时间 concurrentModifyException 加载因子 3.常用类源 ...

  3. Java学习之反射篇

    Java学习之反射篇 0x00 前言 今天简单来记录一下,反射与注解的一些东西,反射这个机制对于后面的java反序列化漏洞研究和代码审计也是比较重要. 0x01 反射机制概述 Java反射是Java非 ...

  4. java基础(十一 )-----反射——Java高级开发必须懂的

    本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...

  5. Java基础之一反射

    反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))   一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...

  6. Java基础之多线程篇(线程创建与终止、互斥、通信、本地变量)

    线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...

  7. Java基础之—反射

    反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))   一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...

  8. JAVA基础知识|反射

    一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...

  9. java基础之反射机制

    一.概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...

  10. java基础之反射---重要

    java反射: 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)):   1:获取Class字节码文件对象的三种方式: /** ...

随机推荐

  1. Linux下open与fopen的区别

    int open(const char *path, int access,int mode)    path 要打开的文件路径和名称   access 访问模式,宏定义和含义如下:          ...

  2. mysql 连接出错 'mysqladmin flush-hosts'

    本文章 转载于: http://blog.itechol.com/space-33-do-blog-id-5670.html    求助QQ:499628121   环境说明:   内网测试服务器19 ...

  3. c#中何时使用Empty()和DefalutIfEmpty()

    在项目中,当我们想获取IEnumerable<T>集合的时候,这个集合有可能是null.但通常的做法是返回一个空的集合. 假设有这样一个场景:当商店不营业时,返回一个空的IEnumerab ...

  4. MFC中添加ToolTip提示框

    PART 1 MFC 对话框中的 Buttton添加提示 例如我们想在一个对话框中的一个button控件添加tooltip,实现的方法如下: 1. 在该对话框的类中添加一个CToolTipCtrl类型 ...

  5. VS2010 打包生成exe文件后 执行安装文件出现 TODO:&lt;文件说明&gt;已停止工作并已关闭

    一.VS2010 打包生成exe文件后  执行安装文件出现  TODO:<文件说明>已停止工作并已关闭 TODO: <文件说明>已停止工作 原因: 打包的时候在文件系统中建立了 ...

  6. C++语言笔记系列之十六——赋值兼容规则&amp;多继承的二义性

    1.赋值兼容规则 (1)派生类对象能够给基类对象赋值,这样的情况下派生类对象将从基类继承的成员的值赋值给一个基类对象:可是不同意将一个基类的对象赋值给一个派生类. (2)能够将派生类对象的地址赋给基类 ...

  7. DAHON 美国大行

    DAHON美国大行1982年创立于美国加州,多年来一直率先推动环保的代步工具——折叠自行车.创新是大行的生命,从韩氏兄弟发明了全世界第一辆小到能够放进火车座椅底下的折叠自行车起,大行就开启了不断向前的 ...

  8. 【BZOJ】【2527】【POI2011】Meteors

    整体二分+树状数组 整体二分……感谢zyf提供的入门题 简单粗暴的做法:枚举每一个国家,二分他的$w_i$,然后计算……然而这样效率很低…… 整体二分就是:对所有的国家一起进行二分,$w_i$在mid ...

  9. 第四章 四种List实现类的对比总结

    1.ArrayList 非线程安全 基于对象数组 get(int index)不需要遍历数组,速度快: iterator()方法中调用了get(int index),所以速度也快 set(int in ...

  10. 移动立方体算法(Marching cubes algorithm)

    百度百科: 医学图像三维重建的方法主要有两大类:一类是三维面绘制,另一类是三维体绘制.体绘制能够更真实地反映物体结构,但由于其运算量大,即使利用高性能的计算机也无法满足实际应用中交互操作的需要.因此, ...