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

 

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 编程珠玑笔记(第4章):编写正确的程序

    编程珠玑笔记(第4章):编写正确的程序

    2021年8月26日
    60
  • GPU利用率低的解决办法

    GPU利用率低的解决办法watch-n0.1-dnvidia-smi#检查GPU利用率参数解决办法:1.dataloader设置参数2.增大batchsize3.减少IO操作,比如tensorboard的写入和打印。4.换显卡

    2022年6月30日
    146
  • 行为树

    行为树行为树常被用来实现游戏中的AI。每次执行AI,都会从根节点遍历整个树,父节点执行子节点,子节点执行完后将结果返回父节点。下面是基本的四个节点:1*顺序节点(Sequence):属于组合节点,顺序执行

    2022年8月1日
    4
  • bool类型_bool类型什么为真

    bool类型_bool类型什么为真转自:http://www.vcgood.com/archives/3709我们知道在C++里有专门的bool类型,用来表示真或假。但是在C语言里没有这样的类型(至少我是一直这么认为的),表达式的值0

    2022年8月5日
    3
  • 杭电OJ2058_杭电OJ

    杭电OJ2058_杭电OJ杭电OJ2058我写的超时了下面是不超时的#include<stdio.h>#include<math.h>intmain(){ intn,m,i,j; while(scanf(“%d%d”,&n,&m)!=EOF){ if(n==0&&m==0) break; for(j=(int)sqrt((double)(2*m));j>=1;j–){ i=(

    2022年10月2日
    0
  • cas 原理分析

    cas 原理分析CAS原理分析1、了解java中锁的类型1.1悲观锁(PessimisticLock)顾名思义,就是很悲观,假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。1.2乐观锁(OptimisticLock)顾名思义,就是很乐观,假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。乐观锁不能解决脏读的问题。每次拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,

    2022年10月16日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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