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 实例对象通过 反射 来调用 静态属性 和 对象属性都能调用得到。