之前在 慕课网 上学习了反射,以代码的形式总结一下,写入博客:
代码片段1:几种类类型的表示方式
(解释类类型:万事万物皆对象,类也是对象,是Class类的实例对象,这个对象成为该类的类类型。)
import com.imooc.reflect.Foo;
class Foo{}
public class ClassDemo1 {
public static void main(String[] args) {
//Foo类的实例对象
Foo f1 = new Foo();
//Foo类也是实例对象,是Class类的实例对象,如何表示?
//任何一个类都是Class的实例对象,这个实例对象有三种表示方式。
//第一种表示--->任何一个类都有一个隐含的静态成员变量class
Class c1 = Foo.class;
//第二种表示 已经知道该类的对象,通过getClass方法
Class c2 = f1.getClass();
/*
* c1,c2表示了Foo类的类类型(class type)
* 万事万物皆对象,类也是对象,是Class类的实例对象,这个对象成为该类的类类型。
* f1是Foo类的实例对象,c1,c2是Foo类的类类型。
*/
System.out.println(c1 == c2); //输出true
//第三种表示
try {
Class c3 = Class.forName("com.imooc.reflect.Foo");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//通过类的类类型创建实例对象
try {
Foo foo2 = (Foo) c1.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
代码片段2:得到类类型的名称
public class ClassDemo2 {
public static void main(String[] args) {
Class c1 = int.class;
System.out.println(c1.getName()); //输出int
Class c2 = double.class;
Class c3 = Void.class;
System.out.println(c2.getName()); //输出double
System.out.println(c3.getSimpleName()); //输出Void
}
}
代码片段3:
class A{
public void print(){
System.out.println("hello world!");
}
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());
}
}
public class ClassDemo4 {
public static void main(String[] args) {
A a = new A();
Class c = a.getClass();
try {
//获取print(int a, int b)方法
Method m = c.getDeclaredMethod("print", new Class[]{int.class, int.class});
//或者可以写成
Method m1 = c.getDeclaredMethod("print", int.class, int.class);
//获取print(String a, String b)方法
Method m2 = c.getDeclaredMethod("print", String.class,String.class);
//获取print()方法
Method m3 = c.getDeclaredMethod("print" );
try {
Object o = m1.invoke(a, 10,20);
//如果print方法没有返回值,o为null,否则o为print的返回值
System.out.println(o);
System.out.println("========================");
o = m2.invoke(a, "hello","world");
System.out.println("========================");
o = m3.invoke(a);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
//学习反射之前调用print(int a, int b)这样写:
//a.print(10, 20); //输出30
//学习反射之后,可以用m调用print()方法
}
}
invoke方法的参数是:
invoke
public Object invoke(Object obj, Object... args)
代码片段4:反射会使泛型失效
(注:Java中集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译就无效了)
public class ClassDemo5 {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ArrayList list1 = new ArrayList();
ArrayList<String> list2 = new ArrayList<>();
list2.add("hello");
//list2.add(20); //编译错误
Class c1 = list1.getClass();
Class c2 = list2.getClass();
System.out.println(c1 == c2); //输出true
/*
* 反射的操作都是编译之后的操作
* c1 == c2结果返回true,说明编译之后集合的泛型是去泛型化的
* Java中集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译就无效了
* 验证:通过方法的反射来操作list,绕过编译,非String类型也能加入到list2中
*/
try {
Method m = c2.getMethod("add", Object.class);
m.invoke(list2, 20); //实际上list2是只允许加入String类型的
//打印输出list2的值,发现20也被加入了list2中
System.out.println(list2);
//将会报错,因为20不能转换为string类型
for (String string : list2) {
System.out.println(string);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}