理解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)


相关推荐

  • Mac 破解zip压缩文件密码详解

    Mac 破解zip压缩文件密码详解使用fcrackzip来破解zip类型压缩文件fcrackzip是一款专门破解zip类型压缩文件密码的工具,工具破解速度还是可以的,能用字典和指定字符集破解,适用于Linux、MacOS系统。如果你的电脑没有安装brew,需要执行下面命令行/usr/bin/ruby-e"$(curl-fsSLhttps://raw.githubusercontent.com/Homebr…

  • 发html邮件乱码 java,Java发送邮件时标题和发件人乱码

    发html邮件乱码 java,Java发送邮件时标题和发件人乱码#Java发送邮件时标题和发件人乱码最近碰到一个问题,Java发送邮件时,查看邮箱结果,发件人及邮件标题正文全部乱码通过翻阅资料,原因及解决方法如下:“`//SetSubject:头字段message.setSubject(MimeUtility.encodeText(mail,MimeUtility.mimeCharset(“gb2312”),null));//设置邮件发送日期m…

  • 最强大的疯狂java学习路线图,java学习者必看「建议收藏」

    最强大的疯狂java学习路线图,java学习者必看「建议收藏」双击有图片放大效果

  • 2D网络游戏(2d网络游戏大全列表)

    2D网络游戏开发(网络篇)(一) 作者:akinggw “2D网游开发”,我有时都觉得这个标题包含的内容太多,要实现起来也太难。于是,我决定将它分门别类,我按照我要实现的一个网络游戏将它分成下面几个部分: l      客户端l      网络端l      服务器端l      网页端 我们来讲解一下,我们分别要在每个端口完成什么内容: 

  • pycharm如何配置_网络配置异常怎么修复

    pycharm如何配置_网络配置异常怎么修复PyCharm配置示例1、全局设置:这里是全局设置,也可在每个项目里面单独设置点击右下角的Configure选择Preferences1、设置背景颜色与显示内存大小:2、设置不默认打开上次的工程3、设置显示方法右边分割线:4、设置自动引包:5、设置显示方法缩进线6、设置字体与字体大小:7、设置文件编码格式:请注意,这一步很重要,不要坑队友!8、测试本机是…

  • 贪心算法之背包问题

    贪心算法之背包问题

发表回复

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

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