理解java中反射,区别Class.forName(),Class.forName().instance() ,new,如果获取对象中的方法和字段「建议收藏」

理解java中反射,区别Class.forName(),Class.forName().instance() ,new,如果获取对象中的方法和字段「建议收藏」理解java中反射,区别Class.forName(),Class.forName().instance() ,new,如果获取对象中的方法和字段

大家好,又见面了,我是你们的朋友全栈君。

先了解一些基本的概念:运行时,编译时,编译型,解释型,类加载器,动态加载类 
什么是编译?将原程序翻译成计算机语言,就是二进制代码,在java中是将.java文件也就是源程序翻译成.class的字节码 
什么是编译时?将原程序翻译成计算机语言的过程中,将.java翻译为.class文件的过程 
什么是运行时?就是在启动这个程序的时候,在java中是,类加载器加载.class文件,并交给jvm处理 
什么是编译型语言?将原程序一次性全部转换为二进制代码,然后执行程序 
什么是解释型语言?转换一句,执行一句,java是既编译又解释的语言 
编译型语言和解释型语言的区别:编译型语言效率高,依赖于编译器,但是跨平台差,解释型的效率低,依赖于解释器,但跨平台强 
什么是类加载器?类加载器就是JVM中的类装载器,作用就是将编译好的.class字节码运到检查器进行安全检查的,检查通过后开始解释执行 
什么是运行时动态加载类? 
反射就是可以将一个程序(类)在运行的时候获得该程序(类)的信息的机制,也就是获得在编译期不可能获得的类的信息,因为这些信息是保存在Class对象中的,而这个Class对象是在程序运行时动态加载的 
它 就是可以在程序运行的时候动态装载类,查看类的信息,生成对象,或操作生成对象。类在运行的时候,可以得到该类的信息,并且 可以动态的修改这些信息。class对象是在运行的时候产生的,通过class对象操作类的信息是在运行时进行的,当运行 程序的时候,类加载器会加载真正需要的类,什么是真正需要的呢?就是该类真正起作用,如:有该类的对象实例,或该类调用了静态方法属性等 

那么如何实现反射呢?

要正确使用Java反射机制就得使用java.lang.Class这个类。它是Java反射机制的起源。当一个类被加载以后,Java虚拟机就会自动产 生一个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息。 三种方式得到Class对象: 

1.调用对象的getClass方法,返回该对象的Class对象。

2.Class.forName(“类的完整名字”);可以在类不确定的情况下实例化Class,最灵活。

3.Class c=类名.class 

举例说明吧:

package test;
/**
 * 
 * @author liuxin
 * @date   2018年8月22日
 */
public class A {
	
	private String name="ees";
	
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public A (){
		System.out.println("默认构造方法执行了");
	}
	
	static{
		System.out.println("执行静态代码块");
	}
	
	{System.out.println("执行非静态代码块");}
	

}

测试类:

package test;
/**
 * 
 * @author liuxin
 * @date   2018年8月22日
 */
public class Test {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		// TODO Auto-generated method stub
		A a=new A();
		System.out.println(a.getClass());
		System.out.println(Class.forName("test.A"));
		System.out.println(A.class);
	}
}

上面依次是三种得到class对象对象的方式:

执行结果:

执行静态代码块
执行非静态代码块
默认构造方法执行了
class test.A
class test.A
class test.A

这里要注意是先执行非静态代码块,再执行默认构造方法。

—————————————————————————————————————————————————–

下面我们回过头看class.forName()方法,这个方法提供了两个重载方法

先看第一个:

package test;
/**
 * 
 * @author liuxin
 * @date   2018年8月22日
 */
public class Test {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		// TODO Auto-generated method stub
//		A a=new A();
//		System.out.println(a.getClass());
//		System.out.println(Class.forName("test.A"));
//		System.out.println(A.class);
		
//		Class c=Class.forName("test.A");
		
		
		Class c=Class.forName("test.A",false,A.class.getClassLoader());
	}
}

true:是否实例化该类,也就是说实际上调用Class.forName(“类的完整名字”)加载类时执行初始化

this.getClass().getClassLoader()调用类加载器

上面forName第二个参数是false,因此,不会实例化,因此上面没有任何出入结果,这个例子证实了先执行类加载器,再执行静态方法块。

把false改成true,就会有输出结果:

执行静态代码块

再看第二个forname重载方法:

package test;
/**
 * 
 * @author liuxin
 * @date   2018年8月22日
 */
public class Test {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		// TODO Auto-generated method stub
//		A a=new A();
//		System.out.println(a.getClass());
//		System.out.println(Class.forName("test.A"));
//		System.out.println(A.class);
		
//		Class c=Class.forName("test.A",true,A.class.getClassLoader());
		
		Class c=Class.forName("test.A");
	}
}

这个结果就跟上面一样了,

执行静态代码块

可是上面的实例化的对象是个class,并没有准确到一个确切对象,那么怎么使用forName来创建呢?

package test;
/**
 * 
 * @author liuxin
 * @date   2018年8月22日
 */
public class Test {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		// TODO Auto-generated method stub
//		A a=new A();
//		System.out.println(a.getClass());
//		System.out.println(Class.forName("test.A"));
//		System.out.println(A.class);
		
//		Class c=Class.forName("test.A",true,A.class.getClassLoader());
		
//		Class c=Class.forName("test.A");
		A a= (A) Class.forName("test.A").newInstance();
		System.out.println(a.getName());
	}
}

结果:

执行静态代码块
执行非静态代码块
默认构造方法执行了
ees

需要补充的是:Class.forName(“完整类名”).newInstance();的用法相当于直接new();

—————————————————————————————————————————————————————————–

这里证实一个类再类加载中只加载一次:

package test;
/**
 * 
 * @author liuxin
 * @date   2018年8月22日
 */
public class Test {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		// TODO Auto-generated method stub
		A a1=new A();
		A a2=new A();
//		System.out.println(a.getClass());
//		System.out.println(Class.forName("test.A"));
//		System.out.println(A.class);
		
//		Class c=Class.forName("test.A",true,A.class.getClassLoader());
		
//		Class c=Class.forName("test.A");
		A a= (A) Class.forName("test.A").newInstance();
		
		System.out.println(a.getName());
	}
}

结果:

执行静态代码块
执行非静态代码块
默认构造方法执行了
执行非静态代码块
默认构造方法执行了
执行非静态代码块
默认构造方法执行了
ees

这里相当于new了3次 ,但是只执行了一次静态代码块。

 

——————————————————————————————————————————————————————————

下面通过反射获取类中的方法、字段等属性:

package test;

import java.lang.reflect.Method;

import org.apache.tools.ant.types.CommandlineJava.SysProperties;

/**
 * 
 * @author liuxin
 * @date   2018年8月22日
 */
public class Test {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		// TODO Auto-generated method stub
//		A a1=new A();
//		System.out.println(a.getClass());
//		System.out.println(Class.forName("test.A"));
//		System.out.println(A.class);
//		Class c=Class.forName("test.A");
//		A a= (A) Class.forName("test.A").newInstance();
		
		
		Class c=Class.forName("test.A",true,A.class.getClassLoader());
		Method[] methods=c.getMethods();
		for(Method m:methods){
			System.out.println(m);
		}
	}
}

结果:

执行静态代码块
public java.lang.String test.A.getName()
public void test.A.setName(java.lang.String)
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 java.lang.String java.lang.Object.toString()
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()

同理,还有获取所有字段的方法:

Field[] fields=c.getDeclaredFields();
		for(Field f:fields){
			System.out.println(f);
		}

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/106036.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • unix命令之xargs[通俗易懂]

    unix命令之xargs[通俗易懂]unix命令之xargs,与"|"配合的神奇命令

  • FastAI 课程学习笔记 lesson 1:宠物图片分类

    FastAI 课程学习笔记 lesson 1:宠物图片分类文章目录代码解析神奇的”%”导入fastAI库下载解压数据集untar_data获取帮助文档help()???doc设置路径get_image_filesImageDataBunchfrom_name_regrep命令检验正则表达式pythonre检验正则表达式代码解析神奇的”%”%reload_extautoreload%autoreload2%matplotlibinli…

  • 6688常见问题FAQ

    6688常见问题FAQ1、V-KLAY问题2、关于备份3、关于驱动问题、联机问题4、有关打补丁,刷机,升级5、JAVA使用问题6、解锁问题7、无网络问题8、铃声问题9、重要记事问题10、时间调整、自动开关机问题11、通讯录丢失问题12、wap上网13、有关工模(工程模式)6688常见问题FAQ:本帖最后由胡同印象于2006-10-2711:23编辑原文网址:http://bbs.0110.cn/threa

  • Editormd的使用——在线编辑和查看文章

    Editormd的使用——在线编辑和查看文章使用Editormd可以方便地在界面上嵌入markdown编辑器,并能够实时预览。先看一下实现效果:编辑文章界面:展示文章界面:用法:首先,到https://pandao.github.io/editor.md/下载Editormd的压缩包,解压到自己的静态资源文件夹下。第二步,引入必要的文件: <linkrel=”stylesheet”href=”/resource/assets/editormd/css/editormd.css”/><linkrel=

  • 2022.01idea激活码[最新免费获取]

    (2022.01idea激活码)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

  • Java异常类型及处理

    Java异常类型及处理前言:Java异常,大家都很熟悉。但是对于具体怎么分类的,JVM对其怎么处理的,代码中怎么处理的,应该怎么使用,底层怎么实现的等等,可能就会有些不是那么清晰。本文基于此详细捋一下异常类型,实现以及使用时应怎么注意。一、异常实现及分类1.先看下异常类的结构图上图可以简单展示一下异常类实现结构图,当然上图不是所有的异常,用户自己也可以自定义异常实现。上图已经足够帮我们解释和理解异常…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号