class类
1、在面向对象的世界里,万事万物皆对象
我们提供的每一个类也是对象
问:类是谁的对象?
答:类是对象,类是java.lang.class类的实例对象
写一个student类,student类是class类的对象
There is a class named Class
2、这个对象怎么表示?
public class ClassDemo1 {
public static void main(String[] args) {
//Foo的实例对象如何表示
Foo foo1 = new Foo();
//Foo这个类也是一个实例对象,class类的实例对象,如何表示呢
//不能通过New
//只有Java虚拟机才能创建class类的实例对象
//任何一个类都是class的实例对象,这个实例对象有三种表示方式
//第一种表示方式-->实际在告诉我们任何一个类都有一个隐含的静态成员变量class
Class c1 = Foo.class;
//第二种表达方式,已知道该类的对象通过getClass的方法
Class c2 = foo1.getClass();
//官网 c1,c2表示了Foo类的类类型(class type)
//Foo这个类本身就是一个对象,是class对象
//但是Foo类也有一个对象
//这个对象(类)称为该类的类类型
//class type两种翻译 1:类类型 2:类的实例对象
System.out.println(c1 == c2);
//不管c1或者c2都代表了Foo类的类类型,一个类只可能是class类的一个实例对象
//第三种方式
Class c3 = null;
try {
c3 = Class.forName("com.imooc.reflect.Foo");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(c2 == c3);
//我们完全可以通过类的类类型创建该类的对象--->通过c1 or c2 or c3 创建Foo的实例
try {
//做强制类型转换
Foo foo = (Foo)c1.newInstance(); //需要有无参数的构造方法
foo.print();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Foo{
void print() {
System.out.println("foo");
}
}```
动态加载类
Class类
Class.forName(“类的全称”)
- 不仅表示了类的类类型,还代表了动态加载类
- 请大家区分编译、运行(使用cmd)
- 编译时刻加载类是静态加载类(通过new)、运行时刻加载类是动态加载类
动态加载类其实就是当程序的部分类的功能丧失的时候,任何能够加载已经完成了的类的程序,通过class.forName()方法可得
new创建对象 是静态加载类,在编译时刻就需要加载所有可能使用到的类
通过动态加载类可以解决这个问题
基本的数据类型也对应有类类型,void关键字都存在类类型
class类的基本API操作
打印类的信息,包括类的成员函数、成员变量、该对象所属类的信息
获取方法的信息的步骤:
1、获取类的类类型(.class)
2、Java的reflect包里面有一个Method类,有个getMethods的方法,一个成员方法就是一个Method对象
其中:getMethods()方法是获取所有public的函数,包括父类继承而来的
getDeclaredMethods()方法获取所有该类自己声明的方法,不问访问权限
public class ClassUtil {
/*
* 打印类的信息,包括类的成员函数、成员变量
* 该对象所属类的信息
*/
public static void printClassMessage(Object obj) {
//要获取类的信息, 首先要获取类的类类型
Class c = obj.getClass(); //传递的是哪个子类的对象,c是该子类的类类型
System.out.println("类的名称是:" + c.getClass());
/*
* Method类,方法对象
* 一个成员方法就是一个Method对象
* getMethods()方法获取的是所有Public的函数,包括父类继承而来的
* getDeclaredMethods()获取所有该类自己声明的方法,不问访问权限
*/
Method[] ms = c.getMethods(); //c.getDeclaredMethods()
c.getDeclaredMethods();
for(int i = 0; i < ms.length; i++) {
//得到方法的返回值类型的类类型
//如果返回的是String 即返回String.class
Class returnType = ms[i].getReturnType();
System.out.print(returnType.getName() + " ");
//得到方法的名称
System.out.print(ms[i].getName() + "(");
//获取参数类型 -->得到的是参数列表的类型的类类型
Class[] paramTypes = ms[i].getParameterTypes();
for(Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
}
}
其中还有关于构造函数等的反射的api与上面代码类似
方法的反射
- 如何获取某个方法
方法的名称和方法的参数列表才能唯一决定某个方法 - 方法反射的操作
method.invoke(对象,参数列表)
例子:
mport java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodDemo1 {
public static void main(String[] args) {
//要获取print(int,int)方法
// 1、要获取一个方法就是获取类的信息,获取类的信息首先获取类的类类型
A a1 = new A();
Class c = a1.getClass();
/*
* 2、获取方法 名称和参数列表来决定
* getMethod()获取的是public的方法
* getDeclaredMethod()自己声明的方法
* 其中传入的参数是方法名+数组
*/
try {
Method m = c.getDeclaredMethod("print", new Class[] {int.class,int.class});
//方法的反射操作
//a1.print(10, 20);
//方法的反射操作是使用m对象来进行方法的调用 和a1.print调用方法的效果完全相同
//方法如果没有返回值返回null,有返回值返回具体的返回值
Object o = m.invoke(a1, new Object[] {10,20});
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
class A{
public void print(int a,int b) {
System.out.println(a + b);
}
public void print(String a,String b) {
System.out.println(a.toUpperCase() + "," + b.toLowerCase());
}
}
关于类类型的进一步解释
Class类被创建后的对象就是Class对象,注意Class对象表示的是自己手动编写类的类型信息,比如创建一个shape类,那么,JVM就会创建一个shapes对应的Class类的Class的对象,该Class对象保存了Shapes类相关的类型信息。实际上Java中每个类都有一个Class对象,每当我们编写并且编译一个新创建的类就会产生一个对应的Class对象并且这个Class对象会被保存在同名.class文件里(编译后的字节码文件或者文件保存的就是Class对象)
问题是:那么为什么需要这样一个Class对象呢?
是这样的,当我们new一个新对象或者引用静态成员变量时,Java虚拟机中的类的加载器子系统会将对应Class对象加载到JVM中,然后JVM再根据这个类型信息相关的Class对象创建我们需要的实例对象或者提供静态变量的引用值。
需要特别注意的是,手动编写的每个class类,无论创建多少个实例对象,在JVM中都只有一个Class对象,即在内存中每个类有且只有一个相对应的Class对象。
所以我们可以得到的信息是:
- Class类也是类的一种,与class关键字不同
- 手动编写的类被编译后会产生一个Class对象,其表示的是创建类的类型信息,而且这个Class对象保存在同名.class的文件中(字节码文件),比如创建一个Shapes类,编译Shapes类后会创建其包含Shapes类相关类型的Class对象,并保存在Shapes.class字节码文件中
- 每个通过关键字class标识的类,在内存中有且只有一个与之对应的Class对象来描述其类型信息
- Class类只存私有构造函数,因此对应Class对象只有JVM创建和加载
- Class类的对象作用是运行时提供或获得某个对象的类型信息。
最后一点需要阐明反射的作用功能:
1、在运行时判断任意一个对象所属的类
2、在运行时构造任意一个类的对象
3、在运行时判断任意一个类所具有的成员变量和方法
4、在运行时调用任意一个对象的方法
5、生成动态代理
参考博客:
添加链接描述