1、类也是对象,类是java.lang.Class的对象
public Class Foo{}
Foo foo1 = new Foo() //foo1表示Foo的对象
表示Class类对象三种方法:
1.1 : java.lang.Class c1 = Foo.class //任何一个类都有一个隐含的静态成员class
1.2 : java.lang.Class c2 = foo1.getClass() //已知该类(Foo)对象(foo1),获取该Class
1.3 :java.lang.Class c3 = null
c3 = Class.forName("com.lxj.Foo") //括号中要写类全称
【注意1】c1、c2、c3就是表示类Foo类的类类型(Class Type),c1、c2、c3是
java.lang.Class类对象(这里c1==c2==c3 : true)
【注意2】Foo类本身就是一个对象,他是谁的对象?就是java.lang.Class类的对象
而Foo类本身也有自己对象就是foo1
【注意3】通过类(Foo)的类类型(c1、c2、c3)创建该类(Foo)对象实例,
通过c1、c2、c3创建Foo的实例:
Foo foo = (Foo)c1.newInstance() //创建出来的就是Foo类的对象
【总结】:万物皆对象,类(普通的定义的类)也是对象,类(普通的定义的类)是Class实例的
对象,这个对象我们称为该类(普通的定义的类)的类类型
2、动态加载、静态加载:
2.1:静态加载:编译时候加载(new 对象),饿汉
2.2 动态加载:执行时候加载(Class.forName),懒汉
功能性代码,动态加载方便扩展,如下(使用EXCEL、WORLD)ClassDemo.java文件:
public class ClassDemo {
public static void main(String[] args) {
Class c = null;
try {
c = Class.forName(args[0]);
IOffice office = (IOffice) c.newInstance();
office.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
interface IOffice{
public void start();
}
class World implements IOffice{
public void start(){
System.out.println("world");
}
}
class Excel implements IOffice{
public void start(){
System.out.println("excel");
}
}
一次编译: javac ClassDemo.java
多次执行: java ClassDemo World
多次执行: java ClassDemo Excel
3、 获取类信息
3.1 获取类名
Class c = Integer.class;
c.getName() //获取类全名,带包名。java.lang.Integer
c.getSimpleName() //获取不带包名的类名。Integer
3.2 获取类所有信息
public class ClassUtil {
public static void printClassMessage(Object object){
Class c = object.getClass();
//获取类的名称
System.out.print("类名称:"+c.getName());
/**
* 获取类所有方法
* Method类,方法对象
* 一个成员方法就是一个Method对象
* getMethods()方法获取的是所有public函数,包括从父类继承来的
* getDeclaredMethod()方法获取的是该类自己的方法,不论什么访问权限
*/
Method[] ms = c.getMethods(); //c.getDeclaredMethod()
for(Method m : ms){
//得到的是返回值类型的类类型
Class returnType = m.getReturnType();
//得到返回值类型的名称
System.out.print(returnType.getName() + " ");
//得到方法名称
System.out.print(m.getName()+"(");
//得到方法参数类类型
Class[] paramTypes = m.getParameterTypes();
for (Class paramType : paramTypes){
System.out.print(paramType.getName() + ",");
}
System.out.println(")");
}
/**
* 获取成员属性
* 成员变量也是对象
* java.lang.reflect.Field
* Field 类封装了关于成员变量的操作
* getFields()方法获取的是所有的public的成员变量的信息
* getDeclaredFields获取的是该类自己声明的成员变量的信息
*/
Field[] fields = c.getFields();
for(Field field : fields){
//得到成员变量的类类型
Class fieldType = field.getType();
//获取成员变量类型名称
String fieldTypeName = fieldType.getName();
//获取成员变量名称
String fieldName = field.getName();
System.out.println(fieldTypeName + " " + fieldName);
}
/**
* 打印构造函数信息
* 构造函数也是对象
* java.lang.reflect.Constructor
*/
// Constructor[] constructors = c.getConstructors(); //获取所有public构造方法包含父类的
Constructor[] constructors = c.getDeclaredConstructors(); //获取当前类的构造方法
for(Constructor constructor:constructors){
//构造函数没有返回值,所以没有返回值类型
String constructorName = constructor.getName(); //获取构造函数名称
System.out.print(constructorName + "(");
//获取构造函数参数的类类型
Class[] paramTypes = constructor.getParameterTypes();
for(Class paramType:paramTypes){
System.out.print(paramType.getName() + ",");
}
System.out.println(")");
}
}
}
调用:
Integer i = 1;
ClassUtil.printClassMessage(i)
4、方法反射基本操作
4.1:如何获取某个方法(方法的名称与方法的参数列表才能唯一决定某个方法)
4.2:方法反射的操作:method.invoke(对象,参数列表)
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) {
//获取A的 print(int a,int b)方法
//1、获取一个类的方法,首先要获取类的类类型
A a = new A();
Class c = a.getClass();
/**
* 2、获取方法 : 方法名称和参数列表来决定
* getMethod()获取的是所有public
* getDeclaredMethod() 获取的是当前类自己的方法
*/
try {
//方法一
// Method m = c.getMethod("print",new Class[]{int.class,int.class});
//方法二
Method m = c.getMethod("print", int.class, int.class);
/* 3、调用print(1,2)方法 */
Object o = m.invoke(a,new Object[]{1,2}); //3
/*调用*/
Method m1 = c.getMethod("print");
m1.invoke(a); // dddd
//如果方法没返回值o就是null,有返回值就是返回值
} catch (Exception e) {
e.printStackTrace();
}
}
}
class A{
public void print(){
System.out.println("dddd");
}
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.toUpperCase());
}
}
5、通过反射了解集合泛型的本质
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
//获取A的 print(int a,int b)方法
List list = new ArrayList();
List<String> list1 = new ArrayList<String>();
Class c1 = list.getClass();
Class c2 = list1.getClass();
System.out.println(c1 == c2); //true
//反射的操作都是编译之后的操作
//c1==c2,说明编译之后的集合是去泛型化的(不带泛型),编译之后的集合不带泛型,java中的集合是防止编译程序时候出错的,绕过编译就无效了
//验证上面这段话:通过方法的反射
try {
Method m = c2.getMethod("add",Object.class);
m.invoke(list1,100);
m.invoke(list1,200);
System.out.println(list1.size()); //2 ,本来list1是String泛型的,现在说明添加2个int类型添加进去了,反射操作不走编译直接运行,所以验证是对的
//但是不能用for遍历,如果用for遍历就类型出错了
}catch (Exception e){
e.printStackTrace();
}
}
}