Java反射机制 Object 与 Class 的关系 以及static方法与非静态方法的关系

 Class是所有类的根源     Object是所有对象的最终父类根源 

 一个Object必定能通过 Object.getClass() 获得对应的Class,一个Class并不包含Object但 它能通过 newInstance()方法来获得Object。

 并且对于同一种Class类型的对象 Object 它的Class类型是唯一的。 是一对多的关系。



一个类  class Test{ } 只存在着一个 Test.Class (只包含静态属性方法区块 【这些静态属性方法不一定每个Class都有视具体业务而定,但一旦有static块那么它一定在这个Class中】) 而存在无数个 Test Object 对象(包含对象方法属性+Test.Class包含的静态块)



一:  Class 和 Object  存在的形式

1.1 

单独存在Class 是可以的。通过 方法Class.forName() 能返回一个Class对象 并且存储有该Class的属性【如图 包含静态static属性 Str 和对象属性Str1】以及方法【包含静态方法 static method() 和对象方法 method1()】【通过该Class能访问得到static的属性以及方法,但是如果访问对象属性和方法将会报错 参数错误--只有实例才能访问这些对象的属性和方法】Class 能通过方法newInstance() 得到  Class+ Object  对应的实例对象。 相当于 new Test()


1.2

单独存在 Object 是不存在的。


1.3

 Class+ Object  就是我们在内存中创建的对象。该对象(包含对象方法属性+Test.Class包含的静态块)

New Object(实例对象1)  = Class (1)+ Object (1)

New Object(实例对象2)  = Class (1)+ Object (2)

New Object(实例对象3)  = Class (1)+ Object (3)

...... 所以 任何一个实例对象 调用静态方法 都只是对 Class部分操作,每个对象都含有该唯一的Class。


:代码分析

基本的Test类 该类含有

static属性   String str

static方法  method()

static 区块  static {}


对象属性 String str1

对象方法 method1()

package D1;

public class Test {
	static String str;
	String str1;
	static {
		System.out.println("Test类静态块");
		str = "Test类静态属性";
		System.out.println(str);
	}

	public static void method() {
		System.out.println("Test类静方法method()");
	}
	public void method1() {
		System.out.println("Test对象方法method1()");
	}

	public static void main(String[] args) {
		// XXXX
	}
}





★1.使用 Class.forName 取得 Class 

论证: 在创建Class的过程中,静态属性和方法会被创建,静态区块会被调用。

public static void main(String[] args) throws ClassNotFoundException {
	Class.forName("D1.Test");
}

打印结果:

Test类静态块
Test类静态属性


结论:

Class.forName 会根据 参数 "D1.Test"找到该Test.class 文件,然后把它转为JVM可运行的Class 

在创建Class的过程中,静态属性和方法会被创建,静态区块会被调用。


★2.使用 Class取得对应的方法【包括静态的方法 和 对象的方法】

论证: Class存储了 类的static静态方法 和 对象实例方法。

	public static void main(String[] args) throws ClassNotFoundException {
		Class test = null;
		try {
			test = Class.forName("D1.Test");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		Method[] mList = test.getMethods();
		System.out.println("Class<Test>对应的方法数量"+mList.length);
		for (int i = 0; i < mList.length; i++) {
			System.out.print(i + " " + mList[i].getReturnType().toString());
			System.out.print(" " + mList[i].getName() + " ");
			System.out.print("( ");
			Class[] pList = mList[i].getParameterTypes();// 获得参数列表
			for (int j = 0; j < pList.length; j++) {
				if (j > 0) System.out.print(",");
				System.out.print(pList[j].getName());
			}
			System.out.print(") ");
			System.out.println();
		}
	}

打印结果:

Test类静态块
Test类静态属性
Class<Test>对应的方法数量12
0 void method1 ( ) 
1 void main ( [Ljava.lang.String;) 
2 void method ( ) 
3 void wait ( long) 
4 void wait ( ) 
5 void wait ( long,int) 
6 boolean equals ( java.lang.Object) 
7 class java.lang.String toString ( ) 
8 int hashCode ( ) 
9 class java.lang.Class getClass ( ) 
10 void notify ( ) 
11 void notifyAll ( ) 

结论:

在打印结果中 

0 void method1 ( )  对应的是Test类中的对象方法 ---------public void method()

2 void method ( )  对应的是Test类中的静态方法 ---------public static void method()

由此可知,Class存储了 类的static静态方法 和 对象实例方法。


★3.使用 Class取得对应的属性【包括静态属性 和 对象属性】

论证: Class存储了 类的static静态属性 和 对象实例属性。

	public static void main(String[] args) throws ClassNotFoundException {
		Class test = null;
		try {
			test = Class.forName("D1.Test");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println("获得属性列表"); 
		Field[] fList=test.getDeclaredFields(); 
		for(int i=0;i<fList.length;i++) 
		{
		System.out.println(fList[i].getType()+" "+fList[i].getName()); 
		}
	}

打印结果:

Test类静态块
Test类静态属性
获得属性列表
class java.lang.String str
class java.lang.String str1


结论: 

在打印结果中 

class java.lang.String str1 对应的是Test类中的对象属性 ---------String str1;

class java.lang.String str  对应的是Test类中的静态属性 ---------static String str;

由此可知,Class存储了 类的static静态属性 和 对象实例属性。


★4.使用 Class取得对应的属性【包括静态属性 和 对象属性】的值

论证:  Class 只能访问静态属性,它不能调用【Class+ Object  】实例对象中属于Object 部分的属性

	public static void main(String[] args) throws ClassNotFoundException,
			IllegalArgumentException, IllegalAccessException {
		Class test = null;
		try {
			test = Class.forName("D1.Test");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println("获得属性列表");
		Field[] fList = test.getDeclaredFields();
		for (int i = 0; i < fList.length; i++) {
			System.out.println(fList[i].getType() + " " + fList[i].getName());

			if (fList[i].getName() == "str")
				System.out.println(fList[i].getName() + "的值为:    "+ fList[i].get(test));

			if (fList[i].getName() == "str1")
				System.out.println(fList[i].getName() + "的值为:    "+ fList[i].get(test));
		}
	}
打印结果:



结论: 

在打印的Log中看到 静态变量 static String str 的数值能正确打印,它的值为  【Test类静态属性】  通过 fList[i].get(test【test是Class 它包含静态部分】)获得

而对象属性 String  str1 在获得它的值的过程中报错,由此可得出 Class 只能访问静态属性,它不能调用【Class+ Object  】实例对象中属于Object 部分的属性



★5.使用 Class调用方法【包括静态方法 和 对象方法】

论证:Class 能调用属于它自己的 静态方法和属性  不能调用 属于对象 Object 的那部分信息。

	public static void main(String[] args) throws ClassNotFoundException,
	IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
		Class test = null;
		try {
			test = Class.forName("D1.Test");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		Method staticMethod = test.getMethod("method", null);
		Method objectMethod = test.getMethod("method1", null);
		staticMethod.invoke(test, null);
		System.out.println("===========================");
		objectMethod.invoke(test, null);
	}

打印结果:


结论:

在Log中能看到  静态方法 static void method()  能正常执行打印出 【Test类静方法method()】,通过反射 Method.invoke() 方法调用参数是Class

而 对象方法 void method1()   在参数是 Class的情况下调用错误,错误信息为: 参数不是一个声明类的实例对象。

说明 Class 能调用属于它自己的 静态方法和属性  不能调用 属于对象 Object 的那部分信息。



★6.使用 Class<Test>  classA 和 Class classB 的区别

论证:对于程序来说 Class<Test>  classA  泛型类 和 Class类 处理是一样的,使用Class<Test> 是为了更好的理解程序。

	public static void main(String[] args) throws ClassNotFoundException,
			IllegalArgumentException, IllegalAccessException {
		Class<Test> testA = null;
		Class        testB = null;
		try {
			testA = (Class<Test>)Class.forName("D1.Test");
			testB = Class.forName("D1.Test");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println(testA.equals(testB));
		System.out.println(testA.hashCode() == testB.hashCode());
		System.out.println("testA 的方法数量:"+testA.getMethods().length);
		System.out.println("testB 的方法数量:"+testB.getMethods().length);
		System.out.println("testA 的类名:"+testA.getName());
		System.out.println("testB 的类名:"+testB.getName());
	}

打印结果:

Test类静态块
Test类静态属性
true
true
testA 的方法数量:12
testB 的方法数量:12
testA 的类名:D1.Test
testB 的类名:D1.Test


结论:

使用泛型 Class<Test>  和 使用 Class 得到的类 他们的哈希码 他们的类名  他们的方法数量 他们的equal方法 都表明

对于程序来说 Class<Test>  classA  泛型类 和 Class类 处理是一样的,使用Class<Test> 是为了更好的理解程序。


★7.使用 Class 的 newInstance() 方法创建类的实例

论证: 难怪很多程序需要保留类的无参空构造方法,可以通过Class.getName("XXX").newInstance() 方法得到类的实例对象。

	Test(){
		System.out.println("Test实例对象 构造方法!");
	}
	
	public static void main(String[] args) throws ClassNotFoundException,
			IllegalArgumentException, IllegalAccessException, InstantiationException {
		Class test = null;
		try {
			test = Class.forName("D1.Test");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		Test testObject = (Test) test.newInstance();
	}

打印结果:

Test类静态块
Test类静态属性
Test实例对象 构造方法!


结论: 方法 newInstance() 会返回一个类的实例对象 前提是该类必须有一个空的无参构造函数。


★8.使用 Class + Object 实例对象通过 反射 来调用 静态属性方法 和 对象方法

	public static void main(String[] args) throws ClassNotFoundException,
			IllegalArgumentException, IllegalAccessException, InstantiationException, SecurityException, NoSuchMethodException, InvocationTargetException {
		Test testObject = new Test();
		Class test = testObject.getClass();

         Method staticMethod =  test.getMethod("method", null);
         Method objectMethod =  test.getMethod("method1", null);
         System.out.println("=======================1======================");
         staticMethod.invoke(testObject, null);
         objectMethod.invoke(testObject, null);
         System.out.println("=======================2======================");
         testObject.method();
         testObject.method1();
         System.out.println("=======================3======================");
         staticMethod.invoke(staticMethod, null);
         objectMethod.invoke(staticMethod, null);
	}

打印结果:

Test类静态块
Test类静态属性
Test实例对象 构造方法!
=======================1======================
Test类静方法method()
Test对象方法method1()
=======================2======================
Test类静方法method()
Test对象方法method1()
=======================3======================
Test类静方法method()
Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at D1.Test.main(Test.java:57)


结论:Class + Object 实例对象通过 反射 来调用 静态方法 和 对象方法.而 Class 类不能通过反射调用实例的和方法


★9.使用 Class + Object 实例对象通过 反射 来调用 静态属性 和 对象属性

	Test(){
		str1 ="hellow world!"; 
		System.out.println("Test实例对象 构造方法!");
	}
	
	public static void main(String[] args) throws ClassNotFoundException,
			IllegalArgumentException, IllegalAccessException, InstantiationException, SecurityException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
		Test testObject = new Test();
		Class test = testObject.getClass();
         System.out.println("=======================1======================");
		 System.out.println(test.getDeclaredField("str").get(testObject));
		 System.out.println(test.getDeclaredField("str").get(test));
         System.out.println("=======================2======================");
		 System.out.println(test.getDeclaredField("str1").get(testObject));
		 System.out.println(test.getDeclaredField("str1").get(test));
         System.out.println("=======================3======================");

	}

打印结果:

Test类静态块
Test类静态属性
Test实例对象 构造方法!
=======================1======================
Test类静态属性
Test类静态属性
=======================2======================
hellow world!
Exception in thread "main" java.lang.IllegalArgumentException: Can not set java.lang.String field D1.Test.str1 to java.lang.Class
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(Unknown Source)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(Unknown Source)
at java.lang.reflect.Field.get(Unknown Source)
at D1.Test.main(Test.java:52)

结论:

使用 Class + Object 实例对象通过 反射 来调用 静态属性 和 对象属性都能调用得到。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值