java反射(三)--反射与操作类
一.反射与操作类
在反射机制的处理过程之中不仅仅只是一个实例化对象的处理操作,更多的情况下还有类的组成的操作,任何一个类的基本组成结构:父类(父接口),包,属性,方法(构造方法,普通方法)
--获取类的基本信息
一个类的基本信息主要包括的是所在的包名称,父类的定义,父接口的定义.
--范例:定义一个程序类
package 反射.反射与操作类; /**
* @author : S K Y
* @version :0.0.1
*/
public interface IMessageStrvice { //消息服务
void send();
}
package 反射.反射与操作类; /**
* @author : S K Y
* @version :0.0.1
*/
public interface IChannelService {
boolean connect();
}
package 反射.反射与操作类; /**
* @author : S K Y
* @version :0.0.1
*/
public class AbstractBase {
}
package 反射.反射与操作类; /**
* @author : S K Y
* @version :0.0.1
*/
public class Person extends AbstractBase implements IMessageStrvice, IChannelService {
@Override
public boolean connect() {
return true;
} @Override
public void send() {
if (this.connect()) {
System.out.println("消息发送");
}
}
}
--如果此时要想获取一些类的基础信息则可以通过class类中的如下方法:
获取包名称: public Package getPackage()
获取继承父类: public Class<? super T> getClass();
获取实现父接口: public Class<?>[] getInterfaces()
public class PersonDemo {
public static void main(String[] args) {
Class<Person> personClass = Person.class; //获取指定类的class对象
Package aPackage = personClass.getPackage(); //获取指定类的包定义
System.out.println("获取包名称: " + aPackage.getName());
Class<? super Person> superclass = personClass.getSuperclass(); //获取父类
System.out.println("Person获取父类: " + superclass.getName()) ;
System.out.println("superclass获取父类: " + superclass.getSuperclass().getName());
Class<?>[] interfaces = personClass.getInterfaces(); //获取父接口
for (int i = 0; i < interfaces.length; i++) {
System.out.println("获取父接口" + (i + 1) + ": " + interfaces[i].getName());
}
}
}
--运行结果
获取包名称: 反射.反射与操作类
Person获取父类: 反射.反射与操作类.AbstractBase
superclass获取父类: java.lang.Object
获取父接口1: 反射.反射与操作类.IMessageStrvice
获取父接口2: 反射.反射与操作类.IChannelService Process finished with exit code 0
-获取一个类的Class对象之后就以为这这个对象可以获取类之中的一切继承结构信息,因此我们可以知道Class可以描述普通类,抽象类,接口
二.反射调用构造方法
在一个类之中除了有继承的关系之外,最为重要的操作就是类中的结构处理了,类中的中首先需要关注的就是构造方法的使用问题,实际上在之前通过反射实例化对象的使用就已经接触到了构造方法的问题了,及newInstance()方法,所有类的构造方法的获取都可以直接通过Class类来完成,该类中定义有如下的几个方法:
获取指定构造方法(根据参数类型): Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
获取所有构造方法: Constructor<?>[] getDeclaredConstructors()
获取所有构造方法: Constructor<?>[] getConstructors()
获取指定构造方法: Constructor<T> getConstructor(Class<?>... parameterTypes)
package 反射.反射与操作类; /**
* @author : S K Y
* @version :0.0.1
*/
public class AbstractBase {
public AbstractBase(){}
public AbstractBase(String name){}
}
--修改Person类的定义
package 反射.反射与操作类; /**
* @author : S K Y
* @version :0.0.1
*/
public class Person extends AbstractBase implements IMessageStrvice, IChannelService {
public Person() {
} public Person(String name, int age) {
} @Override
public boolean connect() {
return true;
} @Override
public void send() {
if (this.connect()) {
System.out.println("消息发送");
}
}
}
--范例:获取全部构造方法
class ConstructorDemo{
public static void main(String[] args) {
Class<Person> personClass = Person.class; //获取指定类的class对象
Constructor<?>[] constructors = personClass.getDeclaredConstructors(); //获取全部构造
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("========================");
constructors = personClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
}
}
--运行结果
public 反射.反射与操作类.Person()
public 反射.反射与操作类.Person(java.lang.String,int)
========================
public 反射.反射与操作类.Person()
public 反射.反射与操作类.Person(java.lang.String,int) Process finished with exit code 0
--此时获取的是类之中的全部构造方法,但是也可以获取一个指定参数的构造
package 反射.反射与操作类; /**
* @author : S K Y
* @version :0.0.1
*/
public class Person extends AbstractBase implements IMessageStrvice, IChannelService {
private String name;
private int age;
public Person() {
} public Person(String name, int age) {
this.name = name;
this.age = age;
} @Override
public boolean connect() {
return true;
} @Override
public void send() {
if (this.connect()) {
System.out.println("消息发送");
}
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
--需要调用类的有参构造方法,那么我们应该传入参数,观察java.lang.reflect.Constructor类的方法
实例化方法: public T newInstance(Object... initargs)throws InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException
--范例:调用指定构造实例化对象
class OneConstructorDemo {
public static void main(String[] args) throws Exception {
Class<Person> personClass = Person.class; //获取指定类的class对象
Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
Person person = constructor.newInstance("张三", 56);
System.out.println(person);
}
}
--运行结果
Person{name='张三', age=56} Process finished with exit code 0
--虽然程序代码本身允许开发者调用有参构造处理,但是如果从实际开发来讲,所有的类中最好提供有无参构造(特别是使用反射的类中),这样的实例化能够达到很高的统一性
--我们观察Constructor类的结构发现在JDK1.8之后提供了一个Executable类作为Constructor类的父类对象
三.反射调用普通方法
在进行反射处理的时候,也可以通过反射获取类中的全部方法,但是需要提醒的是,如果要想通过反射调用这些方法,必须有一个前提条件,类之中要提供有实例化对象
--在Class类中提供有如下的操作可以获取方法对象:
获取全部方法: public Method[] getMethods()throws SecurityException
获取指定方法: Method getMethod(String name, Class<?>... parameterTypes)
获取本类全部方法:Method[] getDeclaredMethods()
获取本类指定方法: Method getDeclaredMethod(String name, Class<?>... parameterTypes)
--范例:获取全部方法
class MethodDemo{
public static void main(String[] args) {
Class<Person> personClass = Person.class; //获取指定类的class对象
{ //获取全部方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
}
--运行结果
public java.lang.String 反射.反射与操作类.Person.toString()
public boolean 反射.反射与操作类.Person.connect()
public void 反射.反射与操作类.Person.send()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
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 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() Process finished with exit code 0
--可以发现将父类Object中的方法也获取到了,如果只是想获取本地的方法
class MethodDemo{
public static void main(String[] args) {
Class<Person> personClass = Person.class; //获取指定类的class对象
{ //获取全部方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
System.out.println("=========================");
{ //获取全部方法
Method[] methods = personClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
}
--运行结果
public java.lang.String 反射.反射与操作类.Person.toString()
public boolean 反射.反射与操作类.Person.connect()
public void 反射.反射与操作类.Person.send()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
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 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()
=========================
public java.lang.String 反射.反射与操作类.Person.toString()
public boolean 反射.反射与操作类.Person.connect()
public void 反射.反射与操作类.Person.send() Process finished with exit code 0
--但是需要注意的是这个时候的方法信息的获取时依靠Method类提供的toString()方法来完成的,很多时候也可以由用户自己拼凑方法的输出
class MyMethodDemo {
public static void main(String[] args) {
Class<Person> personClass = Person.class; //获取指定类的class对象
Method[] methods = personClass.getMethods();
for (Method method : methods) {
String modifier = Modifier.toString(method.getModifiers());//获取访问修饰符
String returnType = method.getReturnType().getName(); //获取方法的返回类型
Class<?>[] parameterTypes = method.getParameterTypes(); //获取参数类型
StringBuffer buffer = new StringBuffer();
buffer.append("(");
for (int i = 0; i < parameterTypes.length; i++) {
buffer.append(parameterTypes[i].getName());
buffer.append(" arg").append(i);
if (i < parameterTypes.length - 1) {
buffer.append(",");
}
}
buffer.append(")");
String parameterType = buffer.toString();
Class<?>[] exceptionTypes = method.getExceptionTypes(); //获取异常类型
buffer = new StringBuffer();
if (exceptionTypes.length > 0) {
buffer.append(" throws ");
for (int i = 0; i < exceptionTypes.length; i++) {
buffer.append(exceptionTypes[i].getName());
buffer.append(" e").append(i);
if (i < exceptionTypes.length - 1) {
buffer.append(",");
}
}
}
String exceptionType = buffer.toString();
System.out.println(modifier + " " + returnType + " " + method.getName() + parameterType + "" + exceptionType);
}
}
}
--运行结果
public java.lang.String toString()
public boolean connect()
public void send()
public final void wait() throws java.lang.InterruptedException e0
public final void wait(long arg0,int arg1) throws java.lang.InterruptedException e0
public final native void wait(long arg0) throws java.lang.InterruptedException e0
public boolean equals(java.lang.Object arg0)
public native int hashCode()
public final native java.lang.Class getClass()
public final native void notify()
public final native void notifyAll() Process finished with exit code 0
--在Method类中有一个重要的方法: public Object invoke(Object obj,Object... args)throws IllegalAccessException,IllegalArgumentException,InvocationTargetException,用于反射调用方法,在Person类中有name属性追加有setter与getter方法:
package 反射.反射与操作类; /**
* @author : S K Y
* @version :0.0.1
*/
public class Person extends AbstractBase implements IMessageStrvice, IChannelService {
private String name;
private int age;
public Person() {
} public Person(String name, int age) {
this.name = name;
this.age = age;
} @Override
public boolean connect() {
return true;
} @Override
public void send() {
if (this.connect()) {
System.out.println("消息发送");
}
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
--通过反射机制来实现person类之中的setter与getter方法的调用处理,并且不进行person类的包导入操作
class GetterAndSetterDemo {
public static void main(String[] args) throws Exception {
//在不导入开发包的情况下实现属性的配置
Class<?> aClass = Class.forName("反射.反射与操作类.Person");//获取指定类的class对象
String attribute = "name"; //要操作的类属性
String value = "张三"; //要设置的属性内容
//1.任何情况写想要调用类中的属性或者调用类中的方法都必须保证存在有实例化对象
Object obj = aClass.newInstance(); //调用无参构造实例化
//2.如果想要进行方法的调用,一定要获取方法的名称
String setMethodName = "setName";
Method method = aClass.getDeclaredMethod(setMethodName, String.class);
method.invoke(obj, value); //等价于 person.setName("小强");
System.out.println("toString: " + obj);
String getMethodName = "getName";
Method getName = aClass.getDeclaredMethod(getMethodName);
System.out.println("getName: " + getName.invoke(obj)); //等价于 person.getName();
}
}
--运行结果
toString: Person{name='张三', age=0}
getName: 张三 Process finished with exit code 0
--利用此类操作整体的形式不会有任何的明确的类对象产生,这样的处理避免了某一个类的耦合问题.
四.反射调用成员
类结构之中的最后一个核心的组成就是成员(Field),大部分情况下都会将其称为成员属性,对成员属性的获取也是通过Class类来完成的,在这个类中提供有如下两组操作方法:
获取本类全部成员: Field[] getDeclaredFields()
获取本类指定成员: Field getDeclaredField(String name)
获取父类全部成员: Field[] getFields()
获取父类指定成员: Field getField(String name)
--修改AbstractBase类
package 反射.反射与操作类; /**
* @author : S K Y
* @version :0.0.1
*/
public class AbstractBase {
public static final String BASE = "123456789";
private String info = "hello world";
protected static final String ABC = "888";
public AbstractBase() {
} public AbstractBase(String name) {
}
}
package 反射.反射与操作类; /**
* @author : S K Y
* @version :0.0.1
*/
public class Person extends AbstractBase implements IMessageStrvice, IChannelService {
public static final String NAME = "小张三";
private String name;
private int age;
public Person() {
} public Person(String name, int age) {
this.name = name;
this.age = age;
} @Override
public boolean connect() {
return true;
} @Override
public void send() {
if (this.connect()) {
System.out.println("消息发送");
}
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
--范例:获取类中的成员
class GetFieldDemo{
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("反射.反射与操作类.Person");//获取指定类的class对象
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("======================");
fields = aClass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
--运行结果
public static final java.lang.String 反射.反射与操作类.Person.NAME
public static final java.lang.String 反射.反射与操作类.AbstractBase.BASE
======================
public static final java.lang.String 反射.反射与操作类.Person.NAME
private java.lang.String 反射.反射与操作类.Person.name
private int 反射.反射与操作类.Person.age Process finished with exit code 0
--从上述结果我们可以得知getFields()可以获得父类及子类的公有成员,而getDeclaredFields()可以获得子类的所有成员,但是在Field类中最为重要的操作形式并不是获取全部的成员,而是如下的三个方法:
设置属性内容: public void set(Object obj,Object value)throws IllegalArgumentException,IllegalAccessException
获取属性内容: public Object get(Object obj)throws IllegalArgumentException,IllegalAccessException
解除封装: public static void setAccessible(AccessibleObject[] array,boolean flag)throws SecurityException
所有的成员都是在对象实例化之后进行空间分配的,所以此时一定要先有实例化对象之后,才可以进行成员的操作.
--范例:直接调用person类中的name私有成员:
class UseNameDemo{
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("反射.反射与操作类.Person");//获取指定类的class对象
Object obj = aClass.getConstructor().newInstance();
Field name = aClass.getDeclaredField("name");
name.setAccessible(true); //解除封装
name.set(obj,"张三");
System.out.println(name.get(obj));
}
}
--运行结果
张三 Process finished with exit code 0
--通过一系列的分析可以发现,类之中的构造方法,成员属性都可以通过反射实现调用,但是对于成员的反射调用很少这样直接处理,大部分操作都应该通过getter和setter处理,所以对于以上的代码只是能够说明反射具有这样的能力,而对于Field类在实际的开发之中只有一个方法最为常用:
获取成员类型: public Class<?> getType()
--范例:获取Person类中的name成员的类型
class UseNameDemo{
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("反射.反射与操作类.Person");//获取指定类的class对象
Object obj = aClass.getConstructor().newInstance();
Field name = aClass.getDeclaredField("name");
System.out.println(name.getType().getName()); //获取完整类名称
System.out.println(name.getType().getSimpleName());
}
}
--运行结果
java.lang.String
String Process finished with exit code 0
--在开发中进行反射处理的时候,往往会利用Field与Method类实现类中的setter方法的调用.
五.Unsafe工具类
反射是java的第一大特点,一旦打开了反射的大门,就可以有更加丰富的类的设计形式,除了JVM本身支持的反射处理之外,在java里面也提供有一个Unsafe(不安全操作),这个类的主要特点是可以利用反射来获取对象,并且直接使用底层的c++来代替JVM执行,即可以绕过JVM的相关的对象的管理机制,如果项目中使用了Unsafe类,那么项目之中将无法进行JVM的内存管理机制以及垃圾回收处理.
--如果要想使用Unsafe类首先就需要确认一下这个类之中定义的构造方法与常量问题
构造方法: private Unsafe(){}
私有常量: private static final Unsafe theUnsafe;
但是需要注意的是在这个Unsafe的类中并没有提供static的方法,即不能通过类似与传统的单例设计模式中提供的样式进行操作,如果要想获得这个类的对象,就必须利用反射机制来完成:
class GetUnsafeDemo{
public static void main(String[] args) throws Exception{
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true); //解除封装处理
Unsafe unsafe = (Unsafe) theUnsafe.get(null); //static属性不需要传递实例化对象
}
}
--在传统的开发之中,一个程序类必须要通过实例化对象后,才可以调用类中的普通方法,尤其以单例设计模式为例:
class Singleton {
private static final Singleton INSTANCE = new Singleton(); private Singleton() {
} public static Singleton getInstance() {
return INSTANCE;
} public void print() {
System.out.println("实例化对象输出内容");
}
}
--利用Unsafe类绕过JVM的管理机制使用print()方法:
class GetUnsafeDemo {
public static void main(String[] args) throws Exception {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true); //解除封装处理
Unsafe unsafe = (Unsafe) theUnsafe.get(null); //static属性不需要传递实例化对象
Singleton singleton = (Singleton) unsafe.allocateInstance(Singleton.class);
singleton.print();
}
} class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton(){
System.out.println("构造方法");
}
public void print() {
System.out.println("实例化对象输出内容");
}
}
--运行结果
构造方法
实例化对象输出内容 Process finished with exit code 0
--Uusafe只能说为开发提供了一些更加方便的处理机制,但是这种操作由于不受JVM的管理所以如果不是必须的情况下不建议使用
java反射(三)--反射与操作类的更多相关文章
- java学习笔记07--日期操作类
java学习笔记07--日期操作类 一.Date类 在java.util包中定义了Date类,Date类本身使用非常简单,直接输出其实例化对象即可. public class T { public ...
- JAVA中的集合容器操作类
目录 JAVA中的集合容器操作类 List集合 ArrayList的操作方法说明 LinkedList Stack Set Map Queue 总结 JAVA中的集合容器操作类 Java容器类库总共分 ...
- “全栈2019”Java第三十八章:类与方法
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第三十七章:类与字段
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- java基础(三):反射、反序列化破解单列模式和解决方式
单例模式指的是一个类只有一个对象,通过一些措施达到达到这个目的.但是反射和反序列化可以获得多个不同的对象. 先简单的认识一下单例模式 一:单例模式 通过私有构造器,声明一个该类的静态对象成员,提供一个 ...
- java学习笔记——大数据操作类
java.math包中提供了两个大数字操作类:BigInteger(大整数操作类) BigDecimal(大小数操作类). 大整数操作类:BigInteger BigInteger类构造方法:publ ...
- Java IO编程——File文件操作类
在Java语言里面提供有对于文件操作系统操作的支持,而这个支持就在java.io.File类中进行了定义,也就是说在整个java.io包里面,File类是唯一 一个与文件本身操作(创建.删除.重命名等 ...
- JAVA多线程提高五:原子性操作类的应用
当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可能i不等于3,而是等于2.因为A和B线程在更新变量i ...
- JAVA多线程学习九-原子性操作类的应用
当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可能i不等于3,而是等于2.因为A和B线程在更新变量i ...
随机推荐
- DevExpress 控件中设置分隔符
原文:DevExpress 控件中设置分隔符 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net ...
- sql插入语句笔记
使用INSERT插入数据行 [一次插入一行数据] 全写: INSERT INTO renshi (name, sex, age ,tel) VALUES ('胡大姐','女','35','13 ...
- 机器学习-线性回归补充-R^
线性回归算法在选自变量会遇到两个问题:一是去掉多重共线性干扰,二是选择最优自变量组合. 线性回归步骤 1.选择自变量 注意点 去掉多重共线性干扰,选择最优自变量组合.这里需要理解决定系数:R^.它是理 ...
- python常用函数 P
popleft(iterable) 对应pop,左侧弹出,队列适用. 例子: permutations(iterable, int) itertools的permutations方法可以产生集合的所有 ...
- BZOJ 2141 排队 (CDQ分治)
[BZOJ2141]排队 这道题和动态逆序对比较像(BZOJ-3295 没做过的同学建议先做这题),只是删除操作变成了交换.解法:交换操作可以变成删除加插入操作,那么这题就变成了 (时间,位置,值)的 ...
- java使用对象类型作为方法的参数
- 罗技K380使用手册
Ipad最佳伴侣|码字神器|罗技K380|附使用指南 ———— 为了方便平时在家处理工作➕写小红书笔记,年初买了个Ipad2018 我以前买过一个罗技的K480,因为太重了不方便携带,于是又入了K38 ...
- center os7 安装mysql
安装mariadb MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可.开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将MySQL闭源的潜在风险, ...
- HTML5 arc的例子
demo.html <!DOCTYPE html> <html lang="zh"> <head> <meta charset=" ...
- centos7在线安装mysql8.0.16
一.官网复制安装源地址: 1.进入官网地址:https://dev.mysql.com/downloads/repo/yum/ 二.进入/usr/local目录下 ,创建mysql文件夹 三.使用命令 ...