您的位置:首页 > 移动开发 > Objective-C

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

2016-08-04 13:52 375 查看
 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 
http://img.my.csdn.net/uploads/201608/04/1470290740_9645.PNG" border="0" >
(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"
b554
).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 实例对象通过 反射 来调用 静态属性 和 对象属性都能调用得到。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐