Java反射是什么?看这篇绝对会了!(1)

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

基本的 Java类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。Class 没有公共构造方法。

Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

Person p1 = new Person();

//下面的这三种方式都可以得到字节码

CLass c1 = Date.class();

p1.getClass();

//若存在则加载,否则新建,往往使用第三种,类的名字在写源程序时不需要知道,到运行时再传递过来

Class.forName(“java.lang.String”);

Class.forName()字节码已经加载到java虚拟机中,去得到字节码;java虚拟机中还没有生成字节码 用类加载器进行加载,加载的字节码缓冲到虚拟机中。

考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。

import java.lang.reflect.*;

public class DumpMethods {

public static void main(String args[]) {

try {

Class c = Class.forName(“java.util.Stack”);

Method m[] = c.getDeclaredMethods();

for (int i = 0; i < m.length; i++)

System.out.println(m[i].toString());

}

catch (Throwable e){

System.err.println(e);

}

}

}

public synchronized java.lang.Object java.util.Stack.pop()

public java.lang.Object java.util.Stack.push(java.lang.Object)

public boolean java.util.Stack.empty()

public synchronized java.lang.Object java.util.Stack.peek()

public synchronized int java.util.Stack.search(java.lang.Object)

这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。这个程序使用Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。

以下示例使用 Class 对象来显示对象的类名:

void printClassName(Object obj) {

System.out.println("The class of " + obj +

" is " + obj.getClass().getName());

}

还可以使用一个类字面值(JLS Section 15.8.2)来获取指定类型(或 void)的 Class 对象。例如:

System.out.println("The name of class Foo is: "+Foo.class.getName());

在没有对象实例的时候,主要有两种办法。

//获得类类型的两种方式

Class cls1 = Role.class;

Class cls2 = Class.forName(“yui.Role”);

注意第二种方式中,forName中的参数一定是完整的类名(包名+类名),并且这个方法需要捕获异常。现在得到cls1就可以创建一个Role类的实例了,利用Class的newInstance方法相当于调用类的默认的构造器。

Object o = cls1.newInstance();

//创建一个实例

//Object o1 = new Role();   //与上面的方法等价

二.常用方法


1.isPrimitive(判断是否是基本类型的字节码)

public class TestReflect {

public static void main(String[] args) {

// TODO Auto-generated method stub

String str = “abc”;

Class cls1 = str.getClass();

Class cls2 = String.class;

Class cls3 = null;//必须要加上null

try {

cls3 = Class.forName(“java.lang.String”);

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(cls1==cls2);

System.out.println(cls1==cls3);

System.out.println(cls1.isPrimitive());

System.out.println(int.class.isPrimitive());//判定指定的 Class 对象是否表示一个基本类型。

System.out.println(int.class == Integer.class);

System.out.println(int.class == Integer.TYPE);

System.out.println(int[].class.isPrimitive());

System.out.println(int[].class.isArray());

}

}

结果:

true

true

false

true

false

true

false

true

2.getConstructor和getConstructors()

java中构造方法没有先后顺序,通过类型和参数个数区分。

public class TestReflect {

public static void main(String[] args) throws SecurityException, NoSuchMethodException {

// TODO Auto-generated method stub

String str = “abc”;

System.out.println(String.class.getConstructor(StringBuffer.class));

}

}

3.Filed类代表某一类中的一个成员变量。

import java.lang.reflect.Field;

public class TestReflect {

public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {

ReflectPointer rp1 = new ReflectPointer(3,4);

Field fieldx = rp1.getClass().getField(“x”);//必须是x或者y

System.out.println(fieldx.get(rp1));

/*

* private的成员变量必须使用getDeclaredField,并setAccessible(true),否则看得到拿不到

*/

Field fieldy = rp1.getClass().getDeclaredField(“y”);

fieldy.setAccessible(true);//暴力反射

System.out.println(fieldy.get(rp1));

}

}

class ReflectPointer {

public int x = 0;

private int y = 0;

public ReflectPointer(int x,int y) {//alt + shift +s相当于右键source

super();

// TODO Auto-generated constructor stub

this.x = x;

this.y = y;

}

}

三.典型例题


1.将所有String类型的成员变量里的b改成a。

import java.lang.reflect.Field;

public class TestReflect {

public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {

ReflectPointer rp1 = new ReflectPointer(3,4);

changeBtoA(rp1);

System.out.println(rp1);

}

private static void changeBtoA(Object obj) throws RuntimeException, Exception {

Field[] fields = obj.getClass().getFields();

for(Field field : fields) {

//if(field.getType().equals(String.class))

//由于字节码只有一份,用equals语义不准确

if(field.getType()==String.class) {

String oldValue = (String)field.get(obj);

String newValue = oldValue.replace(‘b’, ‘a’);

field.set(obj,newValue);

}

}

}

}

class ReflectPointer {

private int x = 0;

public int y = 0;

public String str1 = “ball”;

public String str2 = “basketball”;

public String str3 = “itcat”;

public ReflectPointer(int x,int y) {//alt + shift +s相当于右键source

super();

// TODO Auto-generated constructor stub

this.x = x;

this.y = y;

}

@Override

public String toString() {

return “ReflectPointer [str1=” + str1 + “, str2=” + str2 + “, str3=”

+ str3 + “]”;

}

}

2.写一个程序根据用户提供的类名,调用该类的里的main方法。

为什么要用反射的方式呢?

import java.lang.reflect.Field;

import java.lang.reflect.Method;

public class TestReflect {

public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {

String str = args[0];

/*

* 这样会数组角标越界,因为压根没有这个字符数组

* 需要右键在run as-configurations-arguments里输入b.Inter(完整类名)

*

*/

Method m = Class.forName(str).getMethod(“main”,String[].class);

//下面这两种方式都可以,main方法需要一个参数

m.invoke(null, new Object[]{new String[]{“111”,“222”,“333”}});

m.invoke(null, (Object)new String[]{“111”,“222”,“333”});//这个可以说明,数组也是Object

/*

* m.invoke(null, new String[]{“111”,“222”,“333”})

* 上面的不可以,因为java会自动拆包

*/

}

}

class Inter {

public static void main(String[] args) {

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
**

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-RzjXTdfa-1715725057192)]

[外链图片转存中…(img-wSjol7MK-1715725057192)]

[外链图片转存中…(img-xO8sfCVc-1715725057192)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值